0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/unistd.h>
0009 #include <linux/syscalls.h>
0010 #include <linux/security.h>
0011 #include <linux/ipc_namespace.h>
0012 #include "util.h"
0013
0014 #ifdef __ARCH_WANT_SYS_IPC
0015 #include <linux/errno.h>
0016 #include <linux/ipc.h>
0017 #include <linux/shm.h>
0018 #include <linux/uaccess.h>
0019
0020 int ksys_ipc(unsigned int call, int first, unsigned long second,
0021 unsigned long third, void __user * ptr, long fifth)
0022 {
0023 int version, ret;
0024
0025 version = call >> 16;
0026 call &= 0xffff;
0027
0028 switch (call) {
0029 case SEMOP:
0030 return ksys_semtimedop(first, (struct sembuf __user *)ptr,
0031 second, NULL);
0032 case SEMTIMEDOP:
0033 if (IS_ENABLED(CONFIG_64BIT))
0034 return ksys_semtimedop(first, ptr, second,
0035 (const struct __kernel_timespec __user *)fifth);
0036 else if (IS_ENABLED(CONFIG_COMPAT_32BIT_TIME))
0037 return compat_ksys_semtimedop(first, ptr, second,
0038 (const struct old_timespec32 __user *)fifth);
0039 else
0040 return -ENOSYS;
0041
0042 case SEMGET:
0043 return ksys_semget(first, second, third);
0044 case SEMCTL: {
0045 unsigned long arg;
0046 if (!ptr)
0047 return -EINVAL;
0048 if (get_user(arg, (unsigned long __user *) ptr))
0049 return -EFAULT;
0050 return ksys_old_semctl(first, second, third, arg);
0051 }
0052
0053 case MSGSND:
0054 return ksys_msgsnd(first, (struct msgbuf __user *) ptr,
0055 second, third);
0056 case MSGRCV:
0057 switch (version) {
0058 case 0: {
0059 struct ipc_kludge tmp;
0060 if (!ptr)
0061 return -EINVAL;
0062
0063 if (copy_from_user(&tmp,
0064 (struct ipc_kludge __user *) ptr,
0065 sizeof(tmp)))
0066 return -EFAULT;
0067 return ksys_msgrcv(first, tmp.msgp, second,
0068 tmp.msgtyp, third);
0069 }
0070 default:
0071 return ksys_msgrcv(first,
0072 (struct msgbuf __user *) ptr,
0073 second, fifth, third);
0074 }
0075 case MSGGET:
0076 return ksys_msgget((key_t) first, second);
0077 case MSGCTL:
0078 return ksys_old_msgctl(first, second,
0079 (struct msqid_ds __user *)ptr);
0080
0081 case SHMAT:
0082 switch (version) {
0083 default: {
0084 unsigned long raddr;
0085 ret = do_shmat(first, (char __user *)ptr,
0086 second, &raddr, SHMLBA);
0087 if (ret)
0088 return ret;
0089 return put_user(raddr, (unsigned long __user *) third);
0090 }
0091 case 1:
0092
0093
0094
0095
0096 return -EINVAL;
0097 }
0098 case SHMDT:
0099 return ksys_shmdt((char __user *)ptr);
0100 case SHMGET:
0101 return ksys_shmget(first, second, third);
0102 case SHMCTL:
0103 return ksys_old_shmctl(first, second,
0104 (struct shmid_ds __user *) ptr);
0105 default:
0106 return -ENOSYS;
0107 }
0108 }
0109
0110 SYSCALL_DEFINE6(ipc, unsigned int, call, int, first, unsigned long, second,
0111 unsigned long, third, void __user *, ptr, long, fifth)
0112 {
0113 return ksys_ipc(call, first, second, third, ptr, fifth);
0114 }
0115 #endif
0116
0117 #ifdef CONFIG_COMPAT
0118 #include <linux/compat.h>
0119
0120 #ifndef COMPAT_SHMLBA
0121 #define COMPAT_SHMLBA SHMLBA
0122 #endif
0123
0124 struct compat_ipc_kludge {
0125 compat_uptr_t msgp;
0126 compat_long_t msgtyp;
0127 };
0128
0129 #ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC
0130 int compat_ksys_ipc(u32 call, int first, int second,
0131 u32 third, compat_uptr_t ptr, u32 fifth)
0132 {
0133 int version;
0134 u32 pad;
0135
0136 version = call >> 16;
0137 call &= 0xffff;
0138
0139 switch (call) {
0140 case SEMOP:
0141
0142 return ksys_semtimedop(first, compat_ptr(ptr), second, NULL);
0143 case SEMTIMEDOP:
0144 if (!IS_ENABLED(CONFIG_COMPAT_32BIT_TIME))
0145 return -ENOSYS;
0146 return compat_ksys_semtimedop(first, compat_ptr(ptr), second,
0147 compat_ptr(fifth));
0148 case SEMGET:
0149 return ksys_semget(first, second, third);
0150 case SEMCTL:
0151 if (!ptr)
0152 return -EINVAL;
0153 if (get_user(pad, (u32 __user *) compat_ptr(ptr)))
0154 return -EFAULT;
0155 return compat_ksys_old_semctl(first, second, third, pad);
0156
0157 case MSGSND:
0158 return compat_ksys_msgsnd(first, ptr, second, third);
0159
0160 case MSGRCV: {
0161 void __user *uptr = compat_ptr(ptr);
0162
0163 if (first < 0 || second < 0)
0164 return -EINVAL;
0165
0166 if (!version) {
0167 struct compat_ipc_kludge ipck;
0168 if (!uptr)
0169 return -EINVAL;
0170 if (copy_from_user(&ipck, uptr, sizeof(ipck)))
0171 return -EFAULT;
0172 return compat_ksys_msgrcv(first, ipck.msgp, second,
0173 ipck.msgtyp, third);
0174 }
0175 return compat_ksys_msgrcv(first, ptr, second, fifth, third);
0176 }
0177 case MSGGET:
0178 return ksys_msgget(first, second);
0179 case MSGCTL:
0180 return compat_ksys_old_msgctl(first, second, compat_ptr(ptr));
0181
0182 case SHMAT: {
0183 int err;
0184 unsigned long raddr;
0185
0186 if (version == 1)
0187 return -EINVAL;
0188 err = do_shmat(first, compat_ptr(ptr), second, &raddr,
0189 COMPAT_SHMLBA);
0190 if (err < 0)
0191 return err;
0192 return put_user(raddr, (compat_ulong_t __user *)compat_ptr(third));
0193 }
0194 case SHMDT:
0195 return ksys_shmdt(compat_ptr(ptr));
0196 case SHMGET:
0197 return ksys_shmget(first, (unsigned int)second, third);
0198 case SHMCTL:
0199 return compat_ksys_old_shmctl(first, second, compat_ptr(ptr));
0200 }
0201
0202 return -ENOSYS;
0203 }
0204
0205 COMPAT_SYSCALL_DEFINE6(ipc, u32, call, int, first, int, second,
0206 u32, third, compat_uptr_t, ptr, u32, fifth)
0207 {
0208 return compat_ksys_ipc(call, first, second, third, ptr, fifth);
0209 }
0210 #endif
0211 #endif