diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 872b96fd574e..bd74ab4dd61d 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -2583,6 +2583,7 @@ static struct aa_sfs_entry aa_sfs_entry_domain[] = { static struct aa_sfs_entry aa_sfs_entry_unconfined[] = { AA_SFS_FILE_BOOLEAN("change_profile", 1), + AA_SFS_FILE_INTPTR("userns", aa_unprivileged_userns_restricted), { } }; @@ -2605,7 +2606,7 @@ static struct aa_sfs_entry aa_sfs_entry_policy[] = { AA_SFS_FILE_BOOLEAN("set_load", 1), /* number of out of band transitions supported */ AA_SFS_FILE_U64("outofband", MAX_OOB_SUPPORTED), - AA_SFS_FILE_U64("permstable32_version", 1), + AA_SFS_FILE_U64("permstable32_version", 2), AA_SFS_FILE_STRING("permstable32", PERMS32STR), AA_SFS_DIR("unconfined_restrictions", aa_sfs_entry_unconfined), { } diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 389a26808baa..33e126f12269 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -1219,16 +1219,18 @@ static int apparmor_userns_create(const struct cred *cred) struct aa_label *label; struct aa_profile *profile; int error = 0; - DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_TASK, AA_CLASS_NS, - OP_USERNS_CREATE); - - ad.subj_cred = current_cred(); label = begin_current_label_crit_section(); - if (aa_unprivileged_userns_restricted || !unconfined(label)) { + /* remove unprivileged_userns_restricted check when unconfined is updated */ + if (aa_unprivileged_userns_restricted || + LABEL_MEDIATES(label, AA_CLASS_NS)) { + DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_TASK, AA_CLASS_NS, + OP_USERNS_CREATE); + ad.subj_cred = current_cred(); + error = fn_for_each(label, profile, - aa_profile_ns_perm(profile, &ad, - AA_USERNS_CREATE)); + aa_profile_ns_perm(profile, &ad, AA_USERNS_CREATE)); + end_current_label_crit_section(label); } end_current_label_crit_section(label); diff --git a/security/apparmor/task.c b/security/apparmor/task.c index 2a667ce9aba7..48c9b87a5866 100644 --- a/security/apparmor/task.c +++ b/security/apparmor/task.c @@ -317,32 +317,40 @@ int aa_profile_ns_perm(struct aa_profile *profile, struct apparmor_audit_data *ad, u32 request) { + struct aa_ruleset *rules = list_first_entry(&profile->rules, + typeof(*rules), list); struct aa_perms perms = { }; + aa_state_t state; ad->subj_label = &profile->label; ad->request = request; - if (profile_unconfined(profile)) { - if (!aa_unprivileged_userns_restricted || - ns_capable_noaudit(current_user_ns(), CAP_SYS_ADMIN)) - return 0; - ad->info = "User namespace creation restricted"; - /* don't just return: allow complain mode to override */ - } else { - struct aa_ruleset *rules = list_first_entry(&profile->rules, - typeof(*rules), - list); - aa_state_t state; - - state = RULE_MEDIATES(rules, ad->class); - if (!state && !aa_unprivileged_userns_restricted_force) - /* TODO: add flag to complain about unmediated */ + /* TODO: rework unconfined profile/dfa to mediate user ns, then + * we can drop the unconfined test + */ + state = RULE_MEDIATES(rules, ad->class); + if (!state) { + /* TODO: this gets replaced when the default unconfined + * profile dfa gets updated to handle this + */ + if (profile_unconfined(profile) && + profile == profiles_ns(profile)->unconfined) { + if (!aa_unprivileged_userns_restricted || + ns_capable_noaudit(current_user_ns(), + CAP_SYS_ADMIN)) + return 0; + ad->info = "User namespace creation restricted"; + /* unconfined unprivileged user */ + /* don't just return: allow complain mode to override */ + } else if (!aa_unprivileged_userns_restricted_force) { return 0; - perms = *aa_lookup_perms(rules->policy, state); - if (aa_unprivileged_userns_restricted_complain) - perms.complain = ALL_PERMS_MASK; + } + /* continue to mediation */ } + perms = *aa_lookup_perms(rules->policy, state); + if (aa_unprivileged_userns_restricted_complain) + perms.complain = ALL_PERMS_MASK; aa_apply_modes_to_perms(profile, &perms); return aa_check_perms(profile, &perms, request, ad, audit_ns_cb);