Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
[linux-2.6-block.git] / fs / namei.c
index 2e0a1c5729f1cf64cc9cac54419dcd1714a41a32..734cef54fdf8b0cc3c4136dc3b11f6e07c5952e2 100644 (file)
@@ -537,12 +537,12 @@ static int __nd_alloc_stack(struct nameidata *nd)
        struct saved *p;
 
        if (nd->flags & LOOKUP_RCU) {
-               p= kmalloc(MAXSYMLINKS * sizeof(struct saved),
+               p= kmalloc_array(MAXSYMLINKS, sizeof(struct saved),
                                  GFP_ATOMIC);
                if (unlikely(!p))
                        return -ECHILD;
        } else {
-               p= kmalloc(MAXSYMLINKS * sizeof(struct saved),
+               p= kmalloc_array(MAXSYMLINKS, sizeof(struct saved),
                                  GFP_KERNEL);
                if (unlikely(!p))
                        return -ENOMEM;
@@ -984,13 +984,15 @@ static bool safe_hardlink_source(struct inode *inode)
  */
 static int may_linkat(struct path *link)
 {
-       struct inode *inode;
+       struct inode *inode = link->dentry->d_inode;
+
+       /* Inode writeback is not safe when the uid or gid are invalid. */
+       if (!uid_valid(inode->i_uid) || !gid_valid(inode->i_gid))
+               return -EOVERFLOW;
 
        if (!sysctl_protected_hardlinks)
                return 0;
 
-       inode = link->dentry->d_inode;
-
        /* Source inode owner (or CAP_FOWNER) can hardlink all they like,
         * otherwise, it must be a safe source.
         */
@@ -1438,10 +1440,8 @@ static int path_parent_directory(struct path *path)
 static int follow_dotdot(struct nameidata *nd)
 {
        while(1) {
-               if (nd->path.dentry == nd->root.dentry &&
-                   nd->path.mnt == nd->root.mnt) {
+               if (path_equal(&nd->path, &nd->root))
                        break;
-               }
                if (nd->path.dentry != nd->path.mnt->mnt_root) {
                        int ret = path_parent_directory(&nd->path);
                        if (ret)
@@ -2778,6 +2778,11 @@ static int may_delete(struct inode *dir, struct dentry *victim, bool isdir)
        BUG_ON(!inode);
 
        BUG_ON(victim->d_parent->d_inode != dir);
+
+       /* Inode writeback is not safe when the uid or gid are invalid. */
+       if (!uid_valid(inode->i_uid) || !gid_valid(inode->i_gid))
+               return -EOVERFLOW;
+
        audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE);
 
        error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
@@ -3396,7 +3401,9 @@ finish_open_created:
                goto out;
        *opened |= FILE_OPENED;
 opened:
-       error = ima_file_check(file, op->acc_mode, *opened);
+       error = open_check_o_direct(file);
+       if (!error)
+               error = ima_file_check(file, op->acc_mode, *opened);
        if (!error && will_truncate)
                error = handle_truncate(file);
 out:
@@ -3476,6 +3483,9 @@ static int do_tmpfile(struct nameidata *nd, unsigned flags,
        error = finish_open(file, child, NULL, opened);
        if (error)
                goto out2;
+       error = open_check_o_direct(file);
+       if (error)
+               fput(file);
 out2:
        mnt_drop_write(path.mnt);
 out:
@@ -3701,7 +3711,8 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
        if (error)
                return error;
 
-       if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD))
+       if ((S_ISCHR(mode) || S_ISBLK(mode)) &&
+           !ns_capable(dentry->d_sb->s_user_ns, CAP_MKNOD))
                return -EPERM;
 
        if (!dir->i_op->mknod)
@@ -3876,11 +3887,11 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry)
        if (error)
                goto out;
 
-       shrink_dcache_parent(dentry);
        error = dir->i_op->rmdir(dir, dentry);
        if (error)
                goto out;
 
+       shrink_dcache_parent(dentry);
        dentry->d_inode->i_flags |= S_DEAD;
        dont_mount(dentry);
        detach_mounts(dentry);
@@ -4463,8 +4474,6 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                    old_dir->i_nlink >= max_links)
                        goto out;
        }
-       if (is_dir && !(flags & RENAME_EXCHANGE) && target)
-               shrink_dcache_parent(new_dentry);
        if (!is_dir) {
                error = try_break_deleg(source, delegated_inode);
                if (error)
@@ -4481,8 +4490,10 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                goto out;
 
        if (!(flags & RENAME_EXCHANGE) && target) {
-               if (is_dir)
+               if (is_dir) {
+                       shrink_dcache_parent(new_dentry);
                        target->i_flags |= S_DEAD;
+               }
                dont_mount(new_dentry);
                detach_mounts(new_dentry);
        }