summaryrefslogtreecommitdiffstats
path: root/ipc/shm.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-09-14 20:37:26 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2017-09-14 20:37:26 -0400
commitcc73fee0bae2d66594d1fa2df92bbd783aa98e04 (patch)
treed1e7fe7f76cae4cbc941fc3bb43a46d237a9df77 /ipc/shm.c
parente7cdb60fd28b252f1c15a0e50f79a01906124915 (diff)
parentaaed2dd8a31359e5767ee099ecbb078d55be4d29 (diff)
Merge branch 'work.ipc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull ipc compat cleanup and 64-bit time_t from Al Viro: "IPC copyin/copyout sanitizing, including 64bit time_t work from Deepa Dinamani" * 'work.ipc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: utimes: Make utimes y2038 safe ipc: shm: Make shmid_kernel timestamps y2038 safe ipc: sem: Make sem_array timestamps y2038 safe ipc: msg: Make msg_queue timestamps y2038 safe ipc: mqueue: Replace timespec with timespec64 ipc: Make sys_semtimedop() y2038 safe get rid of SYSVIPC_COMPAT on ia64 semtimedop(): move compat to native shmat(2): move compat to native msgrcv(2), msgsnd(2): move compat to native ipc(2): move compat to native ipc: make use of compat ipc_perm helpers semctl(): move compat to native semctl(): separate all layout-dependent copyin/copyout msgctl(): move compat to native msgctl(): split the actual work from copyin/copyout ipc: move compat shmctl to native shmctl: split the work from copyin/copyout
Diffstat (limited to 'ipc/shm.c')
-rw-r--r--ipc/shm.c533
1 files changed, 363 insertions, 170 deletions
diff --git a/ipc/shm.c b/ipc/shm.c
index 8fc97beb5234..1b3adfe3c60e 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -202,7 +202,7 @@ static int __shm_open(struct vm_area_struct *vma)
202 if (IS_ERR(shp)) 202 if (IS_ERR(shp))
203 return PTR_ERR(shp); 203 return PTR_ERR(shp);
204 204
205 shp->shm_atim = get_seconds(); 205 shp->shm_atim = ktime_get_real_seconds();
206 shp->shm_lprid = task_tgid_vnr(current); 206 shp->shm_lprid = task_tgid_vnr(current);
207 shp->shm_nattch++; 207 shp->shm_nattch++;
208 shm_unlock(shp); 208 shm_unlock(shp);
@@ -289,7 +289,7 @@ static void shm_close(struct vm_area_struct *vma)
289 goto done; /* no-op */ 289 goto done; /* no-op */
290 290
291 shp->shm_lprid = task_tgid_vnr(current); 291 shp->shm_lprid = task_tgid_vnr(current);
292 shp->shm_dtim = get_seconds(); 292 shp->shm_dtim = ktime_get_real_seconds();
293 shp->shm_nattch--; 293 shp->shm_nattch--;
294 if (shm_may_destroy(ns, shp)) 294 if (shm_may_destroy(ns, shp))
295 shm_destroy(ns, shp); 295 shm_destroy(ns, shp);
@@ -594,7 +594,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
594 shp->shm_cprid = task_tgid_vnr(current); 594 shp->shm_cprid = task_tgid_vnr(current);
595 shp->shm_lprid = 0; 595 shp->shm_lprid = 0;
596 shp->shm_atim = shp->shm_dtim = 0; 596 shp->shm_atim = shp->shm_dtim = 0;
597 shp->shm_ctim = get_seconds(); 597 shp->shm_ctim = ktime_get_real_seconds();
598 shp->shm_segsz = size; 598 shp->shm_segsz = size;
599 shp->shm_nattch = 0; 599 shp->shm_nattch = 0;
600 shp->shm_file = file; 600 shp->shm_file = file;
@@ -815,23 +815,17 @@ static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss,
815 * NOTE: no locks must be held, the rwsem is taken inside this function. 815 * NOTE: no locks must be held, the rwsem is taken inside this function.
816 */ 816 */
817static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd, 817static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd,
818 struct shmid_ds __user *buf, int version) 818 struct shmid64_ds *shmid64)
819{ 819{
820 struct kern_ipc_perm *ipcp; 820 struct kern_ipc_perm *ipcp;
821 struct shmid64_ds shmid64;
822 struct shmid_kernel *shp; 821 struct shmid_kernel *shp;
823 int err; 822 int err;
824 823
825 if (cmd == IPC_SET) {
826 if (copy_shmid_from_user(&shmid64, buf, version))
827 return -EFAULT;
828 }
829
830 down_write(&shm_ids(ns).rwsem); 824 down_write(&shm_ids(ns).rwsem);
831 rcu_read_lock(); 825 rcu_read_lock();
832 826
833 ipcp = ipcctl_pre_down_nolock(ns, &shm_ids(ns), shmid, cmd, 827 ipcp = ipcctl_pre_down_nolock(ns, &shm_ids(ns), shmid, cmd,
834 &shmid64.shm_perm, 0); 828 &shmid64->shm_perm, 0);
835 if (IS_ERR(ipcp)) { 829 if (IS_ERR(ipcp)) {
836 err = PTR_ERR(ipcp); 830 err = PTR_ERR(ipcp);
837 goto out_unlock1; 831 goto out_unlock1;
@@ -851,10 +845,10 @@ static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd,
851 goto out_up; 845 goto out_up;
852 case IPC_SET: 846 case IPC_SET:
853 ipc_lock_object(&shp->shm_perm); 847 ipc_lock_object(&shp->shm_perm);
854 err = ipc_update_perm(&shmid64.shm_perm, ipcp); 848 err = ipc_update_perm(&shmid64->shm_perm, ipcp);
855 if (err) 849 if (err)
856 goto out_unlock0; 850 goto out_unlock0;
857 shp->shm_ctim = get_seconds(); 851 shp->shm_ctim = ktime_get_real_seconds();
858 break; 852 break;
859 default: 853 default:
860 err = -EINVAL; 854 err = -EINVAL;
@@ -870,125 +864,175 @@ out_up:
870 return err; 864 return err;
871} 865}
872 866
873static int shmctl_nolock(struct ipc_namespace *ns, int shmid, 867static int shmctl_ipc_info(struct ipc_namespace *ns,
874 int cmd, int version, void __user *buf) 868 struct shminfo64 *shminfo)
875{ 869{
876 int err; 870 int err = security_shm_shmctl(NULL, IPC_INFO);
877 struct shmid_kernel *shp; 871 if (!err) {
878 872 memset(shminfo, 0, sizeof(*shminfo));
879 /* preliminary security checks for *_INFO */ 873 shminfo->shmmni = shminfo->shmseg = ns->shm_ctlmni;
880 if (cmd == IPC_INFO || cmd == SHM_INFO) { 874 shminfo->shmmax = ns->shm_ctlmax;
881 err = security_shm_shmctl(NULL, cmd); 875 shminfo->shmall = ns->shm_ctlall;
882 if (err) 876 shminfo->shmmin = SHMMIN;
883 return err;
884 }
885
886 switch (cmd) {
887 case IPC_INFO:
888 {
889 struct shminfo64 shminfo;
890
891 memset(&shminfo, 0, sizeof(shminfo));
892 shminfo.shmmni = shminfo.shmseg = ns->shm_ctlmni;
893 shminfo.shmmax = ns->shm_ctlmax;
894 shminfo.shmall = ns->shm_ctlall;
895
896 shminfo.shmmin = SHMMIN;
897 if (copy_shminfo_to_user(buf, &shminfo, version))
898 return -EFAULT;
899
900 down_read(&shm_ids(ns).rwsem); 877 down_read(&shm_ids(ns).rwsem);
901 err = ipc_get_maxid(&shm_ids(ns)); 878 err = ipc_get_maxid(&shm_ids(ns));
902 up_read(&shm_ids(ns).rwsem); 879 up_read(&shm_ids(ns).rwsem);
903
904 if (err < 0) 880 if (err < 0)
905 err = 0; 881 err = 0;
906 goto out;
907 } 882 }
908 case SHM_INFO: 883 return err;
909 { 884}
910 struct shm_info shm_info;
911 885
912 memset(&shm_info, 0, sizeof(shm_info)); 886static int shmctl_shm_info(struct ipc_namespace *ns,
887 struct shm_info *shm_info)
888{
889 int err = security_shm_shmctl(NULL, SHM_INFO);
890 if (!err) {
891 memset(shm_info, 0, sizeof(*shm_info));
913 down_read(&shm_ids(ns).rwsem); 892 down_read(&shm_ids(ns).rwsem);
914 shm_info.used_ids = shm_ids(ns).in_use; 893 shm_info->used_ids = shm_ids(ns).in_use;
915 shm_get_stat(ns, &shm_info.shm_rss, &shm_info.shm_swp); 894 shm_get_stat(ns, &shm_info->shm_rss, &shm_info->shm_swp);
916 shm_info.shm_tot = ns->shm_tot; 895 shm_info->shm_tot = ns->shm_tot;
917 shm_info.swap_attempts = 0; 896 shm_info->swap_attempts = 0;
918 shm_info.swap_successes = 0; 897 shm_info->swap_successes = 0;
919 err = ipc_get_maxid(&shm_ids(ns)); 898 err = ipc_get_maxid(&shm_ids(ns));
920 up_read(&shm_ids(ns).rwsem); 899 up_read(&shm_ids(ns).rwsem);
921 if (copy_to_user(buf, &shm_info, sizeof(shm_info))) { 900 if (err < 0)
922 err = -EFAULT; 901 err = 0;
923 goto out; 902 }
903 return err;
904}
905
906static int shmctl_stat(struct ipc_namespace *ns, int shmid,
907 int cmd, struct shmid64_ds *tbuf)
908{
909 struct shmid_kernel *shp;
910 int result;
911 int err;
912
913 rcu_read_lock();
914 if (cmd == SHM_STAT) {
915 shp = shm_obtain_object(ns, shmid);
916 if (IS_ERR(shp)) {
917 err = PTR_ERR(shp);
918 goto out_unlock;
919 }
920 result = shp->shm_perm.id;
921 } else {
922 shp = shm_obtain_object_check(ns, shmid);
923 if (IS_ERR(shp)) {
924 err = PTR_ERR(shp);
925 goto out_unlock;
924 } 926 }
927 result = 0;
928 }
925 929
926 err = err < 0 ? 0 : err; 930 err = -EACCES;
927 goto out; 931 if (ipcperms(ns, &shp->shm_perm, S_IRUGO))
932 goto out_unlock;
933
934 err = security_shm_shmctl(shp, cmd);
935 if (err)
936 goto out_unlock;
937
938 memset(tbuf, 0, sizeof(*tbuf));
939 kernel_to_ipc64_perm(&shp->shm_perm, &tbuf->shm_perm);
940 tbuf->shm_segsz = shp->shm_segsz;
941 tbuf->shm_atime = shp->shm_atim;
942 tbuf->shm_dtime = shp->shm_dtim;
943 tbuf->shm_ctime = shp->shm_ctim;
944 tbuf->shm_cpid = shp->shm_cprid;
945 tbuf->shm_lpid = shp->shm_lprid;
946 tbuf->shm_nattch = shp->shm_nattch;
947 rcu_read_unlock();
948 return result;
949
950out_unlock:
951 rcu_read_unlock();
952 return err;
953}
954
955static int shmctl_do_lock(struct ipc_namespace *ns, int shmid, int cmd)
956{
957 struct shmid_kernel *shp;
958 struct file *shm_file;
959 int err;
960
961 rcu_read_lock();
962 shp = shm_obtain_object_check(ns, shmid);
963 if (IS_ERR(shp)) {
964 err = PTR_ERR(shp);
965 goto out_unlock1;
928 } 966 }
929 case SHM_STAT:
930 case IPC_STAT:
931 {
932 struct shmid64_ds tbuf;
933 int result;
934
935 rcu_read_lock();
936 if (cmd == SHM_STAT) {
937 shp = shm_obtain_object(ns, shmid);
938 if (IS_ERR(shp)) {
939 err = PTR_ERR(shp);
940 goto out_unlock;
941 }
942 result = shp->shm_perm.id;
943 } else {
944 shp = shm_obtain_object_check(ns, shmid);
945 if (IS_ERR(shp)) {
946 err = PTR_ERR(shp);
947 goto out_unlock;
948 }
949 result = 0;
950 }
951 967
952 err = -EACCES; 968 audit_ipc_obj(&(shp->shm_perm));
953 if (ipcperms(ns, &shp->shm_perm, S_IRUGO)) 969 err = security_shm_shmctl(shp, cmd);
954 goto out_unlock; 970 if (err)
971 goto out_unlock1;
955 972
956 err = security_shm_shmctl(shp, cmd); 973 ipc_lock_object(&shp->shm_perm);
957 if (err)
958 goto out_unlock;
959 974
960 memset(&tbuf, 0, sizeof(tbuf)); 975 /* check if shm_destroy() is tearing down shp */
961 kernel_to_ipc64_perm(&shp->shm_perm, &tbuf.shm_perm); 976 if (!ipc_valid_object(&shp->shm_perm)) {
962 tbuf.shm_segsz = shp->shm_segsz; 977 err = -EIDRM;
963 tbuf.shm_atime = shp->shm_atim; 978 goto out_unlock0;
964 tbuf.shm_dtime = shp->shm_dtim;
965 tbuf.shm_ctime = shp->shm_ctim;
966 tbuf.shm_cpid = shp->shm_cprid;
967 tbuf.shm_lpid = shp->shm_lprid;
968 tbuf.shm_nattch = shp->shm_nattch;
969 rcu_read_unlock();
970
971 if (copy_shmid_to_user(buf, &tbuf, version))
972 err = -EFAULT;
973 else
974 err = result;
975 goto out;
976 } 979 }
977 default: 980
978 return -EINVAL; 981 if (!ns_capable(ns->user_ns, CAP_IPC_LOCK)) {
982 kuid_t euid = current_euid();
983
984 if (!uid_eq(euid, shp->shm_perm.uid) &&
985 !uid_eq(euid, shp->shm_perm.cuid)) {
986 err = -EPERM;
987 goto out_unlock0;
988 }
989 if (cmd == SHM_LOCK && !rlimit(RLIMIT_MEMLOCK)) {
990 err = -EPERM;
991 goto out_unlock0;
992 }
979 } 993 }
980 994
981out_unlock: 995 shm_file = shp->shm_file;
996 if (is_file_hugepages(shm_file))
997 goto out_unlock0;
998
999 if (cmd == SHM_LOCK) {
1000 struct user_struct *user = current_user();
1001
1002 err = shmem_lock(shm_file, 1, user);
1003 if (!err && !(shp->shm_perm.mode & SHM_LOCKED)) {
1004 shp->shm_perm.mode |= SHM_LOCKED;
1005 shp->mlock_user = user;
1006 }
1007 goto out_unlock0;
1008 }
1009
1010 /* SHM_UNLOCK */
1011 if (!(shp->shm_perm.mode & SHM_LOCKED))
1012 goto out_unlock0;
1013 shmem_lock(shm_file, 0, shp->mlock_user);
1014 shp->shm_perm.mode &= ~SHM_LOCKED;
1015 shp->mlock_user = NULL;
1016 get_file(shm_file);
1017 ipc_unlock_object(&shp->shm_perm);
1018 rcu_read_unlock();
1019 shmem_unlock_mapping(shm_file->f_mapping);
1020
1021 fput(shm_file);
1022 return err;
1023
1024out_unlock0:
1025 ipc_unlock_object(&shp->shm_perm);
1026out_unlock1:
982 rcu_read_unlock(); 1027 rcu_read_unlock();
983out:
984 return err; 1028 return err;
985} 1029}
986 1030
987SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf) 1031SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
988{ 1032{
989 struct shmid_kernel *shp;
990 int err, version; 1033 int err, version;
991 struct ipc_namespace *ns; 1034 struct ipc_namespace *ns;
1035 struct shmid64_ds sem64;
992 1036
993 if (cmd < 0 || shmid < 0) 1037 if (cmd < 0 || shmid < 0)
994 return -EINVAL; 1038 return -EINVAL;
@@ -997,92 +1041,222 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
997 ns = current->nsproxy->ipc_ns; 1041 ns = current->nsproxy->ipc_ns;
998 1042
999 switch (cmd) { 1043 switch (cmd) {
1000 case IPC_INFO: 1044 case IPC_INFO: {
1001 case SHM_INFO: 1045 struct shminfo64 shminfo;
1046 err = shmctl_ipc_info(ns, &shminfo);
1047 if (err < 0)
1048 return err;
1049 if (copy_shminfo_to_user(buf, &shminfo, version))
1050 err = -EFAULT;
1051 return err;
1052 }
1053 case SHM_INFO: {
1054 struct shm_info shm_info;
1055 err = shmctl_shm_info(ns, &shm_info);
1056 if (err < 0)
1057 return err;
1058 if (copy_to_user(buf, &shm_info, sizeof(shm_info)))
1059 err = -EFAULT;
1060 return err;
1061 }
1002 case SHM_STAT: 1062 case SHM_STAT:
1003 case IPC_STAT: 1063 case IPC_STAT: {
1004 return shmctl_nolock(ns, shmid, cmd, version, buf); 1064 err = shmctl_stat(ns, shmid, cmd, &sem64);
1005 case IPC_RMID: 1065 if (err < 0)
1066 return err;
1067 if (copy_shmid_to_user(buf, &sem64, version))
1068 err = -EFAULT;
1069 return err;
1070 }
1006 case IPC_SET: 1071 case IPC_SET:
1007 return shmctl_down(ns, shmid, cmd, buf, version); 1072 if (copy_shmid_from_user(&sem64, buf, version))
1073 return -EFAULT;
1074 /* fallthru */
1075 case IPC_RMID:
1076 return shmctl_down(ns, shmid, cmd, &sem64);
1008 case SHM_LOCK: 1077 case SHM_LOCK:
1009 case SHM_UNLOCK: 1078 case SHM_UNLOCK:
1010 { 1079 return shmctl_do_lock(ns, shmid, cmd);
1011 struct file *shm_file; 1080 default:
1081 return -EINVAL;
1082 }
1083}
1012 1084
1013 rcu_read_lock(); 1085#ifdef CONFIG_COMPAT
1014 shp = shm_obtain_object_check(ns, shmid); 1086
1015 if (IS_ERR(shp)) { 1087struct compat_shmid_ds {
1016 err = PTR_ERR(shp); 1088 struct compat_ipc_perm shm_perm;
1017 goto out_unlock1; 1089 int shm_segsz;
1018 } 1090 compat_time_t shm_atime;
1091 compat_time_t shm_dtime;
1092 compat_time_t shm_ctime;
1093 compat_ipc_pid_t shm_cpid;
1094 compat_ipc_pid_t shm_lpid;
1095 unsigned short shm_nattch;
1096 unsigned short shm_unused;
1097 compat_uptr_t shm_unused2;
1098 compat_uptr_t shm_unused3;
1099};
1019 1100
1020 audit_ipc_obj(&(shp->shm_perm)); 1101struct compat_shminfo64 {
1021 err = security_shm_shmctl(shp, cmd); 1102 compat_ulong_t shmmax;
1022 if (err) 1103 compat_ulong_t shmmin;
1023 goto out_unlock1; 1104 compat_ulong_t shmmni;
1105 compat_ulong_t shmseg;
1106 compat_ulong_t shmall;
1107 compat_ulong_t __unused1;
1108 compat_ulong_t __unused2;
1109 compat_ulong_t __unused3;
1110 compat_ulong_t __unused4;
1111};
1024 1112
1025 ipc_lock_object(&shp->shm_perm); 1113struct compat_shm_info {
1114 compat_int_t used_ids;
1115 compat_ulong_t shm_tot, shm_rss, shm_swp;
1116 compat_ulong_t swap_attempts, swap_successes;
1117};
1026 1118
1027 /* check if shm_destroy() is tearing down shp */ 1119static int copy_compat_shminfo_to_user(void __user *buf, struct shminfo64 *in,
1028 if (!ipc_valid_object(&shp->shm_perm)) { 1120 int version)
1029 err = -EIDRM; 1121{
1030 goto out_unlock0; 1122 if (in->shmmax > INT_MAX)
1031 } 1123 in->shmmax = INT_MAX;
1124 if (version == IPC_64) {
1125 struct compat_shminfo64 info;
1126 memset(&info, 0, sizeof(info));
1127 info.shmmax = in->shmmax;
1128 info.shmmin = in->shmmin;
1129 info.shmmni = in->shmmni;
1130 info.shmseg = in->shmseg;
1131 info.shmall = in->shmall;
1132 return copy_to_user(buf, &info, sizeof(info));
1133 } else {
1134 struct shminfo info;
1135 memset(&info, 0, sizeof(info));
1136 info.shmmax = in->shmmax;
1137 info.shmmin = in->shmmin;
1138 info.shmmni = in->shmmni;
1139 info.shmseg = in->shmseg;
1140 info.shmall = in->shmall;
1141 return copy_to_user(buf, &info, sizeof(info));
1142 }
1143}
1032 1144
1033 if (!ns_capable(ns->user_ns, CAP_IPC_LOCK)) { 1145static int put_compat_shm_info(struct shm_info *ip,
1034 kuid_t euid = current_euid(); 1146 struct compat_shm_info __user *uip)
1035 1147{
1036 if (!uid_eq(euid, shp->shm_perm.uid) && 1148 struct compat_shm_info info;
1037 !uid_eq(euid, shp->shm_perm.cuid)) { 1149
1038 err = -EPERM; 1150 memset(&info, 0, sizeof(info));
1039 goto out_unlock0; 1151 info.used_ids = ip->used_ids;
1040 } 1152 info.shm_tot = ip->shm_tot;
1041 if (cmd == SHM_LOCK && !rlimit(RLIMIT_MEMLOCK)) { 1153 info.shm_rss = ip->shm_rss;
1042 err = -EPERM; 1154 info.shm_swp = ip->shm_swp;
1043 goto out_unlock0; 1155 info.swap_attempts = ip->swap_attempts;
1044 } 1156 info.swap_successes = ip->swap_successes;
1045 } 1157 return copy_to_user(up, &info, sizeof(info));
1158}
1046 1159
1047 shm_file = shp->shm_file; 1160static int copy_compat_shmid_to_user(void __user *buf, struct shmid64_ds *in,
1048 if (is_file_hugepages(shm_file)) 1161 int version)
1049 goto out_unlock0; 1162{
1163 if (version == IPC_64) {
1164 struct compat_shmid64_ds v;
1165 memset(&v, 0, sizeof(v));
1166 to_compat_ipc64_perm(&v.shm_perm, &in->shm_perm);
1167 v.shm_atime = in->shm_atime;
1168 v.shm_dtime = in->shm_dtime;
1169 v.shm_ctime = in->shm_ctime;
1170 v.shm_segsz = in->shm_segsz;
1171 v.shm_nattch = in->shm_nattch;
1172 v.shm_cpid = in->shm_cpid;
1173 v.shm_lpid = in->shm_lpid;
1174 return copy_to_user(buf, &v, sizeof(v));
1175 } else {
1176 struct compat_shmid_ds v;
1177 memset(&v, 0, sizeof(v));
1178 to_compat_ipc_perm(&v.shm_perm, &in->shm_perm);
1179 v.shm_perm.key = in->shm_perm.key;
1180 v.shm_atime = in->shm_atime;
1181 v.shm_dtime = in->shm_dtime;
1182 v.shm_ctime = in->shm_ctime;
1183 v.shm_segsz = in->shm_segsz;
1184 v.shm_nattch = in->shm_nattch;
1185 v.shm_cpid = in->shm_cpid;
1186 v.shm_lpid = in->shm_lpid;
1187 return copy_to_user(buf, &v, sizeof(v));
1188 }
1189}
1050 1190
1051 if (cmd == SHM_LOCK) { 1191static int copy_compat_shmid_from_user(struct shmid64_ds *out, void __user *buf,
1052 struct user_struct *user = current_user(); 1192 int version)
1193{
1194 memset(out, 0, sizeof(*out));
1195 if (version == IPC_64) {
1196 struct compat_shmid64_ds *p = buf;
1197 return get_compat_ipc64_perm(&out->shm_perm, &p->shm_perm);
1198 } else {
1199 struct compat_shmid_ds *p = buf;
1200 return get_compat_ipc_perm(&out->shm_perm, &p->shm_perm);
1201 }
1202}
1053 1203
1054 err = shmem_lock(shm_file, 1, user); 1204COMPAT_SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, void __user *, uptr)
1055 if (!err && !(shp->shm_perm.mode & SHM_LOCKED)) { 1205{
1056 shp->shm_perm.mode |= SHM_LOCKED; 1206 struct ipc_namespace *ns;
1057 shp->mlock_user = user; 1207 struct shmid64_ds sem64;
1058 } 1208 int version = compat_ipc_parse_version(&cmd);
1059 goto out_unlock0; 1209 int err;
1060 }
1061 1210
1062 /* SHM_UNLOCK */ 1211 ns = current->nsproxy->ipc_ns;
1063 if (!(shp->shm_perm.mode & SHM_LOCKED)) 1212
1064 goto out_unlock0; 1213 if (cmd < 0 || shmid < 0)
1065 shmem_lock(shm_file, 0, shp->mlock_user); 1214 return -EINVAL;
1066 shp->shm_perm.mode &= ~SHM_LOCKED;
1067 shp->mlock_user = NULL;
1068 get_file(shm_file);
1069 ipc_unlock_object(&shp->shm_perm);
1070 rcu_read_unlock();
1071 shmem_unlock_mapping(shm_file->f_mapping);
1072 1215
1073 fput(shm_file); 1216 switch (cmd) {
1217 case IPC_INFO: {
1218 struct shminfo64 shminfo;
1219 err = shmctl_ipc_info(ns, &shminfo);
1220 if (err < 0)
1221 return err;
1222 if (copy_compat_shminfo_to_user(uptr, &shminfo, version))
1223 err = -EFAULT;
1224 return err;
1225 }
1226 case SHM_INFO: {
1227 struct shm_info shm_info;
1228 err = shmctl_shm_info(ns, &shm_info);
1229 if (err < 0)
1230 return err;
1231 if (put_compat_shm_info(&shm_info, uptr))
1232 err = -EFAULT;
1074 return err; 1233 return err;
1075 } 1234 }
1235 case IPC_STAT:
1236 case SHM_STAT:
1237 err = shmctl_stat(ns, shmid, cmd, &sem64);
1238 if (err < 0)
1239 return err;
1240 if (copy_compat_shmid_to_user(&sem64, uptr, version))
1241 err = -EFAULT;
1242 return err;
1243
1244 case IPC_SET:
1245 if (copy_compat_shmid_from_user(&sem64, uptr, version))
1246 return -EFAULT;
1247 /* fallthru */
1248 case IPC_RMID:
1249 return shmctl_down(ns, shmid, cmd, &sem64);
1250 case SHM_LOCK:
1251 case SHM_UNLOCK:
1252 return shmctl_do_lock(ns, shmid, cmd);
1253 break;
1076 default: 1254 default:
1077 return -EINVAL; 1255 return -EINVAL;
1078 } 1256 }
1079
1080out_unlock0:
1081 ipc_unlock_object(&shp->shm_perm);
1082out_unlock1:
1083 rcu_read_unlock();
1084 return err; 1257 return err;
1085} 1258}
1259#endif
1086 1260
1087/* 1261/*
1088 * Fix shmaddr, allocate descriptor, map shm, add attach descriptor to lists. 1262 * Fix shmaddr, allocate descriptor, map shm, add attach descriptor to lists.
@@ -1267,6 +1441,25 @@ SYSCALL_DEFINE3(shmat, int, shmid, char __user *, shmaddr, int, shmflg)
1267 return (long)ret; 1441 return (long)ret;
1268} 1442}
1269 1443
1444#ifdef CONFIG_COMPAT
1445
1446#ifndef COMPAT_SHMLBA
1447#define COMPAT_SHMLBA SHMLBA
1448#endif
1449
1450COMPAT_SYSCALL_DEFINE3(shmat, int, shmid, compat_uptr_t, shmaddr, int, shmflg)
1451{
1452 unsigned long ret;
1453 long err;
1454
1455 err = do_shmat(shmid, compat_ptr(shmaddr), shmflg, &ret, COMPAT_SHMLBA);
1456 if (err)
1457 return err;
1458 force_successful_syscall_return();
1459 return (long)ret;
1460}
1461#endif
1462
1270/* 1463/*
1271 * detach and kill segment if marked destroyed. 1464 * detach and kill segment if marked destroyed.
1272 * The work is done in shm_close. 1465 * The work is done in shm_close.
@@ -1397,7 +1590,7 @@ static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
1397 1590
1398 seq_printf(s, 1591 seq_printf(s,
1399 "%10d %10d %4o " SIZE_SPEC " %5u %5u " 1592 "%10d %10d %4o " SIZE_SPEC " %5u %5u "
1400 "%5lu %5u %5u %5u %5u %10lu %10lu %10lu " 1593 "%5lu %5u %5u %5u %5u %10llu %10llu %10llu "
1401 SIZE_SPEC " " SIZE_SPEC "\n", 1594 SIZE_SPEC " " SIZE_SPEC "\n",
1402 shp->shm_perm.key, 1595 shp->shm_perm.key,
1403 shp->shm_perm.id, 1596 shp->shm_perm.id,