]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - fs/file.c
debugfs: fix use-after-free on symlink traversal
[linux.git] / fs / file.c
index 3209ee271c41d15f0138164fd822e236e5125560..3da91a112babe874af392635a32e971d8885937f 100644 (file)
--- a/fs/file.c
+++ b/fs/file.c
@@ -457,6 +457,7 @@ struct files_struct init_files = {
                .full_fds_bits  = init_files.full_fds_bits_init,
        },
        .file_lock      = __SPIN_LOCK_UNLOCKED(init_files.file_lock),
+       .resize_wait    = __WAIT_QUEUE_HEAD_INITIALIZER(init_files.resize_wait),
 };
 
 static unsigned int find_next_fd(struct fdtable *fdt, unsigned int start)
@@ -705,7 +706,7 @@ void do_close_on_exec(struct files_struct *files)
        spin_unlock(&files->file_lock);
 }
 
-static struct file *__fget(unsigned int fd, fmode_t mask)
+static struct file *__fget(unsigned int fd, fmode_t mask, unsigned int refs)
 {
        struct files_struct *files = current->files;
        struct file *file;
@@ -720,7 +721,7 @@ static struct file *__fget(unsigned int fd, fmode_t mask)
                 */
                if (file->f_mode & mask)
                        file = NULL;
-               else if (!get_file_rcu(file))
+               else if (!get_file_rcu_many(file, refs))
                        goto loop;
        }
        rcu_read_unlock();
@@ -728,15 +729,20 @@ static struct file *__fget(unsigned int fd, fmode_t mask)
        return file;
 }
 
+struct file *fget_many(unsigned int fd, unsigned int refs)
+{
+       return __fget(fd, FMODE_PATH, refs);
+}
+
 struct file *fget(unsigned int fd)
 {
-       return __fget(fd, FMODE_PATH);
+       return __fget(fd, FMODE_PATH, 1);
 }
 EXPORT_SYMBOL(fget);
 
 struct file *fget_raw(unsigned int fd)
 {
-       return __fget(fd, 0);
+       return __fget(fd, 0, 1);
 }
 EXPORT_SYMBOL(fget_raw);
 
@@ -767,7 +773,7 @@ static unsigned long __fget_light(unsigned int fd, fmode_t mask)
                        return 0;
                return (unsigned long)file;
        } else {
-               file = __fget(fd, mask);
+               file = __fget(fd, mask, 1);
                if (!file)
                        return 0;
                return FDPUT_FPUT | (unsigned long)file;