apparmor: convert change_profile to use fqname later to give better control
Moving the use of fqname to later allows learning profiles to be based on the fqname request instead of just the hname. It also allows cleaning up some of the name parsing and lookup by allowing the use of the fqlookupn_profile() lib fn. Signed-off-by: John Johansen <john.johansen@canonical.com>
This commit is contained in:
parent
c3e1e584ad
commit
aa9a39ad8f
|
@ -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_onexec", 1),
|
||||||
AA_FS_FILE_BOOLEAN("change_profile", 1),
|
AA_FS_FILE_BOOLEAN("change_profile", 1),
|
||||||
AA_FS_FILE_BOOLEAN("fix_binfmt_elf_mmap", 1),
|
AA_FS_FILE_BOOLEAN("fix_binfmt_elf_mmap", 1),
|
||||||
|
AA_FS_FILE_STRING("version", "1.2"),
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -729,8 +729,7 @@ out:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* aa_change_profile - perform a one-way profile transition
|
* aa_change_profile - perform a one-way profile transition
|
||||||
* @ns_name: name of the profile namespace to change to (MAYBE NULL)
|
* @fqname: name of profile may include namespace (NOT NULL)
|
||||||
* @hname: name of profile to change to (MAYBE NULL)
|
|
||||||
* @onexec: whether this transition is to take place immediately or at exec
|
* @onexec: whether this transition is to take place immediately or at exec
|
||||||
* @permtest: true if this is just a permission test
|
* @permtest: true if this is just a permission test
|
||||||
*
|
*
|
||||||
|
@ -742,19 +741,20 @@ out:
|
||||||
*
|
*
|
||||||
* Returns %0 on success, error otherwise.
|
* Returns %0 on success, error otherwise.
|
||||||
*/
|
*/
|
||||||
int aa_change_profile(const char *ns_name, const char *hname, bool onexec,
|
int aa_change_profile(const char *fqname, bool onexec,
|
||||||
bool permtest)
|
bool permtest, bool stack)
|
||||||
{
|
{
|
||||||
const struct cred *cred;
|
const struct cred *cred;
|
||||||
struct aa_profile *profile, *target = NULL;
|
struct aa_profile *profile, *target = NULL;
|
||||||
struct aa_ns *ns = NULL;
|
|
||||||
struct file_perms perms = {};
|
struct file_perms perms = {};
|
||||||
const char *name = NULL, *info = NULL, *op;
|
const char *info = NULL, *op;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
u32 request;
|
u32 request;
|
||||||
|
|
||||||
if (!hname && !ns_name)
|
if (!fqname || !*fqname) {
|
||||||
|
AA_DEBUG("no profile name");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
if (onexec) {
|
if (onexec) {
|
||||||
request = AA_MAY_ONEXEC;
|
request = AA_MAY_ONEXEC;
|
||||||
|
@ -779,44 +779,15 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec,
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ns_name) {
|
target = aa_fqlookupn_profile(profile, fqname, strlen(fqname));
|
||||||
/* 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);
|
|
||||||
if (!target) {
|
if (!target) {
|
||||||
info = "profile not found";
|
info = "profile not found";
|
||||||
error = -ENOENT;
|
error = -ENOENT;
|
||||||
if (permtest || !COMPLAIN_MODE(profile))
|
if (permtest || !COMPLAIN_MODE(profile))
|
||||||
goto audit;
|
goto audit;
|
||||||
/* released below */
|
/* released below */
|
||||||
target = aa_new_null_profile(profile, false, hname, GFP_KERNEL);
|
target = aa_new_null_profile(profile, false, fqname,
|
||||||
|
GFP_KERNEL);
|
||||||
if (!target) {
|
if (!target) {
|
||||||
info = "failed null profile create";
|
info = "failed null profile create";
|
||||||
error = -ENOMEM;
|
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 */
|
/* check if tracing task is allowed to trace target domain */
|
||||||
error = may_change_ptraced_domain(target);
|
error = may_change_ptraced_domain(target);
|
||||||
if (error) {
|
if (error) {
|
||||||
|
@ -841,10 +819,9 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec,
|
||||||
|
|
||||||
audit:
|
audit:
|
||||||
if (!permtest)
|
if (!permtest)
|
||||||
error = aa_audit_file(profile, &perms, op, request, name,
|
error = aa_audit_file(profile, &perms, op, request, NULL,
|
||||||
hname, GLOBAL_ROOT_UID, info, error);
|
fqname, GLOBAL_ROOT_UID, info, error);
|
||||||
|
|
||||||
aa_put_ns(ns);
|
|
||||||
aa_put_profile(target);
|
aa_put_profile(target);
|
||||||
put_cred(cred);
|
put_cred(cred);
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ void apparmor_bprm_committed_creds(struct linux_binprm *bprm);
|
||||||
|
|
||||||
void aa_free_domain_entries(struct aa_domain *domain);
|
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_hat(const char *hats[], int count, u64 token, bool permtest);
|
||||||
int aa_change_profile(const char *ns_name, const char *name, bool onexec,
|
int aa_change_profile(const char *fqname, bool onexec, bool permtest,
|
||||||
bool permtest);
|
bool stack);
|
||||||
|
|
||||||
#endif /* __AA_DOMAIN_H */
|
#endif /* __AA_DOMAIN_H */
|
||||||
|
|
|
@ -543,17 +543,17 @@ static int apparmor_setprocattr(struct task_struct *task, char *name,
|
||||||
error = aa_setprocattr_changehat(args, arg_size,
|
error = aa_setprocattr_changehat(args, arg_size,
|
||||||
AA_DO_TEST);
|
AA_DO_TEST);
|
||||||
} else if (strcmp(command, "changeprofile") == 0) {
|
} else if (strcmp(command, "changeprofile") == 0) {
|
||||||
error = aa_setprocattr_changeprofile(args, !AA_ONEXEC,
|
error = aa_change_profile(args, !AA_ONEXEC,
|
||||||
!AA_DO_TEST);
|
!AA_DO_TEST, false);
|
||||||
} else if (strcmp(command, "permprofile") == 0) {
|
} else if (strcmp(command, "permprofile") == 0) {
|
||||||
error = aa_setprocattr_changeprofile(args, !AA_ONEXEC,
|
error = aa_change_profile(args, !AA_ONEXEC, AA_DO_TEST,
|
||||||
AA_DO_TEST);
|
false);
|
||||||
} else
|
} else
|
||||||
goto fail;
|
goto fail;
|
||||||
} else if (strcmp(name, "exec") == 0) {
|
} else if (strcmp(name, "exec") == 0) {
|
||||||
if (strcmp(command, "exec") == 0)
|
if (strcmp(command, "exec") == 0)
|
||||||
error = aa_setprocattr_changeprofile(args, AA_ONEXEC,
|
error = aa_change_profile(args, AA_ONEXEC, !AA_DO_TEST,
|
||||||
!AA_DO_TEST);
|
false);
|
||||||
else
|
else
|
||||||
goto fail;
|
goto fail;
|
||||||
} else
|
} else
|
||||||
|
|
|
@ -149,19 +149,3 @@ int aa_setprocattr_changehat(char *args, size_t size, int test)
|
||||||
|
|
||||||
return aa_change_hat(hats, count, token, test);
|
return aa_change_hat(hats, count, token, test);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* aa_setprocattr_changeprofile - handle procattr interface to changeprofile
|
|
||||||
* @fqname: args received from writting to /proc/<pid>/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);
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue