summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Johansen <john.johansen@canonical.com>2023-08-09 00:26:36 -0700
committerJohn Johansen <john.johansen@canonical.com>2023-10-18 15:48:44 -0700
commit2d9da9b188b8cd3b579d7ef5ba5d334be9dd38fc (patch)
tree3ddeaaf865425ba25becb5d22aa6173a59894298
parente105d8079f82819f4773c4853dc199e195fedf40 (diff)
downloadlinux-2d9da9b188b8cd3b579d7ef5ba5d334be9dd38fc.tar.gz
linux-2d9da9b188b8cd3b579d7ef5ba5d334be9dd38fc.tar.bz2
linux-2d9da9b188b8cd3b579d7ef5ba5d334be9dd38fc.zip
apparmor: allow restricting unprivileged change_profile
unprivileged unconfined can use change_profile to alter the confinement set by the mac admin. Allow restricting unprivileged unconfined by still allowing change_profile but stacking the change against unconfined. This allows unconfined to still apply system policy but allows the task to enter the new confinement. If unprivileged unconfined is required a sysctl is provided to switch to the previous behavior. Reviewed-by: Georgia Garcia <georgia.garcia@canonical.com> Signed-off-by: John Johansen <john.johansen@canonical.com>
-rw-r--r--security/apparmor/apparmorfs.c6
-rw-r--r--security/apparmor/domain.c24
-rw-r--r--security/apparmor/include/policy.h1
-rw-r--r--security/apparmor/lsm.c7
-rw-r--r--security/apparmor/policy.c1
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",