diff options
Diffstat (limited to 'fs/open.c')
-rw-r--r-- | fs/open.c | 130 |
1 files changed, 30 insertions, 100 deletions
@@ -132,27 +132,27 @@ SYSCALL_DEFINE2(truncate, const char __user *, path, long, length) | |||
132 | 132 | ||
133 | static long do_sys_ftruncate(unsigned int fd, loff_t length, int small) | 133 | static long do_sys_ftruncate(unsigned int fd, loff_t length, int small) |
134 | { | 134 | { |
135 | struct inode * inode; | 135 | struct inode *inode; |
136 | struct dentry *dentry; | 136 | struct dentry *dentry; |
137 | struct file * file; | 137 | struct fd f; |
138 | int error; | 138 | int error; |
139 | 139 | ||
140 | error = -EINVAL; | 140 | error = -EINVAL; |
141 | if (length < 0) | 141 | if (length < 0) |
142 | goto out; | 142 | goto out; |
143 | error = -EBADF; | 143 | error = -EBADF; |
144 | file = fget(fd); | 144 | f = fdget(fd); |
145 | if (!file) | 145 | if (!f.file) |
146 | goto out; | 146 | goto out; |
147 | 147 | ||
148 | /* explicitly opened as large or we are on 64-bit box */ | 148 | /* explicitly opened as large or we are on 64-bit box */ |
149 | if (file->f_flags & O_LARGEFILE) | 149 | if (f.file->f_flags & O_LARGEFILE) |
150 | small = 0; | 150 | small = 0; |
151 | 151 | ||
152 | dentry = file->f_path.dentry; | 152 | dentry = f.file->f_path.dentry; |
153 | inode = dentry->d_inode; | 153 | inode = dentry->d_inode; |
154 | error = -EINVAL; | 154 | error = -EINVAL; |
155 | if (!S_ISREG(inode->i_mode) || !(file->f_mode & FMODE_WRITE)) | 155 | if (!S_ISREG(inode->i_mode) || !(f.file->f_mode & FMODE_WRITE)) |
156 | goto out_putf; | 156 | goto out_putf; |
157 | 157 | ||
158 | error = -EINVAL; | 158 | error = -EINVAL; |
@@ -165,14 +165,14 @@ static long do_sys_ftruncate(unsigned int fd, loff_t length, int small) | |||
165 | goto out_putf; | 165 | goto out_putf; |
166 | 166 | ||
167 | sb_start_write(inode->i_sb); | 167 | sb_start_write(inode->i_sb); |
168 | error = locks_verify_truncate(inode, file, length); | 168 | error = locks_verify_truncate(inode, f.file, length); |
169 | if (!error) | 169 | if (!error) |
170 | error = security_path_truncate(&file->f_path); | 170 | error = security_path_truncate(&f.file->f_path); |
171 | if (!error) | 171 | if (!error) |
172 | error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, file); | 172 | error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, f.file); |
173 | sb_end_write(inode->i_sb); | 173 | sb_end_write(inode->i_sb); |
174 | out_putf: | 174 | out_putf: |
175 | fput(file); | 175 | fdput(f); |
176 | out: | 176 | out: |
177 | return error; | 177 | return error; |
178 | } | 178 | } |
@@ -276,15 +276,13 @@ int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len) | |||
276 | 276 | ||
277 | SYSCALL_DEFINE(fallocate)(int fd, int mode, loff_t offset, loff_t len) | 277 | SYSCALL_DEFINE(fallocate)(int fd, int mode, loff_t offset, loff_t len) |
278 | { | 278 | { |
279 | struct file *file; | 279 | struct fd f = fdget(fd); |
280 | int error = -EBADF; | 280 | int error = -EBADF; |
281 | 281 | ||
282 | file = fget(fd); | 282 | if (f.file) { |
283 | if (file) { | 283 | error = do_fallocate(f.file, mode, offset, len); |
284 | error = do_fallocate(file, mode, offset, len); | 284 | fdput(f); |
285 | fput(file); | ||
286 | } | 285 | } |
287 | |||
288 | return error; | 286 | return error; |
289 | } | 287 | } |
290 | 288 | ||
@@ -400,16 +398,15 @@ out: | |||
400 | 398 | ||
401 | SYSCALL_DEFINE1(fchdir, unsigned int, fd) | 399 | SYSCALL_DEFINE1(fchdir, unsigned int, fd) |
402 | { | 400 | { |
403 | struct file *file; | 401 | struct fd f = fdget_raw(fd); |
404 | struct inode *inode; | 402 | struct inode *inode; |
405 | int error, fput_needed; | 403 | int error = -EBADF; |
406 | 404 | ||
407 | error = -EBADF; | 405 | error = -EBADF; |
408 | file = fget_raw_light(fd, &fput_needed); | 406 | if (!f.file) |
409 | if (!file) | ||
410 | goto out; | 407 | goto out; |
411 | 408 | ||
412 | inode = file->f_path.dentry->d_inode; | 409 | inode = f.file->f_path.dentry->d_inode; |
413 | 410 | ||
414 | error = -ENOTDIR; | 411 | error = -ENOTDIR; |
415 | if (!S_ISDIR(inode->i_mode)) | 412 | if (!S_ISDIR(inode->i_mode)) |
@@ -417,9 +414,9 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd) | |||
417 | 414 | ||
418 | error = inode_permission(inode, MAY_EXEC | MAY_CHDIR); | 415 | error = inode_permission(inode, MAY_EXEC | MAY_CHDIR); |
419 | if (!error) | 416 | if (!error) |
420 | set_fs_pwd(current->fs, &file->f_path); | 417 | set_fs_pwd(current->fs, &f.file->f_path); |
421 | out_putf: | 418 | out_putf: |
422 | fput_light(file, fput_needed); | 419 | fdput(f); |
423 | out: | 420 | out: |
424 | return error; | 421 | return error; |
425 | } | 422 | } |
@@ -582,23 +579,20 @@ SYSCALL_DEFINE3(lchown, const char __user *, filename, uid_t, user, gid_t, group | |||
582 | 579 | ||
583 | SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group) | 580 | SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group) |
584 | { | 581 | { |
585 | struct file * file; | 582 | struct fd f = fdget(fd); |
586 | int error = -EBADF; | 583 | int error = -EBADF; |
587 | struct dentry * dentry; | ||
588 | 584 | ||
589 | file = fget(fd); | 585 | if (!f.file) |
590 | if (!file) | ||
591 | goto out; | 586 | goto out; |
592 | 587 | ||
593 | error = mnt_want_write_file(file); | 588 | error = mnt_want_write_file(f.file); |
594 | if (error) | 589 | if (error) |
595 | goto out_fput; | 590 | goto out_fput; |
596 | dentry = file->f_path.dentry; | 591 | audit_inode(NULL, f.file->f_path.dentry); |
597 | audit_inode(NULL, dentry); | 592 | error = chown_common(&f.file->f_path, user, group); |
598 | error = chown_common(&file->f_path, user, group); | 593 | mnt_drop_write_file(f.file); |
599 | mnt_drop_write_file(file); | ||
600 | out_fput: | 594 | out_fput: |
601 | fput(file); | 595 | fdput(f); |
602 | out: | 596 | out: |
603 | return error; | 597 | return error; |
604 | } | 598 | } |
@@ -803,50 +797,6 @@ struct file *dentry_open(const struct path *path, int flags, | |||
803 | } | 797 | } |
804 | EXPORT_SYMBOL(dentry_open); | 798 | EXPORT_SYMBOL(dentry_open); |
805 | 799 | ||
806 | static void __put_unused_fd(struct files_struct *files, unsigned int fd) | ||
807 | { | ||
808 | struct fdtable *fdt = files_fdtable(files); | ||
809 | __clear_open_fd(fd, fdt); | ||
810 | if (fd < files->next_fd) | ||
811 | files->next_fd = fd; | ||
812 | } | ||
813 | |||
814 | void put_unused_fd(unsigned int fd) | ||
815 | { | ||
816 | struct files_struct *files = current->files; | ||
817 | spin_lock(&files->file_lock); | ||
818 | __put_unused_fd(files, fd); | ||
819 | spin_unlock(&files->file_lock); | ||
820 | } | ||
821 | |||
822 | EXPORT_SYMBOL(put_unused_fd); | ||
823 | |||
824 | /* | ||
825 | * Install a file pointer in the fd array. | ||
826 | * | ||
827 | * The VFS is full of places where we drop the files lock between | ||
828 | * setting the open_fds bitmap and installing the file in the file | ||
829 | * array. At any such point, we are vulnerable to a dup2() race | ||
830 | * installing a file in the array before us. We need to detect this and | ||
831 | * fput() the struct file we are about to overwrite in this case. | ||
832 | * | ||
833 | * It should never happen - if we allow dup2() do it, _really_ bad things | ||
834 | * will follow. | ||
835 | */ | ||
836 | |||
837 | void fd_install(unsigned int fd, struct file *file) | ||
838 | { | ||
839 | struct files_struct *files = current->files; | ||
840 | struct fdtable *fdt; | ||
841 | spin_lock(&files->file_lock); | ||
842 | fdt = files_fdtable(files); | ||
843 | BUG_ON(fdt->fd[fd] != NULL); | ||
844 | rcu_assign_pointer(fdt->fd[fd], file); | ||
845 | spin_unlock(&files->file_lock); | ||
846 | } | ||
847 | |||
848 | EXPORT_SYMBOL(fd_install); | ||
849 | |||
850 | static inline int build_open_flags(int flags, umode_t mode, struct open_flags *op) | 800 | static inline int build_open_flags(int flags, umode_t mode, struct open_flags *op) |
851 | { | 801 | { |
852 | int lookup_flags = 0; | 802 | int lookup_flags = 0; |
@@ -858,7 +808,7 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o | |||
858 | op->mode = 0; | 808 | op->mode = 0; |
859 | 809 | ||
860 | /* Must never be set by userspace */ | 810 | /* Must never be set by userspace */ |
861 | flags &= ~FMODE_NONOTIFY; | 811 | flags &= ~FMODE_NONOTIFY & ~O_CLOEXEC; |
862 | 812 | ||
863 | /* | 813 | /* |
864 | * O_SYNC is implemented as __O_SYNC|O_DSYNC. As many places only | 814 | * O_SYNC is implemented as __O_SYNC|O_DSYNC. As many places only |
@@ -1038,23 +988,7 @@ EXPORT_SYMBOL(filp_close); | |||
1038 | */ | 988 | */ |
1039 | SYSCALL_DEFINE1(close, unsigned int, fd) | 989 | SYSCALL_DEFINE1(close, unsigned int, fd) |
1040 | { | 990 | { |
1041 | struct file * filp; | 991 | int retval = __close_fd(current->files, fd); |
1042 | struct files_struct *files = current->files; | ||
1043 | struct fdtable *fdt; | ||
1044 | int retval; | ||
1045 | |||
1046 | spin_lock(&files->file_lock); | ||
1047 | fdt = files_fdtable(files); | ||
1048 | if (fd >= fdt->max_fds) | ||
1049 | goto out_unlock; | ||
1050 | filp = fdt->fd[fd]; | ||
1051 | if (!filp) | ||
1052 | goto out_unlock; | ||
1053 | rcu_assign_pointer(fdt->fd[fd], NULL); | ||
1054 | __clear_close_on_exec(fd, fdt); | ||
1055 | __put_unused_fd(files, fd); | ||
1056 | spin_unlock(&files->file_lock); | ||
1057 | retval = filp_close(filp, files); | ||
1058 | 992 | ||
1059 | /* can't restart close syscall because file table entry was cleared */ | 993 | /* can't restart close syscall because file table entry was cleared */ |
1060 | if (unlikely(retval == -ERESTARTSYS || | 994 | if (unlikely(retval == -ERESTARTSYS || |
@@ -1064,10 +998,6 @@ SYSCALL_DEFINE1(close, unsigned int, fd) | |||
1064 | retval = -EINTR; | 998 | retval = -EINTR; |
1065 | 999 | ||
1066 | return retval; | 1000 | return retval; |
1067 | |||
1068 | out_unlock: | ||
1069 | spin_unlock(&files->file_lock); | ||
1070 | return -EBADF; | ||
1071 | } | 1001 | } |
1072 | EXPORT_SYMBOL(sys_close); | 1002 | EXPORT_SYMBOL(sys_close); |
1073 | 1003 | ||