summaryrefslogtreecommitdiffstats
path: root/security/apparmor/apparmorfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/apparmor/apparmorfs.c')
-rw-r--r--security/apparmor/apparmorfs.c66
1 files changed, 49 insertions, 17 deletions
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 853c2ec8e0c9..8542e9a55e1b 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -32,6 +32,7 @@
#include "include/audit.h"
#include "include/context.h"
#include "include/crypto.h"
+#include "include/ipc.h"
#include "include/policy_ns.h"
#include "include/label.h"
#include "include/policy.h"
@@ -248,8 +249,10 @@ static struct dentry *aafs_create(const char *name, umode_t mode,
inode_lock(dir);
dentry = lookup_one_len(name, parent, strlen(name));
- if (IS_ERR(dentry))
+ if (IS_ERR(dentry)) {
+ error = PTR_ERR(dentry);
goto fail_lock;
+ }
if (d_really_is_positive(dentry)) {
error = -EEXIST;
@@ -530,7 +533,7 @@ static ssize_t ns_revision_read(struct file *file, char __user *buf,
long last_read;
int avail;
- mutex_lock(&rev->ns->lock);
+ mutex_lock_nested(&rev->ns->lock, rev->ns->level);
last_read = rev->last_read;
if (last_read == rev->ns->revision) {
mutex_unlock(&rev->ns->lock);
@@ -540,7 +543,7 @@ static ssize_t ns_revision_read(struct file *file, char __user *buf,
last_read !=
READ_ONCE(rev->ns->revision)))
return -ERESTARTSYS;
- mutex_lock(&rev->ns->lock);
+ mutex_lock_nested(&rev->ns->lock, rev->ns->level);
}
avail = sprintf(buffer, "%ld\n", rev->ns->revision);
@@ -574,7 +577,7 @@ static unsigned int ns_revision_poll(struct file *file, poll_table *pt)
unsigned int mask = 0;
if (rev) {
- mutex_lock(&rev->ns->lock);
+ mutex_lock_nested(&rev->ns->lock, rev->ns->level);
poll_wait(file, &rev->ns->wait, pt);
if (rev->last_read < rev->ns->revision)
mask |= POLLIN | POLLRDNORM;
@@ -1443,6 +1446,10 @@ void __aafs_profile_migrate_dents(struct aa_profile *old,
{
int i;
+ AA_BUG(!old);
+ AA_BUG(!new);
+ AA_BUG(!mutex_is_locked(&profiles_ns(old)->lock));
+
for (i = 0; i < AAFS_PROF_SIZEOF; i++) {
new->dents[i] = old->dents[i];
if (new->dents[i])
@@ -1506,6 +1513,9 @@ int __aafs_profile_mkdir(struct aa_profile *profile, struct dentry *parent)
struct dentry *dent = NULL, *dir;
int error;
+ AA_BUG(!profile);
+ AA_BUG(!mutex_is_locked(&profiles_ns(profile)->lock));
+
if (!parent) {
struct aa_profile *p;
p = aa_deref_parent(profile);
@@ -1633,7 +1643,7 @@ static int ns_mkdir_op(struct inode *dir, struct dentry *dentry, umode_t mode)
*/
inode_unlock(dir);
error = simple_pin_fs(&aafs_ops, &aafs_mnt, &aafs_count);
- mutex_lock(&parent->lock);
+ mutex_lock_nested(&parent->lock, parent->level);
inode_lock_nested(dir, I_MUTEX_PARENT);
if (error)
goto out;
@@ -1682,7 +1692,7 @@ static int ns_rmdir_op(struct inode *dir, struct dentry *dentry)
inode_unlock(dir);
inode_unlock(dentry->d_inode);
- mutex_lock(&parent->lock);
+ mutex_lock_nested(&parent->lock, parent->level);
ns = aa_get_ns(__aa_findn_ns(&parent->sub_ns, dentry->d_name.name,
dentry->d_name.len));
if (!ns) {
@@ -1731,12 +1741,13 @@ void __aafs_ns_rmdir(struct aa_ns *ns)
if (!ns)
return;
+ AA_BUG(!mutex_is_locked(&ns->lock));
list_for_each_entry(child, &ns->base.profiles, base.list)
__aafs_profile_rmdir(child);
list_for_each_entry(sub, &ns->sub_ns, base.list) {
- mutex_lock(&sub->lock);
+ mutex_lock_nested(&sub->lock, sub->level);
__aafs_ns_rmdir(sub);
mutex_unlock(&sub->lock);
}
@@ -1866,7 +1877,7 @@ int __aafs_ns_mkdir(struct aa_ns *ns, struct dentry *parent, const char *name,
/* subnamespaces */
list_for_each_entry(sub, &ns->sub_ns, base.list) {
- mutex_lock(&sub->lock);
+ mutex_lock_nested(&sub->lock, sub->level);
error = __aafs_ns_mkdir(sub, ns_subns_dir(ns), NULL, NULL);
mutex_unlock(&sub->lock);
if (error)
@@ -1903,10 +1914,14 @@ static struct aa_ns *__next_ns(struct aa_ns *root, struct aa_ns *ns)
{
struct aa_ns *parent, *next;
+ AA_BUG(!root);
+ AA_BUG(!ns);
+ AA_BUG(ns != root && !mutex_is_locked(&ns->parent->lock));
+
/* is next namespace a child */
if (!list_empty(&ns->sub_ns)) {
next = list_first_entry(&ns->sub_ns, typeof(*ns), base.list);
- mutex_lock(&next->lock);
+ mutex_lock_nested(&next->lock, next->level);
return next;
}
@@ -1916,7 +1931,7 @@ static struct aa_ns *__next_ns(struct aa_ns *root, struct aa_ns *ns)
mutex_unlock(&ns->lock);
next = list_next_entry(ns, base.list);
if (!list_entry_is_head(next, &parent->sub_ns, base.list)) {
- mutex_lock(&next->lock);
+ mutex_lock_nested(&next->lock, next->level);
return next;
}
ns = parent;
@@ -1937,6 +1952,9 @@ static struct aa_ns *__next_ns(struct aa_ns *root, struct aa_ns *ns)
static struct aa_profile *__first_profile(struct aa_ns *root,
struct aa_ns *ns)
{
+ AA_BUG(!root);
+ AA_BUG(ns && !mutex_is_locked(&ns->lock));
+
for (; ns; ns = __next_ns(root, ns)) {
if (!list_empty(&ns->base.profiles))
return list_first_entry(&ns->base.profiles,
@@ -1959,6 +1977,8 @@ static struct aa_profile *__next_profile(struct aa_profile *p)
struct aa_profile *parent;
struct aa_ns *ns = p->ns;
+ AA_BUG(!mutex_is_locked(&profiles_ns(p)->lock));
+
/* is next profile a child */
if (!list_empty(&p->base.profiles))
return list_first_entry(&p->base.profiles, typeof(*p),
@@ -2019,7 +2039,7 @@ static void *p_start(struct seq_file *f, loff_t *pos)
f->private = root;
/* find the first profile */
- mutex_lock(&root->lock);
+ mutex_lock_nested(&root->lock, root->level);
profile = __first_profile(root, root);
/* skip to position */
@@ -2127,6 +2147,11 @@ static struct aa_sfs_entry aa_sfs_entry_ptrace[] = {
{ }
};
+static struct aa_sfs_entry aa_sfs_entry_signal[] = {
+ AA_SFS_FILE_STRING("mask", AA_SFS_SIG_MASK),
+ { }
+};
+
static struct aa_sfs_entry aa_sfs_entry_domain[] = {
AA_SFS_FILE_BOOLEAN("change_hat", 1),
AA_SFS_FILE_BOOLEAN("change_hatv", 1),
@@ -2151,9 +2176,14 @@ static struct aa_sfs_entry aa_sfs_entry_policy[] = {
{ }
};
+static struct aa_sfs_entry aa_sfs_entry_mount[] = {
+ AA_SFS_FILE_STRING("mask", "mount umount pivot_root"),
+ { }
+};
+
static struct aa_sfs_entry aa_sfs_entry_ns[] = {
AA_SFS_FILE_BOOLEAN("profile", 1),
- AA_SFS_FILE_BOOLEAN("pivot_root", 1),
+ AA_SFS_FILE_BOOLEAN("pivot_root", 0),
{ }
};
@@ -2172,22 +2202,24 @@ static struct aa_sfs_entry aa_sfs_entry_features[] = {
AA_SFS_DIR("policy", aa_sfs_entry_policy),
AA_SFS_DIR("domain", aa_sfs_entry_domain),
AA_SFS_DIR("file", aa_sfs_entry_file),
+ AA_SFS_DIR("mount", aa_sfs_entry_mount),
AA_SFS_DIR("namespaces", aa_sfs_entry_ns),
AA_SFS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
AA_SFS_DIR("rlimit", aa_sfs_entry_rlimit),
AA_SFS_DIR("caps", aa_sfs_entry_caps),
AA_SFS_DIR("ptrace", aa_sfs_entry_ptrace),
+ AA_SFS_DIR("signal", aa_sfs_entry_signal),
AA_SFS_DIR("query", aa_sfs_entry_query),
{ }
};
static struct aa_sfs_entry aa_sfs_entry_apparmor[] = {
- AA_SFS_FILE_FOPS(".access", 0640, &aa_sfs_access),
+ AA_SFS_FILE_FOPS(".access", 0666, &aa_sfs_access),
AA_SFS_FILE_FOPS(".stacked", 0444, &seq_ns_stacked_fops),
AA_SFS_FILE_FOPS(".ns_stacked", 0444, &seq_ns_nsstacked_fops),
- AA_SFS_FILE_FOPS(".ns_level", 0666, &seq_ns_level_fops),
- AA_SFS_FILE_FOPS(".ns_name", 0640, &seq_ns_name_fops),
- AA_SFS_FILE_FOPS("profiles", 0440, &aa_sfs_profiles_fops),
+ AA_SFS_FILE_FOPS(".ns_level", 0444, &seq_ns_level_fops),
+ AA_SFS_FILE_FOPS(".ns_name", 0444, &seq_ns_name_fops),
+ AA_SFS_FILE_FOPS("profiles", 0444, &aa_sfs_profiles_fops),
AA_SFS_DIR("features", aa_sfs_entry_features),
{ }
};
@@ -2459,7 +2491,7 @@ static int __init aa_create_aafs(void)
ns_subrevision(root_ns) = dent;
/* policy tree referenced by magic policy symlink */
- mutex_lock(&root_ns->lock);
+ mutex_lock_nested(&root_ns->lock, root_ns->level);
error = __aafs_ns_mkdir(root_ns, aafs_mnt->mnt_root, ".policy",
aafs_mnt->mnt_root);
mutex_unlock(&root_ns->lock);