diff options
-rw-r--r-- | security/apparmor/apparmorfs.c | 6 | ||||
-rw-r--r-- | security/apparmor/domain.c | 24 | ||||
-rw-r--r-- | security/apparmor/include/policy.h | 1 | ||||
-rw-r--r-- | security/apparmor/lsm.c | 7 | ||||
-rw-r--r-- | security/apparmor/policy.c | 1 |
5 files changed, 39 insertions, 0 deletions
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index b123abbc43d8..6d0848f10ff0 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -2341,6 +2341,11 @@ 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), + { } +}; + static struct aa_sfs_entry aa_sfs_entry_versions[] = { AA_SFS_FILE_BOOLEAN("v5", 1), AA_SFS_FILE_BOOLEAN("v6", 1), @@ -2358,6 +2363,7 @@ static struct aa_sfs_entry aa_sfs_entry_policy[] = { AA_SFS_FILE_U64("outofband", MAX_OOB_SUPPORTED), AA_SFS_FILE_U64("permstable32_version", 1), AA_SFS_FILE_STRING("permstable32", PERMS32STR), + AA_SFS_DIR("unconfined_restrictions", aa_sfs_entry_unconfined), { } }; diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index 87dfa0e40398..ed4a13d44894 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -1311,6 +1311,8 @@ static int change_profile_perms_wrapper(const char *op, const char *name, return error; } +const char *stack_msg = "change_profile unprivileged unconfined converted to stacking"; + /** * aa_change_profile - perform a one-way profile transition * @fqname: name of profile may include namespace (NOT NULL) @@ -1370,6 +1372,28 @@ int aa_change_profile(const char *fqname, int flags) op = OP_CHANGE_PROFILE; } + /* This should move to a per profile test. Requires pushing build + * into callback + */ + if (!stack && unconfined(label) && + label == &labels_ns(label)->unconfined->label && + aa_unprivileged_unconfined_restricted && + /* TODO: refactor so this check is a fn */ + cap_capable(current_cred(), &init_user_ns, CAP_MAC_OVERRIDE, + CAP_OPT_NOAUDIT)) { + /* regardless of the request in this case apparmor + * stacks against unconfined so admin set policy can't be + * by-passed + */ + stack = true; + perms.audit = request; + (void) fn_for_each_in_ns(label, profile, + aa_audit_file(subj_cred, profile, &perms, op, + request, auditname, NULL, target, + GLOBAL_ROOT_UID, stack_msg, 0)); + perms.audit = 0; + } + if (*fqname == '&') { stack = true; /* don't have label_parse() do stacking */ diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index e69c91619a7c..75088cc310b6 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -34,6 +34,7 @@ struct aa_ns; extern int unprivileged_userns_apparmor_policy; +extern int aa_unprivileged_unconfined_restricted; extern const char *const aa_profile_mode_names[]; #define APPARMOR_MODE_NAMES_MAX_INDEX 4 diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index bcfe8b9cb4c1..518576ae3cfb 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -1798,6 +1798,13 @@ static struct ctl_table apparmor_sysctl_table[] = { .mode = 0600, .proc_handler = apparmor_dointvec, }, + { + .procname = "apparmor_restrict_unprivileged_unconfined", + .data = &aa_unprivileged_unconfined_restricted, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = apparmor_dointvec, + }, { } }; diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 0b36bd6a6f33..a441d96adcbf 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -88,6 +88,7 @@ #include "include/resource.h" int unprivileged_userns_apparmor_policy = 1; +int aa_unprivileged_unconfined_restricted; const char *const aa_profile_mode_names[] = { "enforce", |