diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index fd0d9e38b6c6..7613a28f157e 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -1052,6 +1052,7 @@ static struct aa_fs_entry aa_fs_entry_domain[] = { AA_FS_FILE_BOOLEAN("change_onexec", 1), AA_FS_FILE_BOOLEAN("change_profile", 1), AA_FS_FILE_BOOLEAN("fix_binfmt_elf_mmap", 1), + AA_FS_FILE_STRING("version", "1.2"), { } }; diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index d18b3f0e5534..ef4beef06e9d 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -729,8 +729,7 @@ out: /** * aa_change_profile - perform a one-way profile transition - * @ns_name: name of the profile namespace to change to (MAYBE NULL) - * @hname: name of profile to change to (MAYBE NULL) + * @fqname: name of profile may include namespace (NOT NULL) * @onexec: whether this transition is to take place immediately or at exec * @permtest: true if this is just a permission test * @@ -742,19 +741,20 @@ out: * * Returns %0 on success, error otherwise. */ -int aa_change_profile(const char *ns_name, const char *hname, bool onexec, - bool permtest) +int aa_change_profile(const char *fqname, bool onexec, + bool permtest, bool stack) { const struct cred *cred; struct aa_profile *profile, *target = NULL; - struct aa_ns *ns = NULL; struct file_perms perms = {}; - const char *name = NULL, *info = NULL, *op; + const char *info = NULL, *op; int error = 0; u32 request; - if (!hname && !ns_name) + if (!fqname || !*fqname) { + AA_DEBUG("no profile name"); return -EINVAL; + } if (onexec) { request = AA_MAY_ONEXEC; @@ -779,44 +779,15 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec, return -EPERM; } - if (ns_name) { - /* released below */ - ns = aa_find_ns(profile->ns, ns_name); - if (!ns) { - /* we don't create new namespace in complain mode */ - name = ns_name; - info = "namespace not found"; - error = -ENOENT; - goto audit; - } - } else - /* released below */ - ns = aa_get_ns(profile->ns); - - /* if the name was not specified, use the name of the current profile */ - if (!hname) { - if (unconfined(profile)) - hname = ns->unconfined->base.hname; - else - hname = profile->base.hname; - } - - perms = change_profile_perms(profile, ns, hname, request, - profile->file.start); - if (!(perms.allow & request)) { - error = -EACCES; - goto audit; - } - - /* released below */ - target = aa_lookup_profile(ns, hname); + target = aa_fqlookupn_profile(profile, fqname, strlen(fqname)); if (!target) { info = "profile not found"; error = -ENOENT; if (permtest || !COMPLAIN_MODE(profile)) goto audit; /* released below */ - target = aa_new_null_profile(profile, false, hname, GFP_KERNEL); + target = aa_new_null_profile(profile, false, fqname, + GFP_KERNEL); if (!target) { info = "failed null profile create"; error = -ENOMEM; @@ -824,6 +795,13 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec, } } + perms = change_profile_perms(profile, target->ns, target->base.hname, + request, profile->file.start); + if (!(perms.allow & request)) { + error = -EACCES; + goto audit; + } + /* check if tracing task is allowed to trace target domain */ error = may_change_ptraced_domain(target); if (error) { @@ -841,10 +819,9 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec, audit: if (!permtest) - error = aa_audit_file(profile, &perms, op, request, name, - hname, GLOBAL_ROOT_UID, info, error); + error = aa_audit_file(profile, &perms, op, request, NULL, + fqname, GLOBAL_ROOT_UID, info, error); - aa_put_ns(ns); aa_put_profile(target); put_cred(cred); diff --git a/security/apparmor/include/domain.h b/security/apparmor/include/domain.h index de04464f0a3f..30544729878a 100644 --- a/security/apparmor/include/domain.h +++ b/security/apparmor/include/domain.h @@ -30,7 +30,7 @@ void apparmor_bprm_committed_creds(struct linux_binprm *bprm); void aa_free_domain_entries(struct aa_domain *domain); int aa_change_hat(const char *hats[], int count, u64 token, bool permtest); -int aa_change_profile(const char *ns_name, const char *name, bool onexec, - bool permtest); +int aa_change_profile(const char *fqname, bool onexec, bool permtest, + bool stack); #endif /* __AA_DOMAIN_H */ diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index c4bae8ae538f..264aa192032e 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -543,17 +543,17 @@ static int apparmor_setprocattr(struct task_struct *task, char *name, error = aa_setprocattr_changehat(args, arg_size, AA_DO_TEST); } else if (strcmp(command, "changeprofile") == 0) { - error = aa_setprocattr_changeprofile(args, !AA_ONEXEC, - !AA_DO_TEST); + error = aa_change_profile(args, !AA_ONEXEC, + !AA_DO_TEST, false); } else if (strcmp(command, "permprofile") == 0) { - error = aa_setprocattr_changeprofile(args, !AA_ONEXEC, - AA_DO_TEST); + error = aa_change_profile(args, !AA_ONEXEC, AA_DO_TEST, + false); } else goto fail; } else if (strcmp(name, "exec") == 0) { if (strcmp(command, "exec") == 0) - error = aa_setprocattr_changeprofile(args, AA_ONEXEC, - !AA_DO_TEST); + error = aa_change_profile(args, AA_ONEXEC, !AA_DO_TEST, + false); else goto fail; } else diff --git a/security/apparmor/procattr.c b/security/apparmor/procattr.c index a9a9ee6659ae..3466a27bca09 100644 --- a/security/apparmor/procattr.c +++ b/security/apparmor/procattr.c @@ -149,19 +149,3 @@ int aa_setprocattr_changehat(char *args, size_t size, int test) return aa_change_hat(hats, count, token, test); } - -/** - * aa_setprocattr_changeprofile - handle procattr interface to changeprofile - * @fqname: args received from writting to /proc//attr/current (NOT NULL) - * @onexec: true if change_profile should be delayed until exec - * @test: true if this is a test of change_profile permissions - * - * Returns: %0 or error code if change_profile fails - */ -int aa_setprocattr_changeprofile(char *fqname, bool onexec, int test) -{ - char *name, *ns_name; - - name = aa_split_fqname(fqname, &ns_name); - return aa_change_profile(ns_name, name, onexec, test); -}