diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2017-04-08 18:10:56 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2017-04-17 12:52:24 -0400 |
commit | 80f0cce6aadebf6caf74d1f8ceb4b008ca72a9e9 (patch) | |
tree | 3ecede861f53ad46e44c0bd72a0353698aeeda33 /fs/fcntl.c | |
parent | 0460b2a28b4b39cdd1ca9a420126353b27ebc954 (diff) |
fcntl: move compat syscalls from compat.c
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/fcntl.c')
-rw-r--r-- | fs/fcntl.c | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/fs/fcntl.c b/fs/fcntl.c index be8fbe289087..8bd81c2e89b2 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/pid_namespace.h> | 23 | #include <linux/pid_namespace.h> |
24 | #include <linux/user_namespace.h> | 24 | #include <linux/user_namespace.h> |
25 | #include <linux/shmem_fs.h> | 25 | #include <linux/shmem_fs.h> |
26 | #include <linux/compat.h> | ||
26 | 27 | ||
27 | #include <asm/poll.h> | 28 | #include <asm/poll.h> |
28 | #include <asm/siginfo.h> | 29 | #include <asm/siginfo.h> |
@@ -420,6 +421,162 @@ out: | |||
420 | } | 421 | } |
421 | #endif | 422 | #endif |
422 | 423 | ||
424 | #ifdef CONFIG_COMPAT | ||
425 | static int get_compat_flock(struct flock *kfl, struct compat_flock __user *ufl) | ||
426 | { | ||
427 | if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) || | ||
428 | __get_user(kfl->l_type, &ufl->l_type) || | ||
429 | __get_user(kfl->l_whence, &ufl->l_whence) || | ||
430 | __get_user(kfl->l_start, &ufl->l_start) || | ||
431 | __get_user(kfl->l_len, &ufl->l_len) || | ||
432 | __get_user(kfl->l_pid, &ufl->l_pid)) | ||
433 | return -EFAULT; | ||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | static int put_compat_flock(struct flock *kfl, struct compat_flock __user *ufl) | ||
438 | { | ||
439 | if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) || | ||
440 | __put_user(kfl->l_type, &ufl->l_type) || | ||
441 | __put_user(kfl->l_whence, &ufl->l_whence) || | ||
442 | __put_user(kfl->l_start, &ufl->l_start) || | ||
443 | __put_user(kfl->l_len, &ufl->l_len) || | ||
444 | __put_user(kfl->l_pid, &ufl->l_pid)) | ||
445 | return -EFAULT; | ||
446 | return 0; | ||
447 | } | ||
448 | |||
449 | #ifndef HAVE_ARCH_GET_COMPAT_FLOCK64 | ||
450 | static int get_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl) | ||
451 | { | ||
452 | if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) || | ||
453 | __get_user(kfl->l_type, &ufl->l_type) || | ||
454 | __get_user(kfl->l_whence, &ufl->l_whence) || | ||
455 | __get_user(kfl->l_start, &ufl->l_start) || | ||
456 | __get_user(kfl->l_len, &ufl->l_len) || | ||
457 | __get_user(kfl->l_pid, &ufl->l_pid)) | ||
458 | return -EFAULT; | ||
459 | return 0; | ||
460 | } | ||
461 | #endif | ||
462 | |||
463 | #ifndef HAVE_ARCH_PUT_COMPAT_FLOCK64 | ||
464 | static int put_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl) | ||
465 | { | ||
466 | if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) || | ||
467 | __put_user(kfl->l_type, &ufl->l_type) || | ||
468 | __put_user(kfl->l_whence, &ufl->l_whence) || | ||
469 | __put_user(kfl->l_start, &ufl->l_start) || | ||
470 | __put_user(kfl->l_len, &ufl->l_len) || | ||
471 | __put_user(kfl->l_pid, &ufl->l_pid)) | ||
472 | return -EFAULT; | ||
473 | return 0; | ||
474 | } | ||
475 | #endif | ||
476 | |||
477 | static unsigned int | ||
478 | convert_fcntl_cmd(unsigned int cmd) | ||
479 | { | ||
480 | switch (cmd) { | ||
481 | case F_GETLK64: | ||
482 | return F_GETLK; | ||
483 | case F_SETLK64: | ||
484 | return F_SETLK; | ||
485 | case F_SETLKW64: | ||
486 | return F_SETLKW; | ||
487 | } | ||
488 | |||
489 | return cmd; | ||
490 | } | ||
491 | |||
492 | COMPAT_SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd, | ||
493 | compat_ulong_t, arg) | ||
494 | { | ||
495 | mm_segment_t old_fs; | ||
496 | struct flock f; | ||
497 | long ret; | ||
498 | unsigned int conv_cmd; | ||
499 | |||
500 | switch (cmd) { | ||
501 | case F_GETLK: | ||
502 | case F_SETLK: | ||
503 | case F_SETLKW: | ||
504 | ret = get_compat_flock(&f, compat_ptr(arg)); | ||
505 | if (ret != 0) | ||
506 | break; | ||
507 | old_fs = get_fs(); | ||
508 | set_fs(KERNEL_DS); | ||
509 | ret = sys_fcntl(fd, cmd, (unsigned long)&f); | ||
510 | set_fs(old_fs); | ||
511 | if (cmd == F_GETLK && ret == 0) { | ||
512 | /* GETLK was successful and we need to return the data... | ||
513 | * but it needs to fit in the compat structure. | ||
514 | * l_start shouldn't be too big, unless the original | ||
515 | * start + end is greater than COMPAT_OFF_T_MAX, in which | ||
516 | * case the app was asking for trouble, so we return | ||
517 | * -EOVERFLOW in that case. | ||
518 | * l_len could be too big, in which case we just truncate it, | ||
519 | * and only allow the app to see that part of the conflicting | ||
520 | * lock that might make sense to it anyway | ||
521 | */ | ||
522 | |||
523 | if (f.l_start > COMPAT_OFF_T_MAX) | ||
524 | ret = -EOVERFLOW; | ||
525 | if (f.l_len > COMPAT_OFF_T_MAX) | ||
526 | f.l_len = COMPAT_OFF_T_MAX; | ||
527 | if (ret == 0) | ||
528 | ret = put_compat_flock(&f, compat_ptr(arg)); | ||
529 | } | ||
530 | break; | ||
531 | |||
532 | case F_GETLK64: | ||
533 | case F_SETLK64: | ||
534 | case F_SETLKW64: | ||
535 | case F_OFD_GETLK: | ||
536 | case F_OFD_SETLK: | ||
537 | case F_OFD_SETLKW: | ||
538 | ret = get_compat_flock64(&f, compat_ptr(arg)); | ||
539 | if (ret != 0) | ||
540 | break; | ||
541 | old_fs = get_fs(); | ||
542 | set_fs(KERNEL_DS); | ||
543 | conv_cmd = convert_fcntl_cmd(cmd); | ||
544 | ret = sys_fcntl(fd, conv_cmd, (unsigned long)&f); | ||
545 | set_fs(old_fs); | ||
546 | if ((conv_cmd == F_GETLK || conv_cmd == F_OFD_GETLK) && ret == 0) { | ||
547 | /* need to return lock information - see above for commentary */ | ||
548 | if (f.l_start > COMPAT_LOFF_T_MAX) | ||
549 | ret = -EOVERFLOW; | ||
550 | if (f.l_len > COMPAT_LOFF_T_MAX) | ||
551 | f.l_len = COMPAT_LOFF_T_MAX; | ||
552 | if (ret == 0) | ||
553 | ret = put_compat_flock64(&f, compat_ptr(arg)); | ||
554 | } | ||
555 | break; | ||
556 | |||
557 | default: | ||
558 | ret = sys_fcntl(fd, cmd, arg); | ||
559 | break; | ||
560 | } | ||
561 | return ret; | ||
562 | } | ||
563 | |||
564 | COMPAT_SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd, | ||
565 | compat_ulong_t, arg) | ||
566 | { | ||
567 | switch (cmd) { | ||
568 | case F_GETLK64: | ||
569 | case F_SETLK64: | ||
570 | case F_SETLKW64: | ||
571 | case F_OFD_GETLK: | ||
572 | case F_OFD_SETLK: | ||
573 | case F_OFD_SETLKW: | ||
574 | return -EINVAL; | ||
575 | } | ||
576 | return compat_sys_fcntl64(fd, cmd, arg); | ||
577 | } | ||
578 | #endif | ||
579 | |||
423 | /* Table to convert sigio signal codes into poll band bitmaps */ | 580 | /* Table to convert sigio signal codes into poll band bitmaps */ |
424 | 581 | ||
425 | static const long band_table[NSIGPOLL] = { | 582 | static const long band_table[NSIGPOLL] = { |