Commit f2f5c290 authored by John Johansen's avatar John Johansen Committed by Thadeu Lima de Souza Cascardo

UBUNTU: SAUCE: apparmor: fix lock ordering for mkdir

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/1645037Signed-off-by: default avatarJohn Johansen <john.johansen@canonical.com>
Acked-by: default avatarStefan Bader <stefan.bader@canonical.com>
Acked-by: default avatarTim Gardner <tim.gardner@canonical.com>
Acked-by: default avatarBrad Figg <brad.figg@canonical.com>
Signed-off-by: default avatarThadeu Lima de Souza Cascardo <cascardo@canonical.com>
parent 70330b27
......@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment