LSM: Move security_path_chmod()/security_path_chown() to after mutex_lock().
Tetsuo Handa [Sun, 22 Nov 2009 02:49:55 +0000 (11:49 +0900)]
We should call security_path_chmod()/security_path_chown() after mutex_lock()
in order to avoid races.

Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Acked-by: John Johansen <john.johansen@canonical.com>
Signed-off-by: James Morris <jmorris@namei.org>

fs/open.c

index 201041d..b4b31d2 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -619,17 +619,17 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd, mode_t, mode)
        err = mnt_want_write_file(file);
        if (err)
                goto out_putf;
+       mutex_lock(&inode->i_mutex);
        err = security_path_chmod(dentry, file->f_vfsmnt, mode);
        if (err)
-               goto out_drop_write;
-       mutex_lock(&inode->i_mutex);
+               goto out_unlock;
        if (mode == (mode_t) -1)
                mode = inode->i_mode;
        newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
        newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
        err = notify_change(dentry, &newattrs);
+out_unlock:
        mutex_unlock(&inode->i_mutex);
-out_drop_write:
        mnt_drop_write(file->f_path.mnt);
 out_putf:
        fput(file);
@@ -652,17 +652,17 @@ SYSCALL_DEFINE3(fchmodat, int, dfd, const char __user *, filename, mode_t, mode)
        error = mnt_want_write(path.mnt);
        if (error)
                goto dput_and_out;
+       mutex_lock(&inode->i_mutex);
        error = security_path_chmod(path.dentry, path.mnt, mode);
        if (error)
-               goto out_drop_write;
-       mutex_lock(&inode->i_mutex);
+               goto out_unlock;
        if (mode == (mode_t) -1)
                mode = inode->i_mode;
        newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
        newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
        error = notify_change(path.dentry, &newattrs);
+out_unlock:
        mutex_unlock(&inode->i_mutex);
-out_drop_write:
        mnt_drop_write(path.mnt);
 dput_and_out:
        path_put(&path);
@@ -675,9 +675,9 @@ SYSCALL_DEFINE2(chmod, const char __user *, filename, mode_t, mode)
        return sys_fchmodat(AT_FDCWD, filename, mode);
 }
 
-static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
+static int chown_common(struct path *path, uid_t user, gid_t group)
 {
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = path->dentry->d_inode;
        int error;
        struct iattr newattrs;
 
@@ -694,7 +694,9 @@ static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
                newattrs.ia_valid |=
                        ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV;
        mutex_lock(&inode->i_mutex);
-       error = notify_change(dentry, &newattrs);
+       error = security_path_chown(path, user, group);
+       if (!error)
+               error = notify_change(path->dentry, &newattrs);
        mutex_unlock(&inode->i_mutex);
 
        return error;
@@ -711,9 +713,7 @@ SYSCALL_DEFINE3(chown, const char __user *, filename, uid_t, user, gid_t, group)
        error = mnt_want_write(path.mnt);
        if (error)
                goto out_release;
-       error = security_path_chown(&path, user, group);
-       if (!error)
-               error = chown_common(path.dentry, user, group);
+       error = chown_common(&path, user, group);
        mnt_drop_write(path.mnt);
 out_release:
        path_put(&path);
@@ -738,9 +738,7 @@ SYSCALL_DEFINE5(fchownat, int, dfd, const char __user *, filename, uid_t, user,
        error = mnt_want_write(path.mnt);
        if (error)
                goto out_release;
-       error = security_path_chown(&path, user, group);
-       if (!error)
-               error = chown_common(path.dentry, user, group);
+       error = chown_common(&path, user, group);
        mnt_drop_write(path.mnt);
 out_release:
        path_put(&path);
@@ -759,9 +757,7 @@ SYSCALL_DEFINE3(lchown, const char __user *, filename, uid_t, user, gid_t, group
        error = mnt_want_write(path.mnt);
        if (error)
                goto out_release;
-       error = security_path_chown(&path, user, group);
-       if (!error)
-               error = chown_common(path.dentry, user, group);
+       error = chown_common(&path, user, group);
        mnt_drop_write(path.mnt);
 out_release:
        path_put(&path);
@@ -784,9 +780,7 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group)
                goto out_fput;
        dentry = file->f_path.dentry;
        audit_inode(NULL, dentry);
-       error = security_path_chown(&file->f_path, user, group);
-       if (!error)
-               error = chown_common(dentry, user, group);
+       error = chown_common(&file->f_path, user, group);
        mnt_drop_write(file->f_path.mnt);
 out_fput:
        fput(file);