summaryrefslogtreecommitdiffstats
path: root/security/apparmor/lsm.c
diff options
context:
space:
mode:
authorJohn Johansen <john.johansen@canonical.com>2017-06-09 02:08:28 -0700
committerJohn Johansen <john.johansen@canonical.com>2017-06-10 17:11:34 -0700
commitcf797c0e5e312520b0b9f0367039fc0279a07a76 (patch)
tree68dc51534745fb230ec35e1d56bb158fb99b225b /security/apparmor/lsm.c
parentfe864821d504f33f22b3ce2d5599ae95598db721 (diff)
downloadop-kernel-dev-cf797c0e5e312520b0b9f0367039fc0279a07a76.zip
op-kernel-dev-cf797c0e5e312520b0b9f0367039fc0279a07a76.tar.gz
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/lsm.c')
-rw-r--r--security/apparmor/lsm.c41
1 files changed, 29 insertions, 12 deletions
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 3549200..49b780b 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -120,7 +120,7 @@ static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective,
rcu_read_lock();
cred = __task_cred(target);
- profile = aa_cred_profile(cred);
+ profile = aa_get_newest_cred_profile(cred);
/*
* cap_capget is stacked ahead of this and will
@@ -131,6 +131,7 @@ static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective,
*permitted = cap_intersect(*permitted, profile->caps.allow);
}
rcu_read_unlock();
+ aa_put_profile(profile);
return 0;
}
@@ -141,9 +142,11 @@ static int apparmor_capable(const struct cred *cred, struct user_namespace *ns,
struct aa_profile *profile;
int error = 0;
- profile = aa_cred_profile(cred);
+ profile = aa_get_newest_cred_profile(cred);
if (!unconfined(profile))
error = aa_capable(profile, cap, audit);
+ aa_put_profile(profile);
+
return error;
}
@@ -162,9 +165,10 @@ static int common_perm(const char *op, const struct path *path, u32 mask,
struct aa_profile *profile;
int error = 0;
- profile = __aa_current_profile();
+ profile = __begin_current_profile_crit_section();
if (!unconfined(profile))
error = aa_path_perm(op, profile, path, 0, mask, cond);
+ __end_current_profile_crit_section(profile);
return error;
}
@@ -297,9 +301,11 @@ static int apparmor_path_link(struct dentry *old_dentry, const struct path *new_
if (!path_mediated_fs(old_dentry))
return 0;
- profile = aa_current_profile();
+ profile = begin_current_profile_crit_section();
if (!unconfined(profile))
error = aa_path_link(profile, old_dentry, new_dir, new_dentry);
+ end_current_profile_crit_section(profile);
+
return error;
}
@@ -312,7 +318,7 @@ static int apparmor_path_rename(const struct path *old_dir, struct dentry *old_d
if (!path_mediated_fs(old_dentry))
return 0;
- profile = aa_current_profile();
+ profile = begin_current_profile_crit_section();
if (!unconfined(profile)) {
struct path old_path = { .mnt = old_dir->mnt,
.dentry = old_dentry };
@@ -332,6 +338,8 @@ static int apparmor_path_rename(const struct path *old_dir, struct dentry *old_d
AA_MAY_CREATE, &cond);
}
+ end_current_profile_crit_section(profile);
+
return error;
}
@@ -369,7 +377,7 @@ static int apparmor_file_open(struct file *file, const struct cred *cred)
return 0;
}
- profile = aa_cred_profile(cred);
+ profile = aa_get_newest_cred_profile(cred);
if (!unconfined(profile)) {
struct inode *inode = file_inode(file);
struct path_cond cond = { inode->i_uid, inode->i_mode };
@@ -379,18 +387,23 @@ static int apparmor_file_open(struct file *file, const struct cred *cred)
/* todo cache full allowed permissions set and state */
fctx->allow = aa_map_file_to_perms(file);
}
+ aa_put_profile(profile);
return error;
}
static int apparmor_file_alloc_security(struct file *file)
{
+ int error = 0;
+
/* freed by apparmor_file_free_security */
+ struct aa_profile *profile = begin_current_profile_crit_section();
file->f_security = aa_alloc_file_context(GFP_KERNEL);
if (!file->f_security)
return -ENOMEM;
- return 0;
+ end_current_profile_crit_section(profile);
+ return error;
}
static void apparmor_file_free_security(struct file *file)
@@ -403,16 +416,17 @@ static void apparmor_file_free_security(struct file *file)
static int common_file_perm(const char *op, struct file *file, u32 mask)
{
struct aa_file_ctx *fctx = file->f_security;
- struct aa_profile *profile, *fprofile = aa_cred_profile(file->f_cred);
+ struct aa_profile *profile, *fprofile;
int error = 0;
+ fprofile = aa_cred_raw_profile(file->f_cred);
AA_BUG(!fprofile);
if (!file->f_path.mnt ||
!path_mediated_fs(file->f_path.dentry))
return 0;
- profile = __aa_current_profile();
+ profile = __begin_current_profile_crit_section();
/* revalidate access, if task is unconfined, or the cached cred
* doesn't match or if the request is for more permissions than
@@ -424,6 +438,7 @@ static int common_file_perm(const char *op, struct file *file, u32 mask)
if (!unconfined(profile) && !unconfined(fprofile) &&
((fprofile != profile) || (mask & ~fctx->allow)))
error = aa_file_perm(op, profile, file, mask);
+ __end_current_profile_crit_section(profile);
return error;
}
@@ -568,10 +583,11 @@ out:
return error;
fail:
- aad(&sa)->profile = aa_current_profile();
+ aad(&sa)->profile = begin_current_profile_crit_section();
aad(&sa)->info = name;
aad(&sa)->error = error = -EINVAL;
aa_audit_msg(AUDIT_APPARMOR_DENIED, &sa, NULL);
+ end_current_profile_crit_section(aad(&sa)->profile);
goto out;
}
@@ -581,7 +597,7 @@ fail:
*/
static void apparmor_bprm_committing_creds(struct linux_binprm *bprm)
{
- struct aa_profile *profile = __aa_current_profile();
+ struct aa_profile *profile = aa_current_raw_profile();
struct aa_task_ctx *new_ctx = cred_ctx(bprm->cred);
/* bail out if unconfined or not changing profile */
@@ -608,11 +624,12 @@ static void apparmor_bprm_committed_creds(struct linux_binprm *bprm)
static int apparmor_task_setrlimit(struct task_struct *task,
unsigned int resource, struct rlimit *new_rlim)
{
- struct aa_profile *profile = __aa_current_profile();
+ struct aa_profile *profile = __begin_current_profile_crit_section();
int error = 0;
if (!unconfined(profile))
error = aa_task_setrlimit(profile, task, resource, new_rlim);
+ __end_current_profile_crit_section(profile);
return error;
}
OpenPOWER on IntegriCloud