diff options
Diffstat (limited to 'fs/fcntl.c')
-rw-r--r-- | fs/fcntl.c | 166 |
1 files changed, 20 insertions, 146 deletions
diff --git a/fs/fcntl.c b/fs/fcntl.c index 887b5ba8c9b5..8f704291d4ed 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c | |||
@@ -26,124 +26,6 @@ | |||
26 | #include <asm/siginfo.h> | 26 | #include <asm/siginfo.h> |
27 | #include <asm/uaccess.h> | 27 | #include <asm/uaccess.h> |
28 | 28 | ||
29 | void set_close_on_exec(unsigned int fd, int flag) | ||
30 | { | ||
31 | struct files_struct *files = current->files; | ||
32 | struct fdtable *fdt; | ||
33 | spin_lock(&files->file_lock); | ||
34 | fdt = files_fdtable(files); | ||
35 | if (flag) | ||
36 | __set_close_on_exec(fd, fdt); | ||
37 | else | ||
38 | __clear_close_on_exec(fd, fdt); | ||
39 | spin_unlock(&files->file_lock); | ||
40 | } | ||
41 | |||
42 | static bool get_close_on_exec(unsigned int fd) | ||
43 | { | ||
44 | struct files_struct *files = current->files; | ||
45 | struct fdtable *fdt; | ||
46 | bool res; | ||
47 | rcu_read_lock(); | ||
48 | fdt = files_fdtable(files); | ||
49 | res = close_on_exec(fd, fdt); | ||
50 | rcu_read_unlock(); | ||
51 | return res; | ||
52 | } | ||
53 | |||
54 | SYSCALL_DEFINE3(dup3, unsigned int, oldfd, unsigned int, newfd, int, flags) | ||
55 | { | ||
56 | int err = -EBADF; | ||
57 | struct file * file, *tofree; | ||
58 | struct files_struct * files = current->files; | ||
59 | struct fdtable *fdt; | ||
60 | |||
61 | if ((flags & ~O_CLOEXEC) != 0) | ||
62 | return -EINVAL; | ||
63 | |||
64 | if (unlikely(oldfd == newfd)) | ||
65 | return -EINVAL; | ||
66 | |||
67 | spin_lock(&files->file_lock); | ||
68 | err = expand_files(files, newfd); | ||
69 | file = fcheck(oldfd); | ||
70 | if (unlikely(!file)) | ||
71 | goto Ebadf; | ||
72 | if (unlikely(err < 0)) { | ||
73 | if (err == -EMFILE) | ||
74 | goto Ebadf; | ||
75 | goto out_unlock; | ||
76 | } | ||
77 | /* | ||
78 | * We need to detect attempts to do dup2() over allocated but still | ||
79 | * not finished descriptor. NB: OpenBSD avoids that at the price of | ||
80 | * extra work in their equivalent of fget() - they insert struct | ||
81 | * file immediately after grabbing descriptor, mark it larval if | ||
82 | * more work (e.g. actual opening) is needed and make sure that | ||
83 | * fget() treats larval files as absent. Potentially interesting, | ||
84 | * but while extra work in fget() is trivial, locking implications | ||
85 | * and amount of surgery on open()-related paths in VFS are not. | ||
86 | * FreeBSD fails with -EBADF in the same situation, NetBSD "solution" | ||
87 | * deadlocks in rather amusing ways, AFAICS. All of that is out of | ||
88 | * scope of POSIX or SUS, since neither considers shared descriptor | ||
89 | * tables and this condition does not arise without those. | ||
90 | */ | ||
91 | err = -EBUSY; | ||
92 | fdt = files_fdtable(files); | ||
93 | tofree = fdt->fd[newfd]; | ||
94 | if (!tofree && fd_is_open(newfd, fdt)) | ||
95 | goto out_unlock; | ||
96 | get_file(file); | ||
97 | rcu_assign_pointer(fdt->fd[newfd], file); | ||
98 | __set_open_fd(newfd, fdt); | ||
99 | if (flags & O_CLOEXEC) | ||
100 | __set_close_on_exec(newfd, fdt); | ||
101 | else | ||
102 | __clear_close_on_exec(newfd, fdt); | ||
103 | spin_unlock(&files->file_lock); | ||
104 | |||
105 | if (tofree) | ||
106 | filp_close(tofree, files); | ||
107 | |||
108 | return newfd; | ||
109 | |||
110 | Ebadf: | ||
111 | err = -EBADF; | ||
112 | out_unlock: | ||
113 | spin_unlock(&files->file_lock); | ||
114 | return err; | ||
115 | } | ||
116 | |||
117 | SYSCALL_DEFINE2(dup2, unsigned int, oldfd, unsigned int, newfd) | ||
118 | { | ||
119 | if (unlikely(newfd == oldfd)) { /* corner case */ | ||
120 | struct files_struct *files = current->files; | ||
121 | int retval = oldfd; | ||
122 | |||
123 | rcu_read_lock(); | ||
124 | if (!fcheck_files(files, oldfd)) | ||
125 | retval = -EBADF; | ||
126 | rcu_read_unlock(); | ||
127 | return retval; | ||
128 | } | ||
129 | return sys_dup3(oldfd, newfd, 0); | ||
130 | } | ||
131 | |||
132 | SYSCALL_DEFINE1(dup, unsigned int, fildes) | ||
133 | { | ||
134 | int ret = -EBADF; | ||
135 | struct file *file = fget_raw(fildes); | ||
136 | |||
137 | if (file) { | ||
138 | ret = get_unused_fd(); | ||
139 | if (ret >= 0) | ||
140 | fd_install(ret, file); | ||
141 | else | ||
142 | fput(file); | ||
143 | } | ||
144 | return ret; | ||
145 | } | ||
146 | |||
147 | #define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT | O_NOATIME) | 29 | #define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT | O_NOATIME) |
148 | 30 | ||
149 | static int setfl(int fd, struct file * filp, unsigned long arg) | 31 | static int setfl(int fd, struct file * filp, unsigned long arg) |
@@ -267,7 +149,7 @@ pid_t f_getown(struct file *filp) | |||
267 | 149 | ||
268 | static int f_setown_ex(struct file *filp, unsigned long arg) | 150 | static int f_setown_ex(struct file *filp, unsigned long arg) |
269 | { | 151 | { |
270 | struct f_owner_ex * __user owner_p = (void * __user)arg; | 152 | struct f_owner_ex __user *owner_p = (void __user *)arg; |
271 | struct f_owner_ex owner; | 153 | struct f_owner_ex owner; |
272 | struct pid *pid; | 154 | struct pid *pid; |
273 | int type; | 155 | int type; |
@@ -307,7 +189,7 @@ static int f_setown_ex(struct file *filp, unsigned long arg) | |||
307 | 189 | ||
308 | static int f_getown_ex(struct file *filp, unsigned long arg) | 190 | static int f_getown_ex(struct file *filp, unsigned long arg) |
309 | { | 191 | { |
310 | struct f_owner_ex * __user owner_p = (void * __user)arg; | 192 | struct f_owner_ex __user *owner_p = (void __user *)arg; |
311 | struct f_owner_ex owner; | 193 | struct f_owner_ex owner; |
312 | int ret = 0; | 194 | int ret = 0; |
313 | 195 | ||
@@ -345,7 +227,7 @@ static int f_getown_ex(struct file *filp, unsigned long arg) | |||
345 | static int f_getowner_uids(struct file *filp, unsigned long arg) | 227 | static int f_getowner_uids(struct file *filp, unsigned long arg) |
346 | { | 228 | { |
347 | struct user_namespace *user_ns = current_user_ns(); | 229 | struct user_namespace *user_ns = current_user_ns(); |
348 | uid_t * __user dst = (void * __user)arg; | 230 | uid_t __user *dst = (void __user *)arg; |
349 | uid_t src[2]; | 231 | uid_t src[2]; |
350 | int err; | 232 | int err; |
351 | 233 | ||
@@ -373,14 +255,10 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, | |||
373 | 255 | ||
374 | switch (cmd) { | 256 | switch (cmd) { |
375 | case F_DUPFD: | 257 | case F_DUPFD: |
258 | err = f_dupfd(arg, filp, 0); | ||
259 | break; | ||
376 | case F_DUPFD_CLOEXEC: | 260 | case F_DUPFD_CLOEXEC: |
377 | if (arg >= rlimit(RLIMIT_NOFILE)) | 261 | err = f_dupfd(arg, filp, FD_CLOEXEC); |
378 | break; | ||
379 | err = alloc_fd(arg, cmd == F_DUPFD_CLOEXEC ? O_CLOEXEC : 0); | ||
380 | if (err >= 0) { | ||
381 | get_file(filp); | ||
382 | fd_install(err, filp); | ||
383 | } | ||
384 | break; | 262 | break; |
385 | case F_GETFD: | 263 | case F_GETFD: |
386 | err = get_close_on_exec(fd) ? FD_CLOEXEC : 0; | 264 | err = get_close_on_exec(fd) ? FD_CLOEXEC : 0; |
@@ -470,25 +348,23 @@ static int check_fcntl_cmd(unsigned cmd) | |||
470 | 348 | ||
471 | SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd, unsigned long, arg) | 349 | SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd, unsigned long, arg) |
472 | { | 350 | { |
473 | struct file *filp; | 351 | struct fd f = fdget_raw(fd); |
474 | int fput_needed; | ||
475 | long err = -EBADF; | 352 | long err = -EBADF; |
476 | 353 | ||
477 | filp = fget_raw_light(fd, &fput_needed); | 354 | if (!f.file) |
478 | if (!filp) | ||
479 | goto out; | 355 | goto out; |
480 | 356 | ||
481 | if (unlikely(filp->f_mode & FMODE_PATH)) { | 357 | if (unlikely(f.file->f_mode & FMODE_PATH)) { |
482 | if (!check_fcntl_cmd(cmd)) | 358 | if (!check_fcntl_cmd(cmd)) |
483 | goto out1; | 359 | goto out1; |
484 | } | 360 | } |
485 | 361 | ||
486 | err = security_file_fcntl(filp, cmd, arg); | 362 | err = security_file_fcntl(f.file, cmd, arg); |
487 | if (!err) | 363 | if (!err) |
488 | err = do_fcntl(fd, cmd, arg, filp); | 364 | err = do_fcntl(fd, cmd, arg, f.file); |
489 | 365 | ||
490 | out1: | 366 | out1: |
491 | fput_light(filp, fput_needed); | 367 | fdput(f); |
492 | out: | 368 | out: |
493 | return err; | 369 | return err; |
494 | } | 370 | } |
@@ -497,38 +373,36 @@ out: | |||
497 | SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd, | 373 | SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd, |
498 | unsigned long, arg) | 374 | unsigned long, arg) |
499 | { | 375 | { |
500 | struct file * filp; | 376 | struct fd f = fdget_raw(fd); |
501 | long err = -EBADF; | 377 | long err = -EBADF; |
502 | int fput_needed; | ||
503 | 378 | ||
504 | filp = fget_raw_light(fd, &fput_needed); | 379 | if (!f.file) |
505 | if (!filp) | ||
506 | goto out; | 380 | goto out; |
507 | 381 | ||
508 | if (unlikely(filp->f_mode & FMODE_PATH)) { | 382 | if (unlikely(f.file->f_mode & FMODE_PATH)) { |
509 | if (!check_fcntl_cmd(cmd)) | 383 | if (!check_fcntl_cmd(cmd)) |
510 | goto out1; | 384 | goto out1; |
511 | } | 385 | } |
512 | 386 | ||
513 | err = security_file_fcntl(filp, cmd, arg); | 387 | err = security_file_fcntl(f.file, cmd, arg); |
514 | if (err) | 388 | if (err) |
515 | goto out1; | 389 | goto out1; |
516 | 390 | ||
517 | switch (cmd) { | 391 | switch (cmd) { |
518 | case F_GETLK64: | 392 | case F_GETLK64: |
519 | err = fcntl_getlk64(filp, (struct flock64 __user *) arg); | 393 | err = fcntl_getlk64(f.file, (struct flock64 __user *) arg); |
520 | break; | 394 | break; |
521 | case F_SETLK64: | 395 | case F_SETLK64: |
522 | case F_SETLKW64: | 396 | case F_SETLKW64: |
523 | err = fcntl_setlk64(fd, filp, cmd, | 397 | err = fcntl_setlk64(fd, f.file, cmd, |
524 | (struct flock64 __user *) arg); | 398 | (struct flock64 __user *) arg); |
525 | break; | 399 | break; |
526 | default: | 400 | default: |
527 | err = do_fcntl(fd, cmd, arg, filp); | 401 | err = do_fcntl(fd, cmd, arg, f.file); |
528 | break; | 402 | break; |
529 | } | 403 | } |
530 | out1: | 404 | out1: |
531 | fput_light(filp, fput_needed); | 405 | fdput(f); |
532 | out: | 406 | out: |
533 | return err; | 407 | return err; |
534 | } | 408 | } |