diff options
| author | Al Viro <viro@zeniv.linux.org.uk> | 2017-07-08 22:52:47 -0400 |
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2017-07-15 20:46:42 -0400 |
| commit | 553f770ef71b27ee053bd241bef0998a15f43467 (patch) | |
| tree | b23887b5e7d6ce16c9bc0627f26748e500ad5177 /ipc | |
| parent | 9ba720c18622b250c0abeccbcea1b03531a92277 (diff) | |
ipc: move compat shmctl to native
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'ipc')
| -rw-r--r-- | ipc/compat.c | 233 | ||||
| -rw-r--r-- | ipc/shm.c | 209 | ||||
| -rw-r--r-- | ipc/util.h | 24 |
3 files changed, 231 insertions, 235 deletions
diff --git a/ipc/compat.c b/ipc/compat.c index 9b3c85f8a538..fbfd6fb0a68d 100644 --- a/ipc/compat.c +++ b/ipc/compat.c | |||
| @@ -39,16 +39,6 @@ struct compat_msgbuf { | |||
| 39 | char mtext[1]; | 39 | char mtext[1]; |
| 40 | }; | 40 | }; |
| 41 | 41 | ||
| 42 | struct compat_ipc_perm { | ||
| 43 | key_t key; | ||
| 44 | __compat_uid_t uid; | ||
| 45 | __compat_gid_t gid; | ||
| 46 | __compat_uid_t cuid; | ||
| 47 | __compat_gid_t cgid; | ||
| 48 | compat_mode_t mode; | ||
| 49 | unsigned short seq; | ||
| 50 | }; | ||
| 51 | |||
| 52 | struct compat_semid_ds { | 42 | struct compat_semid_ds { |
| 53 | struct compat_ipc_perm sem_perm; | 43 | struct compat_ipc_perm sem_perm; |
| 54 | compat_time_t sem_otime; | 44 | compat_time_t sem_otime; |
| @@ -76,44 +66,12 @@ struct compat_msqid_ds { | |||
| 76 | compat_ipc_pid_t msg_lrpid; | 66 | compat_ipc_pid_t msg_lrpid; |
| 77 | }; | 67 | }; |
| 78 | 68 | ||
| 79 | struct compat_shmid_ds { | ||
| 80 | struct compat_ipc_perm shm_perm; | ||
| 81 | int shm_segsz; | ||
| 82 | compat_time_t shm_atime; | ||
| 83 | compat_time_t shm_dtime; | ||
| 84 | compat_time_t shm_ctime; | ||
| 85 | compat_ipc_pid_t shm_cpid; | ||
| 86 | compat_ipc_pid_t shm_lpid; | ||
| 87 | unsigned short shm_nattch; | ||
| 88 | unsigned short shm_unused; | ||
| 89 | compat_uptr_t shm_unused2; | ||
| 90 | compat_uptr_t shm_unused3; | ||
| 91 | }; | ||
| 92 | |||
| 93 | struct compat_ipc_kludge { | 69 | struct compat_ipc_kludge { |
| 94 | compat_uptr_t msgp; | 70 | compat_uptr_t msgp; |
| 95 | compat_long_t msgtyp; | 71 | compat_long_t msgtyp; |
| 96 | }; | 72 | }; |
| 97 | 73 | ||
| 98 | struct compat_shminfo64 { | 74 | static inline int __compat_ipc_parse_version(int *cmd) |
| 99 | compat_ulong_t shmmax; | ||
| 100 | compat_ulong_t shmmin; | ||
| 101 | compat_ulong_t shmmni; | ||
| 102 | compat_ulong_t shmseg; | ||
| 103 | compat_ulong_t shmall; | ||
| 104 | compat_ulong_t __unused1; | ||
| 105 | compat_ulong_t __unused2; | ||
| 106 | compat_ulong_t __unused3; | ||
| 107 | compat_ulong_t __unused4; | ||
| 108 | }; | ||
| 109 | |||
| 110 | struct compat_shm_info { | ||
| 111 | compat_int_t used_ids; | ||
| 112 | compat_ulong_t shm_tot, shm_rss, shm_swp; | ||
| 113 | compat_ulong_t swap_attempts, swap_successes; | ||
| 114 | }; | ||
| 115 | |||
| 116 | static inline int compat_ipc_parse_version(int *cmd) | ||
| 117 | { | 75 | { |
| 118 | #ifdef CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION | 76 | #ifdef CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION |
| 119 | int version = *cmd & IPC_64; | 77 | int version = *cmd & IPC_64; |
| @@ -241,7 +199,7 @@ static long do_compat_semctl(int first, int second, int third, u32 pad) | |||
| 241 | int err, err2; | 199 | int err, err2; |
| 242 | struct semid64_ds sem64; | 200 | struct semid64_ds sem64; |
| 243 | struct semid64_ds __user *up64; | 201 | struct semid64_ds __user *up64; |
| 244 | int version = compat_ipc_parse_version(&third); | 202 | int version = __compat_ipc_parse_version(&third); |
| 245 | 203 | ||
| 246 | memset(&sem64, 0, sizeof(sem64)); | 204 | memset(&sem64, 0, sizeof(sem64)); |
| 247 | 205 | ||
| @@ -499,7 +457,7 @@ COMPAT_SYSCALL_DEFINE3(msgctl, int, first, int, second, void __user *, uptr) | |||
| 499 | { | 457 | { |
| 500 | int err, err2; | 458 | int err, err2; |
| 501 | struct msqid64_ds m64; | 459 | struct msqid64_ds m64; |
| 502 | int version = compat_ipc_parse_version(&second); | 460 | int version = __compat_ipc_parse_version(&second); |
| 503 | void __user *p; | 461 | void __user *p; |
| 504 | 462 | ||
| 505 | memset(&m64, 0, sizeof(m64)); | 463 | memset(&m64, 0, sizeof(m64)); |
| @@ -561,191 +519,6 @@ COMPAT_SYSCALL_DEFINE3(shmat, int, shmid, compat_uptr_t, shmaddr, int, shmflg) | |||
| 561 | return (long)ret; | 519 | return (long)ret; |
| 562 | } | 520 | } |
| 563 | 521 | ||
| 564 | static inline int get_compat_shmid64_ds(struct shmid64_ds *sem64, | ||
| 565 | struct compat_shmid64_ds __user *up64) | ||
| 566 | { | ||
| 567 | if (!access_ok(VERIFY_READ, up64, sizeof(*up64))) | ||
| 568 | return -EFAULT; | ||
| 569 | return __get_compat_ipc64_perm(&sem64->shm_perm, &up64->shm_perm); | ||
| 570 | } | ||
| 571 | |||
| 572 | static inline int get_compat_shmid_ds(struct shmid64_ds *s, | ||
| 573 | struct compat_shmid_ds __user *up) | ||
| 574 | { | ||
| 575 | if (!access_ok(VERIFY_READ, up, sizeof(*up))) | ||
| 576 | return -EFAULT; | ||
| 577 | return __get_compat_ipc_perm(&s->shm_perm, &up->shm_perm); | ||
| 578 | } | ||
| 579 | |||
| 580 | static inline int put_compat_shmid64_ds(struct shmid64_ds *sem64, | ||
| 581 | struct compat_shmid64_ds __user *up64) | ||
| 582 | { | ||
| 583 | int err; | ||
| 584 | |||
| 585 | if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) | ||
| 586 | return -EFAULT; | ||
| 587 | err = __put_compat_ipc64_perm(&sem64->shm_perm, &up64->shm_perm); | ||
| 588 | err |= __put_user(sem64->shm_atime, &up64->shm_atime); | ||
| 589 | err |= __put_user(sem64->shm_dtime, &up64->shm_dtime); | ||
| 590 | err |= __put_user(sem64->shm_ctime, &up64->shm_ctime); | ||
| 591 | err |= __put_user(sem64->shm_segsz, &up64->shm_segsz); | ||
| 592 | err |= __put_user(sem64->shm_nattch, &up64->shm_nattch); | ||
| 593 | err |= __put_user(sem64->shm_cpid, &up64->shm_cpid); | ||
| 594 | err |= __put_user(sem64->shm_lpid, &up64->shm_lpid); | ||
| 595 | return err; | ||
| 596 | } | ||
| 597 | |||
| 598 | static inline int put_compat_shmid_ds(struct shmid64_ds *s, | ||
| 599 | struct compat_shmid_ds __user *up) | ||
| 600 | { | ||
| 601 | int err; | ||
| 602 | |||
| 603 | if (!access_ok(VERIFY_WRITE, up, sizeof(*up))) | ||
| 604 | return -EFAULT; | ||
| 605 | err = __put_compat_ipc_perm(&s->shm_perm, &up->shm_perm); | ||
| 606 | err |= __put_user(s->shm_atime, &up->shm_atime); | ||
| 607 | err |= __put_user(s->shm_dtime, &up->shm_dtime); | ||
| 608 | err |= __put_user(s->shm_ctime, &up->shm_ctime); | ||
| 609 | err |= __put_user(s->shm_segsz, &up->shm_segsz); | ||
| 610 | err |= __put_user(s->shm_nattch, &up->shm_nattch); | ||
| 611 | err |= __put_user(s->shm_cpid, &up->shm_cpid); | ||
| 612 | err |= __put_user(s->shm_lpid, &up->shm_lpid); | ||
| 613 | return err; | ||
| 614 | } | ||
| 615 | |||
| 616 | static inline int put_compat_shminfo64(struct shminfo64 *smi, | ||
| 617 | struct compat_shminfo64 __user *up64) | ||
| 618 | { | ||
| 619 | int err; | ||
| 620 | |||
| 621 | if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) | ||
| 622 | return -EFAULT; | ||
| 623 | if (smi->shmmax > INT_MAX) | ||
| 624 | smi->shmmax = INT_MAX; | ||
| 625 | err = __put_user(smi->shmmax, &up64->shmmax); | ||
| 626 | err |= __put_user(smi->shmmin, &up64->shmmin); | ||
| 627 | err |= __put_user(smi->shmmni, &up64->shmmni); | ||
| 628 | err |= __put_user(smi->shmseg, &up64->shmseg); | ||
| 629 | err |= __put_user(smi->shmall, &up64->shmall); | ||
| 630 | return err; | ||
| 631 | } | ||
| 632 | |||
| 633 | static inline int put_compat_shminfo(struct shminfo64 *smi, | ||
| 634 | struct shminfo __user *up) | ||
| 635 | { | ||
| 636 | int err; | ||
| 637 | |||
| 638 | if (!access_ok(VERIFY_WRITE, up, sizeof(*up))) | ||
| 639 | return -EFAULT; | ||
| 640 | if (smi->shmmax > INT_MAX) | ||
| 641 | smi->shmmax = INT_MAX; | ||
| 642 | err = __put_user(smi->shmmax, &up->shmmax); | ||
| 643 | err |= __put_user(smi->shmmin, &up->shmmin); | ||
| 644 | err |= __put_user(smi->shmmni, &up->shmmni); | ||
| 645 | err |= __put_user(smi->shmseg, &up->shmseg); | ||
| 646 | err |= __put_user(smi->shmall, &up->shmall); | ||
| 647 | return err; | ||
| 648 | } | ||
| 649 | |||
| 650 | static inline int put_compat_shm_info(struct shm_info __user *ip, | ||
| 651 | struct compat_shm_info __user *uip) | ||
| 652 | { | ||
| 653 | int err; | ||
| 654 | struct shm_info si; | ||
| 655 | |||
| 656 | if (!access_ok(VERIFY_WRITE, uip, sizeof(*uip)) || | ||
| 657 | copy_from_user(&si, ip, sizeof(si))) | ||
| 658 | return -EFAULT; | ||
| 659 | err = __put_user(si.used_ids, &uip->used_ids); | ||
| 660 | err |= __put_user(si.shm_tot, &uip->shm_tot); | ||
| 661 | err |= __put_user(si.shm_rss, &uip->shm_rss); | ||
| 662 | err |= __put_user(si.shm_swp, &uip->shm_swp); | ||
| 663 | err |= __put_user(si.swap_attempts, &uip->swap_attempts); | ||
| 664 | err |= __put_user(si.swap_successes, &uip->swap_successes); | ||
| 665 | return err; | ||
| 666 | } | ||
| 667 | |||
| 668 | COMPAT_SYSCALL_DEFINE3(shmctl, int, first, int, second, void __user *, uptr) | ||
| 669 | { | ||
| 670 | void __user *p; | ||
| 671 | struct shmid64_ds sem64; | ||
| 672 | struct shminfo64 smi; | ||
| 673 | int err, err2; | ||
| 674 | int version = compat_ipc_parse_version(&second); | ||
| 675 | |||
| 676 | memset(&sem64, 0, sizeof(sem64)); | ||
| 677 | |||
| 678 | switch (second & (~IPC_64)) { | ||
| 679 | case IPC_RMID: | ||
| 680 | case SHM_LOCK: | ||
| 681 | case SHM_UNLOCK: | ||
| 682 | err = sys_shmctl(first, second, uptr); | ||
| 683 | break; | ||
| 684 | |||
| 685 | case IPC_INFO: | ||
| 686 | p = compat_alloc_user_space(sizeof(smi)); | ||
| 687 | err = sys_shmctl(first, second, p); | ||
| 688 | if (err < 0) | ||
| 689 | break; | ||
| 690 | if (copy_from_user(&smi, p, sizeof(smi))) | ||
| 691 | err2 = -EFAULT; | ||
| 692 | else if (version == IPC_64) | ||
| 693 | err2 = put_compat_shminfo64(&smi, uptr); | ||
| 694 | else | ||
| 695 | err2 = put_compat_shminfo(&smi, uptr); | ||
| 696 | if (err2) | ||
| 697 | err = -EFAULT; | ||
| 698 | break; | ||
| 699 | |||
| 700 | |||
| 701 | case IPC_SET: | ||
| 702 | if (version == IPC_64) | ||
| 703 | err = get_compat_shmid64_ds(&sem64, uptr); | ||
| 704 | else | ||
| 705 | err = get_compat_shmid_ds(&sem64, uptr); | ||
| 706 | |||
| 707 | if (err) | ||
| 708 | break; | ||
| 709 | p = compat_alloc_user_space(sizeof(sem64)); | ||
| 710 | if (copy_to_user(p, &sem64, sizeof(sem64))) | ||
| 711 | err = -EFAULT; | ||
| 712 | else | ||
| 713 | err = sys_shmctl(first, second, p); | ||
| 714 | break; | ||
| 715 | |||
| 716 | case IPC_STAT: | ||
| 717 | case SHM_STAT: | ||
| 718 | p = compat_alloc_user_space(sizeof(sem64)); | ||
| 719 | err = sys_shmctl(first, second, p); | ||
| 720 | if (err < 0) | ||
| 721 | break; | ||
| 722 | if (copy_from_user(&sem64, p, sizeof(sem64))) | ||
| 723 | err2 = -EFAULT; | ||
| 724 | else if (version == IPC_64) | ||
| 725 | err2 = put_compat_shmid64_ds(&sem64, uptr); | ||
| 726 | else | ||
| 727 | err2 = put_compat_shmid_ds(&sem64, uptr); | ||
| 728 | if (err2) | ||
| 729 | err = -EFAULT; | ||
| 730 | break; | ||
| 731 | |||
| 732 | case SHM_INFO: | ||
| 733 | p = compat_alloc_user_space(sizeof(struct shm_info)); | ||
| 734 | err = sys_shmctl(first, second, p); | ||
| 735 | if (err < 0) | ||
| 736 | break; | ||
| 737 | err2 = put_compat_shm_info(p, uptr); | ||
| 738 | if (err2) | ||
| 739 | err = -EFAULT; | ||
| 740 | break; | ||
| 741 | |||
| 742 | default: | ||
| 743 | err = -EINVAL; | ||
| 744 | break; | ||
| 745 | } | ||
| 746 | return err; | ||
| 747 | } | ||
| 748 | |||
| 749 | COMPAT_SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsems, | 522 | COMPAT_SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsems, |
| 750 | unsigned, nsops, | 523 | unsigned, nsops, |
| 751 | const struct compat_timespec __user *, timeout) | 524 | const struct compat_timespec __user *, timeout) |
| @@ -1030,7 +1030,7 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf) | |||
| 1030 | { | 1030 | { |
| 1031 | int err, version; | 1031 | int err, version; |
| 1032 | struct ipc_namespace *ns; | 1032 | struct ipc_namespace *ns; |
| 1033 | struct shmid64_ds tbuf; | 1033 | struct shmid64_ds sem64; |
| 1034 | 1034 | ||
| 1035 | if (cmd < 0 || shmid < 0) | 1035 | if (cmd < 0 || shmid < 0) |
| 1036 | return -EINVAL; | 1036 | return -EINVAL; |
| @@ -1059,18 +1059,19 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf) | |||
| 1059 | } | 1059 | } |
| 1060 | case SHM_STAT: | 1060 | case SHM_STAT: |
| 1061 | case IPC_STAT: { | 1061 | case IPC_STAT: { |
| 1062 | err = shmctl_stat(ns, shmid, cmd, &tbuf); | 1062 | err = shmctl_stat(ns, shmid, cmd, &sem64); |
| 1063 | if (err < 0) | 1063 | if (err < 0) |
| 1064 | return err; | 1064 | return err; |
| 1065 | if (copy_shmid_to_user(buf, &tbuf, version)) | 1065 | if (copy_shmid_to_user(buf, &sem64, version)) |
| 1066 | err = -EFAULT; | 1066 | err = -EFAULT; |
| 1067 | return err; | 1067 | return err; |
| 1068 | } | 1068 | } |
| 1069 | case IPC_SET: | 1069 | case IPC_SET: |
| 1070 | if (copy_shmid_from_user(&tbuf, buf, version)) | 1070 | if (copy_shmid_from_user(&sem64, buf, version)) |
| 1071 | return -EFAULT; | 1071 | return -EFAULT; |
| 1072 | /* fallthru */ | ||
| 1072 | case IPC_RMID: | 1073 | case IPC_RMID: |
| 1073 | return shmctl_down(ns, shmid, cmd, &tbuf); | 1074 | return shmctl_down(ns, shmid, cmd, &sem64); |
| 1074 | case SHM_LOCK: | 1075 | case SHM_LOCK: |
| 1075 | case SHM_UNLOCK: | 1076 | case SHM_UNLOCK: |
| 1076 | return shmctl_do_lock(ns, shmid, cmd); | 1077 | return shmctl_do_lock(ns, shmid, cmd); |
| @@ -1079,6 +1080,204 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf) | |||
| 1079 | } | 1080 | } |
| 1080 | } | 1081 | } |
| 1081 | 1082 | ||
| 1083 | #ifdef CONFIG_COMPAT | ||
| 1084 | |||
| 1085 | struct compat_shmid_ds { | ||
| 1086 | struct compat_ipc_perm shm_perm; | ||
| 1087 | int shm_segsz; | ||
| 1088 | compat_time_t shm_atime; | ||
| 1089 | compat_time_t shm_dtime; | ||
| 1090 | compat_time_t shm_ctime; | ||
| 1091 | compat_ipc_pid_t shm_cpid; | ||
| 1092 | compat_ipc_pid_t shm_lpid; | ||
| 1093 | unsigned short shm_nattch; | ||
| 1094 | unsigned short shm_unused; | ||
| 1095 | compat_uptr_t shm_unused2; | ||
| 1096 | compat_uptr_t shm_unused3; | ||
| 1097 | }; | ||
| 1098 | |||
| 1099 | struct compat_shminfo64 { | ||
| 1100 | compat_ulong_t shmmax; | ||
| 1101 | compat_ulong_t shmmin; | ||
| 1102 | compat_ulong_t shmmni; | ||
| 1103 | compat_ulong_t shmseg; | ||
| 1104 | compat_ulong_t shmall; | ||
| 1105 | compat_ulong_t __unused1; | ||
| 1106 | compat_ulong_t __unused2; | ||
| 1107 | compat_ulong_t __unused3; | ||
| 1108 | compat_ulong_t __unused4; | ||
| 1109 | }; | ||
| 1110 | |||
| 1111 | struct compat_shm_info { | ||
| 1112 | compat_int_t used_ids; | ||
| 1113 | compat_ulong_t shm_tot, shm_rss, shm_swp; | ||
| 1114 | compat_ulong_t swap_attempts, swap_successes; | ||
| 1115 | }; | ||
| 1116 | |||
| 1117 | static int copy_compat_shminfo_to_user(void __user *buf, struct shminfo64 *in, | ||
| 1118 | int version) | ||
| 1119 | { | ||
| 1120 | if (in->shmmax > INT_MAX) | ||
| 1121 | in->shmmax = INT_MAX; | ||
| 1122 | if (version == IPC_64) { | ||
| 1123 | struct compat_shminfo64 info; | ||
| 1124 | memset(&info, 0, sizeof(info)); | ||
| 1125 | info.shmmax = in->shmmax; | ||
| 1126 | info.shmmin = in->shmmin; | ||
| 1127 | info.shmmni = in->shmmni; | ||
| 1128 | info.shmseg = in->shmseg; | ||
| 1129 | info.shmall = in->shmall; | ||
| 1130 | return copy_to_user(buf, &info, sizeof(info)); | ||
| 1131 | } else { | ||
| 1132 | struct shminfo info; | ||
| 1133 | memset(&info, 0, sizeof(info)); | ||
| 1134 | info.shmmax = in->shmmax; | ||
| 1135 | info.shmmin = in->shmmin; | ||
| 1136 | info.shmmni = in->shmmni; | ||
| 1137 | info.shmseg = in->shmseg; | ||
| 1138 | info.shmall = in->shmall; | ||
| 1139 | return copy_to_user(buf, &info, sizeof(info)); | ||
| 1140 | } | ||
| 1141 | } | ||
| 1142 | |||
| 1143 | static int put_compat_shm_info(struct shm_info *ip, | ||
| 1144 | struct compat_shm_info __user *uip) | ||
| 1145 | { | ||
| 1146 | struct compat_shm_info info; | ||
| 1147 | |||
| 1148 | memset(&info, 0, sizeof(info)); | ||
| 1149 | info.used_ids = ip->used_ids; | ||
| 1150 | info.shm_tot = ip->shm_tot; | ||
| 1151 | info.shm_rss = ip->shm_rss; | ||
| 1152 | info.shm_swp = ip->shm_swp; | ||
| 1153 | info.swap_attempts = ip->swap_attempts; | ||
| 1154 | info.swap_successes = ip->swap_successes; | ||
| 1155 | return copy_to_user(up, &info, sizeof(info)); | ||
| 1156 | } | ||
| 1157 | |||
| 1158 | static int copy_compat_shmid_to_user(void __user *buf, struct shmid64_ds *in, | ||
| 1159 | int version) | ||
| 1160 | { | ||
| 1161 | if (version == IPC_64) { | ||
| 1162 | struct compat_shmid64_ds v; | ||
| 1163 | memset(&v, 0, sizeof(v)); | ||
| 1164 | v.shm_perm.key = in->shm_perm.key; | ||
| 1165 | v.shm_perm.uid = in->shm_perm.uid; | ||
| 1166 | v.shm_perm.gid = in->shm_perm.gid; | ||
| 1167 | v.shm_perm.cuid = in->shm_perm.cuid; | ||
| 1168 | v.shm_perm.cgid = in->shm_perm.cgid; | ||
| 1169 | v.shm_perm.mode = in->shm_perm.mode; | ||
| 1170 | v.shm_perm.seq = in->shm_perm.seq; | ||
| 1171 | v.shm_atime = in->shm_atime; | ||
| 1172 | v.shm_dtime = in->shm_dtime; | ||
| 1173 | v.shm_ctime = in->shm_ctime; | ||
| 1174 | v.shm_segsz = in->shm_segsz; | ||
| 1175 | v.shm_nattch = in->shm_nattch; | ||
| 1176 | v.shm_cpid = in->shm_cpid; | ||
| 1177 | v.shm_lpid = in->shm_lpid; | ||
| 1178 | return copy_to_user(buf, &v, sizeof(v)); | ||
| 1179 | } else { | ||
| 1180 | struct compat_shmid_ds v; | ||
| 1181 | memset(&v, 0, sizeof(v)); | ||
| 1182 | v.shm_perm.key = in->shm_perm.key; | ||
| 1183 | SET_UID(v.shm_perm.uid, in->shm_perm.uid); | ||
| 1184 | SET_GID(v.shm_perm.gid, in->shm_perm.gid); | ||
| 1185 | SET_UID(v.shm_perm.cuid, in->shm_perm.cuid); | ||
| 1186 | SET_GID(v.shm_perm.cgid, in->shm_perm.cgid); | ||
| 1187 | v.shm_perm.mode = in->shm_perm.mode; | ||
| 1188 | v.shm_perm.seq = in->shm_perm.seq; | ||
| 1189 | v.shm_atime = in->shm_atime; | ||
| 1190 | v.shm_dtime = in->shm_dtime; | ||
| 1191 | v.shm_ctime = in->shm_ctime; | ||
| 1192 | v.shm_segsz = in->shm_segsz; | ||
| 1193 | v.shm_nattch = in->shm_nattch; | ||
| 1194 | v.shm_cpid = in->shm_cpid; | ||
| 1195 | v.shm_lpid = in->shm_lpid; | ||
| 1196 | return copy_to_user(buf, &v, sizeof(v)); | ||
| 1197 | } | ||
| 1198 | } | ||
| 1199 | |||
| 1200 | static int copy_compat_shmid_from_user(struct shmid64_ds *out, void __user *buf, | ||
| 1201 | int version) | ||
| 1202 | { | ||
| 1203 | memset(out, 0, sizeof(*out)); | ||
| 1204 | if (version == IPC_64) { | ||
| 1205 | struct compat_shmid64_ds *p = buf; | ||
| 1206 | struct compat_ipc64_perm v; | ||
| 1207 | if (copy_from_user(&v, &p->shm_perm, sizeof(v))) | ||
| 1208 | return -EFAULT; | ||
| 1209 | out->shm_perm.uid = v.uid; | ||
| 1210 | out->shm_perm.gid = v.gid; | ||
| 1211 | out->shm_perm.mode = v.mode; | ||
| 1212 | } else { | ||
| 1213 | struct compat_shmid_ds *p = buf; | ||
| 1214 | struct compat_ipc_perm v; | ||
| 1215 | if (copy_from_user(&v, &p->shm_perm, sizeof(v))) | ||
| 1216 | return -EFAULT; | ||
| 1217 | out->shm_perm.uid = v.uid; | ||
| 1218 | out->shm_perm.gid = v.gid; | ||
| 1219 | out->shm_perm.mode = v.mode; | ||
| 1220 | } | ||
| 1221 | return 0; | ||
| 1222 | } | ||
| 1223 | |||
| 1224 | COMPAT_SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, void __user *, uptr) | ||
| 1225 | { | ||
| 1226 | struct ipc_namespace *ns; | ||
| 1227 | struct shmid64_ds sem64; | ||
| 1228 | int version = compat_ipc_parse_version(&cmd); | ||
| 1229 | int err; | ||
| 1230 | |||
| 1231 | ns = current->nsproxy->ipc_ns; | ||
| 1232 | |||
| 1233 | if (cmd < 0 || shmid < 0) | ||
| 1234 | return -EINVAL; | ||
| 1235 | |||
| 1236 | switch (cmd) { | ||
| 1237 | case IPC_INFO: { | ||
| 1238 | struct shminfo64 shminfo; | ||
| 1239 | err = shmctl_ipc_info(ns, &shminfo); | ||
| 1240 | if (err < 0) | ||
| 1241 | return err; | ||
| 1242 | if (copy_compat_shminfo_to_user(uptr, &shminfo, version)) | ||
| 1243 | err = -EFAULT; | ||
| 1244 | return err; | ||
| 1245 | } | ||
| 1246 | case SHM_INFO: { | ||
| 1247 | struct shm_info shm_info; | ||
| 1248 | err = shmctl_shm_info(ns, &shm_info); | ||
| 1249 | if (err < 0) | ||
| 1250 | return err; | ||
| 1251 | if (put_compat_shm_info(&shm_info, uptr)) | ||
| 1252 | err = -EFAULT; | ||
| 1253 | return err; | ||
| 1254 | } | ||
| 1255 | case IPC_STAT: | ||
| 1256 | case SHM_STAT: | ||
| 1257 | err = shmctl_stat(ns, shmid, cmd, &sem64); | ||
| 1258 | if (err < 0) | ||
| 1259 | return err; | ||
| 1260 | if (copy_compat_shmid_to_user(&sem64, uptr, version)) | ||
| 1261 | err = -EFAULT; | ||
| 1262 | return err; | ||
| 1263 | |||
| 1264 | case IPC_SET: | ||
| 1265 | if (copy_compat_shmid_from_user(&sem64, uptr, version)) | ||
| 1266 | return -EFAULT; | ||
| 1267 | /* fallthru */ | ||
| 1268 | case IPC_RMID: | ||
| 1269 | return shmctl_down(ns, shmid, cmd, &sem64); | ||
| 1270 | case SHM_LOCK: | ||
| 1271 | case SHM_UNLOCK: | ||
| 1272 | return shmctl_do_lock(ns, shmid, cmd); | ||
| 1273 | break; | ||
| 1274 | default: | ||
| 1275 | return -EINVAL; | ||
| 1276 | } | ||
| 1277 | return err; | ||
| 1278 | } | ||
| 1279 | #endif | ||
| 1280 | |||
| 1082 | /* | 1281 | /* |
| 1083 | * Fix shmaddr, allocate descriptor, map shm, add attach descriptor to lists. | 1282 | * Fix shmaddr, allocate descriptor, map shm, add attach descriptor to lists. |
| 1084 | * | 1283 | * |
diff --git a/ipc/util.h b/ipc/util.h index c692010e6f0a..3a3dfe137bee 100644 --- a/ipc/util.h +++ b/ipc/util.h | |||
| @@ -191,4 +191,28 @@ int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids, | |||
| 191 | const struct ipc_ops *ops, struct ipc_params *params); | 191 | const struct ipc_ops *ops, struct ipc_params *params); |
| 192 | void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids, | 192 | void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids, |
| 193 | void (*free)(struct ipc_namespace *, struct kern_ipc_perm *)); | 193 | void (*free)(struct ipc_namespace *, struct kern_ipc_perm *)); |
| 194 | |||
| 195 | #ifdef CONFIG_COMPAT | ||
| 196 | #include <linux/compat.h> | ||
| 197 | struct compat_ipc_perm { | ||
| 198 | key_t key; | ||
| 199 | __compat_uid_t uid; | ||
| 200 | __compat_gid_t gid; | ||
| 201 | __compat_uid_t cuid; | ||
| 202 | __compat_gid_t cgid; | ||
| 203 | compat_mode_t mode; | ||
| 204 | unsigned short seq; | ||
| 205 | }; | ||
| 206 | |||
| 207 | static inline int compat_ipc_parse_version(int *cmd) | ||
| 208 | { | ||
| 209 | #ifdef CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION | ||
| 210 | int version = *cmd & IPC_64; | ||
| 211 | *cmd &= ~IPC_64; | ||
| 212 | return version; | ||
| 213 | #else | ||
| 214 | return IPC_64; | ||
| 215 | #endif | ||
| 216 | } | ||
| 217 | #endif | ||
| 194 | #endif | 218 | #endif |
