mirror of
https://gitee.com/bianbu-linux/linux-6.6
synced 2025-04-26 14:17:26 -04:00
+ Bug fixes
- performance regression: only get a label reference if the fast path check fails - fix aa_xattrs_match() may sleep while holding a RCU lock - fix bind mounts aborting with -ENOMEM -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE7cSDD705q2rFEEf7BS82cBjVw9gFAl4RPEUACgkQBS82cBjV w9gUwg/9EsFcegRD6T2NmiqUp7jY2KRjAf5JrKqZJvCbXFj9Mnurv9ug5A6b20JU SbyXU1CNIxqPTmwPMRF1YGtq/vuAV5UIgb14pjepmsvzF5A/xpgKJucR0gokc5PU 6eFbPCQ4aXF83/d+/SiJfANP+oUY372b6cTzHKMouKWXBbeIG4F9vtVrPMEZlcjo NNxDtmHNeFdASV17uA+8OKseGluPzPlWvnpq5va/Uz4avmxdeaBQxqh2N891IUqO drRTpF6cgp/072cEoSrS+2dmliHOteS9785Vh4iLF4LVt8lsRjoT0Z66eGL175Ve TYwp7EfgIwhcUYLZgKjz7t+wp3l7Yw5retlzbzbfFTIxTfGCKunUpZIUwssI+QzW npMOU+0jTLZ9hVZICOicxzs40kHu8tR4dKYPHuYB2G3gNW8LGMEodVn2SBL1H6+2 r4vUjaLIsyUHBpfQDjWHjMEN/gdSekyBvRhpnC5qNMdOTnTeHSNow88igBxmGNhA K9iymhYV0E1ZMw4KfGtyKZ2Zfd3E8F0ryH0cnavXYBYfvuVNs18M0TkaYwPb1+YH 02SyEGRnnhxtIO+GwLve6pmdRT9edZgL6Pc3yCaJ/e/g9FIpFgPbX44IxuO+XrL/ ku6NK9hXrpvk9Z/CAVUHYcRMSgQTz1lTsw9b9ooxgHQmsXuOUhM= =uw+S -----END PGP SIGNATURE----- Merge tag 'apparmor-pr-2020-01-04' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor Pull apparmor fixes from John Johansen: - performance regression: only get a label reference if the fast path check fails - fix aa_xattrs_match() may sleep while holding a RCU lock - fix bind mounts aborting with -ENOMEM * tag 'apparmor-pr-2020-01-04' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor: apparmor: fix aa_xattrs_match() may sleep while holding a RCU lock apparmor: only get a label reference if the fast path check fails apparmor: fix bind mounts aborting with -ENOMEM
This commit is contained in:
commit
a125bcda2d
5 changed files with 54 additions and 46 deletions
|
@ -623,7 +623,7 @@ static __poll_t ns_revision_poll(struct file *file, poll_table *pt)
|
||||||
|
|
||||||
void __aa_bump_ns_revision(struct aa_ns *ns)
|
void __aa_bump_ns_revision(struct aa_ns *ns)
|
||||||
{
|
{
|
||||||
ns->revision++;
|
WRITE_ONCE(ns->revision, ns->revision + 1);
|
||||||
wake_up_interruptible(&ns->wait);
|
wake_up_interruptible(&ns->wait);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -317,6 +317,7 @@ static int aa_xattrs_match(const struct linux_binprm *bprm,
|
||||||
|
|
||||||
if (!bprm || !profile->xattr_count)
|
if (!bprm || !profile->xattr_count)
|
||||||
return 0;
|
return 0;
|
||||||
|
might_sleep();
|
||||||
|
|
||||||
/* transition from exec match to xattr set */
|
/* transition from exec match to xattr set */
|
||||||
state = aa_dfa_null_transition(profile->xmatch, state);
|
state = aa_dfa_null_transition(profile->xmatch, state);
|
||||||
|
@ -361,10 +362,11 @@ out:
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* __attach_match_ - find an attachment match
|
* find_attach - do attachment search for unconfined processes
|
||||||
* @bprm - binprm structure of transitioning task
|
* @bprm - binprm structure of transitioning task
|
||||||
* @name - to match against (NOT NULL)
|
* @ns: the current namespace (NOT NULL)
|
||||||
* @head - profile list to walk (NOT NULL)
|
* @head - profile list to walk (NOT NULL)
|
||||||
|
* @name - to match against (NOT NULL)
|
||||||
* @info - info message if there was an error (NOT NULL)
|
* @info - info message if there was an error (NOT NULL)
|
||||||
*
|
*
|
||||||
* Do a linear search on the profiles in the list. There is a matching
|
* Do a linear search on the profiles in the list. There is a matching
|
||||||
|
@ -374,12 +376,11 @@ out:
|
||||||
*
|
*
|
||||||
* Requires: @head not be shared or have appropriate locks held
|
* Requires: @head not be shared or have appropriate locks held
|
||||||
*
|
*
|
||||||
* Returns: profile or NULL if no match found
|
* Returns: label or NULL if no match found
|
||||||
*/
|
*/
|
||||||
static struct aa_profile *__attach_match(const struct linux_binprm *bprm,
|
static struct aa_label *find_attach(const struct linux_binprm *bprm,
|
||||||
const char *name,
|
struct aa_ns *ns, struct list_head *head,
|
||||||
struct list_head *head,
|
const char *name, const char **info)
|
||||||
const char **info)
|
|
||||||
{
|
{
|
||||||
int candidate_len = 0, candidate_xattrs = 0;
|
int candidate_len = 0, candidate_xattrs = 0;
|
||||||
bool conflict = false;
|
bool conflict = false;
|
||||||
|
@ -388,6 +389,8 @@ static struct aa_profile *__attach_match(const struct linux_binprm *bprm,
|
||||||
AA_BUG(!name);
|
AA_BUG(!name);
|
||||||
AA_BUG(!head);
|
AA_BUG(!head);
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
restart:
|
||||||
list_for_each_entry_rcu(profile, head, base.list) {
|
list_for_each_entry_rcu(profile, head, base.list) {
|
||||||
if (profile->label.flags & FLAG_NULL &&
|
if (profile->label.flags & FLAG_NULL &&
|
||||||
&profile->label == ns_unconfined(profile->ns))
|
&profile->label == ns_unconfined(profile->ns))
|
||||||
|
@ -413,16 +416,32 @@ static struct aa_profile *__attach_match(const struct linux_binprm *bprm,
|
||||||
perm = dfa_user_allow(profile->xmatch, state);
|
perm = dfa_user_allow(profile->xmatch, state);
|
||||||
/* any accepting state means a valid match. */
|
/* any accepting state means a valid match. */
|
||||||
if (perm & MAY_EXEC) {
|
if (perm & MAY_EXEC) {
|
||||||
int ret;
|
int ret = 0;
|
||||||
|
|
||||||
if (count < candidate_len)
|
if (count < candidate_len)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ret = aa_xattrs_match(bprm, profile, state);
|
if (bprm && profile->xattr_count) {
|
||||||
/* Fail matching if the xattrs don't match */
|
long rev = READ_ONCE(ns->revision);
|
||||||
|
|
||||||
|
if (!aa_get_profile_not0(profile))
|
||||||
|
goto restart;
|
||||||
|
rcu_read_unlock();
|
||||||
|
ret = aa_xattrs_match(bprm, profile,
|
||||||
|
state);
|
||||||
|
rcu_read_lock();
|
||||||
|
aa_put_profile(profile);
|
||||||
|
if (rev !=
|
||||||
|
READ_ONCE(ns->revision))
|
||||||
|
/* policy changed */
|
||||||
|
goto restart;
|
||||||
|
/*
|
||||||
|
* Fail matching if the xattrs don't
|
||||||
|
* match
|
||||||
|
*/
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* TODO: allow for more flexible best match
|
* TODO: allow for more flexible best match
|
||||||
*
|
*
|
||||||
|
@ -445,43 +464,28 @@ static struct aa_profile *__attach_match(const struct linux_binprm *bprm,
|
||||||
candidate_xattrs = ret;
|
candidate_xattrs = ret;
|
||||||
conflict = false;
|
conflict = false;
|
||||||
}
|
}
|
||||||
} else if (!strcmp(profile->base.name, name))
|
} else if (!strcmp(profile->base.name, name)) {
|
||||||
/*
|
/*
|
||||||
* old exact non-re match, without conditionals such
|
* old exact non-re match, without conditionals such
|
||||||
* as xattrs. no more searching required
|
* as xattrs. no more searching required
|
||||||
*/
|
*/
|
||||||
return profile;
|
candidate = profile;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conflict) {
|
if (!candidate || conflict) {
|
||||||
|
if (conflict)
|
||||||
*info = "conflicting profile attachments";
|
*info = "conflicting profile attachments";
|
||||||
|
rcu_read_unlock();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return candidate;
|
out:
|
||||||
}
|
candidate = aa_get_newest_profile(candidate);
|
||||||
|
|
||||||
/**
|
|
||||||
* find_attach - do attachment search for unconfined processes
|
|
||||||
* @bprm - binprm structure of transitioning task
|
|
||||||
* @ns: the current namespace (NOT NULL)
|
|
||||||
* @list: list to search (NOT NULL)
|
|
||||||
* @name: the executable name to match against (NOT NULL)
|
|
||||||
* @info: info message if there was an error
|
|
||||||
*
|
|
||||||
* Returns: label or NULL if no match found
|
|
||||||
*/
|
|
||||||
static struct aa_label *find_attach(const struct linux_binprm *bprm,
|
|
||||||
struct aa_ns *ns, struct list_head *list,
|
|
||||||
const char *name, const char **info)
|
|
||||||
{
|
|
||||||
struct aa_profile *profile;
|
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
profile = aa_get_profile(__attach_match(bprm, name, list, info));
|
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
|
||||||
return profile ? &profile->label : NULL;
|
return &candidate->label;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *next_name(int xtype, const char *name)
|
static const char *next_name(int xtype, const char *name)
|
||||||
|
|
|
@ -618,8 +618,7 @@ int aa_file_perm(const char *op, struct aa_label *label, struct file *file,
|
||||||
fctx = file_ctx(file);
|
fctx = file_ctx(file);
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
flabel = aa_get_newest_label(rcu_dereference(fctx->label));
|
flabel = rcu_dereference(fctx->label);
|
||||||
rcu_read_unlock();
|
|
||||||
AA_BUG(!flabel);
|
AA_BUG(!flabel);
|
||||||
|
|
||||||
/* revalidate access, if task is unconfined, or the cached cred
|
/* revalidate access, if task is unconfined, or the cached cred
|
||||||
|
@ -631,9 +630,13 @@ int aa_file_perm(const char *op, struct aa_label *label, struct file *file,
|
||||||
*/
|
*/
|
||||||
denied = request & ~fctx->allow;
|
denied = request & ~fctx->allow;
|
||||||
if (unconfined(label) || unconfined(flabel) ||
|
if (unconfined(label) || unconfined(flabel) ||
|
||||||
(!denied && aa_label_is_subset(flabel, label)))
|
(!denied && aa_label_is_subset(flabel, label))) {
|
||||||
|
rcu_read_unlock();
|
||||||
goto done;
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
flabel = aa_get_newest_label(flabel);
|
||||||
|
rcu_read_unlock();
|
||||||
/* TODO: label cross check */
|
/* TODO: label cross check */
|
||||||
|
|
||||||
if (file->f_path.mnt && path_mediated_fs(file->f_path.dentry))
|
if (file->f_path.mnt && path_mediated_fs(file->f_path.dentry))
|
||||||
|
@ -643,8 +646,9 @@ int aa_file_perm(const char *op, struct aa_label *label, struct file *file,
|
||||||
else if (S_ISSOCK(file_inode(file)->i_mode))
|
else if (S_ISSOCK(file_inode(file)->i_mode))
|
||||||
error = __file_sock_perm(op, label, flabel, file, request,
|
error = __file_sock_perm(op, label, flabel, file, request,
|
||||||
denied);
|
denied);
|
||||||
done:
|
|
||||||
aa_put_label(flabel);
|
aa_put_label(flabel);
|
||||||
|
|
||||||
|
done:
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -442,7 +442,7 @@ int aa_bind_mount(struct aa_label *label, const struct path *path,
|
||||||
buffer = aa_get_buffer(false);
|
buffer = aa_get_buffer(false);
|
||||||
old_buffer = aa_get_buffer(false);
|
old_buffer = aa_get_buffer(false);
|
||||||
error = -ENOMEM;
|
error = -ENOMEM;
|
||||||
if (!buffer || old_buffer)
|
if (!buffer || !old_buffer)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
error = fn_for_each_confined(label, profile,
|
error = fn_for_each_confined(label, profile,
|
||||||
|
|
|
@ -1125,8 +1125,8 @@ ssize_t aa_remove_profiles(struct aa_ns *policy_ns, struct aa_label *subj,
|
||||||
if (!name) {
|
if (!name) {
|
||||||
/* remove namespace - can only happen if fqname[0] == ':' */
|
/* remove namespace - can only happen if fqname[0] == ':' */
|
||||||
mutex_lock_nested(&ns->parent->lock, ns->level);
|
mutex_lock_nested(&ns->parent->lock, ns->level);
|
||||||
__aa_remove_ns(ns);
|
|
||||||
__aa_bump_ns_revision(ns);
|
__aa_bump_ns_revision(ns);
|
||||||
|
__aa_remove_ns(ns);
|
||||||
mutex_unlock(&ns->parent->lock);
|
mutex_unlock(&ns->parent->lock);
|
||||||
} else {
|
} else {
|
||||||
/* remove profile */
|
/* remove profile */
|
||||||
|
@ -1138,9 +1138,9 @@ ssize_t aa_remove_profiles(struct aa_ns *policy_ns, struct aa_label *subj,
|
||||||
goto fail_ns_lock;
|
goto fail_ns_lock;
|
||||||
}
|
}
|
||||||
name = profile->base.hname;
|
name = profile->base.hname;
|
||||||
|
__aa_bump_ns_revision(ns);
|
||||||
__remove_profile(profile);
|
__remove_profile(profile);
|
||||||
__aa_labelset_update_subtree(ns);
|
__aa_labelset_update_subtree(ns);
|
||||||
__aa_bump_ns_revision(ns);
|
|
||||||
mutex_unlock(&ns->lock);
|
mutex_unlock(&ns->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue