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>
This commit is contained in:
John Johansen 2023-08-09 00:26:36 -07:00
parent e105d8079f
commit 2d9da9b188
5 changed files with 39 additions and 0 deletions

View file

@ -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),
{ }
};

View file

@ -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 */

View file

@ -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

View file

@ -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,
},
{ }
};

View file

@ -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",