summaryrefslogtreecommitdiffstats
path: root/security/apparmor/apparmorfs.c
diff options
context:
space:
mode:
authorJohn Johansen <john.johansen@canonical.com>2017-06-09 11:08:28 +0200
committerJohn Johansen <john.johansen@canonical.com>2017-06-11 02:11:34 +0200
commitcf797c0e5e312520b0b9f0367039fc0279a07a76 (patch)
tree68dc51534745fb230ec35e1d56bb158fb99b225b /security/apparmor/apparmorfs.c
parentapparmor: move bprm_committing_creds/committed_creds to lsm.c (diff)
downloadlinux-cf797c0e5e312520b0b9f0367039fc0279a07a76.tar.xz
linux-cf797c0e5e312520b0b9f0367039fc0279a07a76.zip
apparmor: convert to profile block critical sections
There are still a few places where profile replacement fails to update and a stale profile is used for mediation. Fix this by moving to accessing the current label through a critical section that will always ensure mediation is using the current label regardless of whether the tasks cred has been updated or not. Signed-off-by: John Johansen <john.johansen@canonical.com>
Diffstat (limited to 'security/apparmor/apparmorfs.c')
-rw-r--r--security/apparmor/apparmorfs.c40
1 files changed, 25 insertions, 15 deletions
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index b64ea21a42ad..e2919a0766b0 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -407,7 +407,10 @@ static ssize_t policy_update(u32 mask, const char __user *buf, size_t size,
{
ssize_t error;
struct aa_loaddata *data;
- struct aa_profile *profile = aa_current_profile();
+ struct aa_profile *profile;
+
+ profile = begin_current_profile_crit_section();
+
/* high level check about policy management - fine grained in
* below after unpack
*/
@@ -421,6 +424,7 @@ static ssize_t policy_update(u32 mask, const char __user *buf, size_t size,
error = aa_replace_profiles(ns, profile, mask, data);
aa_put_loaddata(data);
}
+ end_current_profile_crit_section(profile);
return error;
}
@@ -468,7 +472,7 @@ static ssize_t profile_remove(struct file *f, const char __user *buf,
ssize_t error;
struct aa_ns *ns = aa_get_ns(f->f_inode->i_private);
- profile = aa_current_profile();
+ profile = begin_current_profile_crit_section();
/* high level check about policy management - fine grained in
* below after unpack
*/
@@ -489,6 +493,7 @@ static ssize_t profile_remove(struct file *f, const char __user *buf,
aa_put_loaddata(data);
}
out:
+ end_current_profile_crit_section(profile);
aa_put_ns(ns);
return error;
}
@@ -667,8 +672,9 @@ static ssize_t query_data(char *buf, size_t buf_len,
if (buf_len < sizeof(bytes) + sizeof(blocks))
return -EINVAL; /* not enough space */
- curr = aa_current_profile();
+ curr = begin_current_profile_crit_section();
profile = aa_fqlookupn_profile(curr, query, strnlen(query, query_len));
+ end_current_profile_crit_section(curr);
if (!profile)
return -ENOENT;
@@ -754,8 +760,9 @@ static ssize_t query_label(char *buf, size_t buf_len,
match_str = label_name + label_name_len + 1;
match_len = query_len - label_name_len - 1;
- curr = aa_current_profile();
+ curr = begin_current_profile_crit_section();
profile = aa_fqlookupn_profile(curr, label_name, label_name_len);
+ end_current_profile_crit_section(curr);
if (!profile)
return -ENOENT;
@@ -1094,18 +1101,22 @@ static const struct file_operations seq_ns_ ##NAME ##_fops = { \
static int seq_ns_level_show(struct seq_file *seq, void *v)
{
- struct aa_ns *ns = aa_current_profile()->ns;
+ struct aa_profile *profile;
- seq_printf(seq, "%d\n", ns->level);
+ profile = begin_current_profile_crit_section();
+ seq_printf(seq, "%d\n", profile->ns->level);
+ end_current_profile_crit_section(profile);
return 0;
}
static int seq_ns_name_show(struct seq_file *seq, void *v)
{
- struct aa_ns *ns = aa_current_profile()->ns;
+ struct aa_profile *profile;
- seq_printf(seq, "%s\n", aa_ns_name(ns, ns, true));
+ profile = begin_current_profile_crit_section();
+ seq_printf(seq, "%s\n", aa_ns_name(profile->ns, profile->ns, true));
+ end_current_profile_crit_section(profile);
return 0;
}
@@ -1530,9 +1541,9 @@ static int ns_mkdir_op(struct inode *dir, struct dentry *dentry, umode_t mode)
{
struct aa_ns *ns, *parent;
/* TODO: improve permission check */
- struct aa_profile *profile = aa_current_profile();
+ struct aa_profile *profile = begin_current_profile_crit_section();
int error = aa_may_manage_policy(profile, NULL, AA_MAY_LOAD_POLICY);
-
+ end_current_profile_crit_section(profile);
if (error)
return error;
@@ -1576,9 +1587,9 @@ static int ns_rmdir_op(struct inode *dir, struct dentry *dentry)
{
struct aa_ns *ns, *parent;
/* TODO: improve permission check */
- struct aa_profile *profile = aa_current_profile();
+ struct aa_profile *profile = begin_current_profile_crit_section();
int error = aa_may_manage_policy(profile, NULL, AA_MAY_LOAD_POLICY);
-
+ end_current_profile_crit_section(profile);
if (error)
return error;
@@ -1922,10 +1933,9 @@ static struct aa_profile *next_profile(struct aa_ns *root,
static void *p_start(struct seq_file *f, loff_t *pos)
{
struct aa_profile *profile = NULL;
- struct aa_ns *root = aa_current_profile()->ns;
+ struct aa_ns *root = aa_get_current_ns();
loff_t l = *pos;
- f->private = aa_get_ns(root);
-
+ f->private = root;
/* find the first profile */
mutex_lock(&root->lock);