@@ -1050,6 +1050,7 @@ static int ns_mkdir_op(struct inode *dir, struct dentry *dentry, umode_t mode)
*/
inode_unlock(dir);
error = securityfs_pin_fs();
+ mutex_lock(&parent->lock);
inode_lock_nested(dir, I_MUTEX_PARENT);
if (error)
goto out;
@@ -1059,7 +1060,8 @@ static int ns_mkdir_op(struct inode *dir, struct dentry *dentry, umode_t mode)
if (error)
goto out_pin;
- ns = aa_create_ns(parent, ACCESS_ONCE(dentry->d_name.name), dentry);
+ ns = __aa_find_or_create_ns(parent, READ_ONCE(dentry->d_name.name),
+ dentry);
if (IS_ERR(ns)) {
error = PTR_ERR(ns);
ns = NULL;
@@ -1069,6 +1071,7 @@ static int ns_mkdir_op(struct inode *dir, struct dentry *dentry, umode_t mode)
out_pin:
securityfs_release_fs();
out:
+ mutex_unlock(&parent->lock);
aa_put_ns(parent);
return error;
@@ -88,8 +88,8 @@ void aa_free_ns_kref(struct kref *kref);
struct aa_ns *aa_find_ns(struct aa_ns *root, const char *name);
struct aa_ns *aa_findn_ns(struct aa_ns *root, const char *name, size_t n);
-struct aa_ns *aa_create_ns(struct aa_ns *parent, const char *name,
- struct dentry *dir);
+struct aa_ns *__aa_find_or_create_ns(struct aa_ns *parent, const char *name,
+ struct dentry *dir);
struct aa_ns *aa_prepare_ns(struct aa_ns *root, const char *name);
void __aa_remove_ns(struct aa_ns *ns);
@@ -225,12 +225,13 @@ static struct aa_ns *__aa_create_ns(struct aa_ns *parent, const char *name,
*
* Returns: the a refcounted ns that has been add or an ERR_PTR
*/
-struct aa_ns *aa_create_ns(struct aa_ns *parent, const char *name,
- struct dentry *dir)
+struct aa_ns *__aa_find_or_create_ns(struct aa_ns *parent, const char *name,
+ struct dentry *dir)
{
struct aa_ns *ns;
- mutex_lock(&parent->lock);
+ AA_BUG(!mutex_is_locked(&parent->lock));
+
/* try and find the specified ns */
/* released by caller */
ns = aa_get_ns(__aa_find_ns(&parent->sub_ns, name));
@@ -238,7 +239,6 @@ struct aa_ns *aa_create_ns(struct aa_ns *parent, const char *name,
ns = __aa_create_ns(parent, name, dir);
else
ns = ERR_PTR(-EEXIST);
- mutex_unlock(&parent->lock);
/* return ref */
return ns;
There is a lock inversion that can result in a dead lock when profile replacements are racing with dir creation for a namespace in apparmorfs. BugLink: http://bugs.launchpad.net/bugs/1645037 Signed-off-by: John Johansen <john.johansen@canonical.com> --- security/apparmor/apparmorfs.c | 5 ++++- security/apparmor/include/policy_ns.h | 4 ++-- security/apparmor/policy_ns.c | 8 ++++---- 3 files changed, 10 insertions(+), 7 deletions(-)