Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0
2 : /*
3 : * sys_ipc() is the old de-multiplexer for the SysV IPC calls.
4 : *
5 : * This is really horribly ugly, and new architectures should just wire up
6 : * the individual syscalls instead.
7 : */
8 : #include <linux/unistd.h>
9 : #include <linux/syscalls.h>
10 : #include <linux/security.h>
11 : #include <linux/ipc_namespace.h>
12 : #include "util.h"
13 :
14 : #ifdef __ARCH_WANT_SYS_IPC
15 : #include <linux/errno.h>
16 : #include <linux/ipc.h>
17 : #include <linux/shm.h>
18 : #include <linux/uaccess.h>
19 :
20 : int ksys_ipc(unsigned int call, int first, unsigned long second,
21 : unsigned long third, void __user * ptr, long fifth)
22 : {
23 : int version, ret;
24 :
25 : version = call >> 16; /* hack for backward compatibility */
26 : call &= 0xffff;
27 :
28 : switch (call) {
29 : case SEMOP:
30 : return ksys_semtimedop(first, (struct sembuf __user *)ptr,
31 : second, NULL);
32 : case SEMTIMEDOP:
33 : if (IS_ENABLED(CONFIG_64BIT))
34 : return ksys_semtimedop(first, ptr, second,
35 : (const struct __kernel_timespec __user *)fifth);
36 : else if (IS_ENABLED(CONFIG_COMPAT_32BIT_TIME))
37 : return compat_ksys_semtimedop(first, ptr, second,
38 : (const struct old_timespec32 __user *)fifth);
39 : else
40 : return -ENOSYS;
41 :
42 : case SEMGET:
43 : return ksys_semget(first, second, third);
44 : case SEMCTL: {
45 : unsigned long arg;
46 : if (!ptr)
47 : return -EINVAL;
48 : if (get_user(arg, (unsigned long __user *) ptr))
49 : return -EFAULT;
50 : return ksys_old_semctl(first, second, third, arg);
51 : }
52 :
53 : case MSGSND:
54 : return ksys_msgsnd(first, (struct msgbuf __user *) ptr,
55 : second, third);
56 : case MSGRCV:
57 : switch (version) {
58 : case 0: {
59 : struct ipc_kludge tmp;
60 : if (!ptr)
61 : return -EINVAL;
62 :
63 : if (copy_from_user(&tmp,
64 : (struct ipc_kludge __user *) ptr,
65 : sizeof(tmp)))
66 : return -EFAULT;
67 : return ksys_msgrcv(first, tmp.msgp, second,
68 : tmp.msgtyp, third);
69 : }
70 : default:
71 : return ksys_msgrcv(first,
72 : (struct msgbuf __user *) ptr,
73 : second, fifth, third);
74 : }
75 : case MSGGET:
76 : return ksys_msgget((key_t) first, second);
77 : case MSGCTL:
78 : return ksys_old_msgctl(first, second,
79 : (struct msqid_ds __user *)ptr);
80 :
81 : case SHMAT:
82 : switch (version) {
83 : default: {
84 : unsigned long raddr;
85 : ret = do_shmat(first, (char __user *)ptr,
86 : second, &raddr, SHMLBA);
87 : if (ret)
88 : return ret;
89 : return put_user(raddr, (unsigned long __user *) third);
90 : }
91 : case 1:
92 : /*
93 : * This was the entry point for kernel-originating calls
94 : * from iBCS2 in 2.2 days.
95 : */
96 : return -EINVAL;
97 : }
98 : case SHMDT:
99 : return ksys_shmdt((char __user *)ptr);
100 : case SHMGET:
101 : return ksys_shmget(first, second, third);
102 : case SHMCTL:
103 : return ksys_old_shmctl(first, second,
104 : (struct shmid_ds __user *) ptr);
105 : default:
106 : return -ENOSYS;
107 : }
108 : }
109 :
110 : SYSCALL_DEFINE6(ipc, unsigned int, call, int, first, unsigned long, second,
111 : unsigned long, third, void __user *, ptr, long, fifth)
112 : {
113 : return ksys_ipc(call, first, second, third, ptr, fifth);
114 : }
115 : #endif
116 :
117 : #ifdef CONFIG_COMPAT
118 : #include <linux/compat.h>
119 :
120 : #ifndef COMPAT_SHMLBA
121 : #define COMPAT_SHMLBA SHMLBA
122 : #endif
123 :
124 : struct compat_ipc_kludge {
125 : compat_uptr_t msgp;
126 : compat_long_t msgtyp;
127 : };
128 :
129 : #ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC
130 0 : int compat_ksys_ipc(u32 call, int first, int second,
131 : u32 third, compat_uptr_t ptr, u32 fifth)
132 : {
133 0 : int version;
134 0 : u32 pad;
135 :
136 0 : version = call >> 16; /* hack for backward compatibility */
137 0 : call &= 0xffff;
138 :
139 0 : switch (call) {
140 0 : case SEMOP:
141 : /* struct sembuf is the same on 32 and 64bit :)) */
142 0 : return ksys_semtimedop(first, compat_ptr(ptr), second, NULL);
143 : case SEMTIMEDOP:
144 : if (!IS_ENABLED(CONFIG_COMPAT_32BIT_TIME))
145 : return -ENOSYS;
146 : return compat_ksys_semtimedop(first, compat_ptr(ptr), second,
147 : compat_ptr(fifth));
148 0 : case SEMGET:
149 0 : return ksys_semget(first, second, third);
150 0 : case SEMCTL:
151 0 : if (!ptr)
152 : return -EINVAL;
153 0 : if (get_user(pad, (u32 __user *) compat_ptr(ptr)))
154 : return -EFAULT;
155 0 : return compat_ksys_old_semctl(first, second, third, pad);
156 :
157 0 : case MSGSND:
158 0 : return compat_ksys_msgsnd(first, ptr, second, third);
159 :
160 : case MSGRCV: {
161 0 : void __user *uptr = compat_ptr(ptr);
162 :
163 0 : if (first < 0 || second < 0)
164 : return -EINVAL;
165 :
166 0 : if (!version) {
167 0 : struct compat_ipc_kludge ipck;
168 0 : if (!uptr)
169 : return -EINVAL;
170 0 : if (copy_from_user(&ipck, uptr, sizeof(ipck)))
171 : return -EFAULT;
172 0 : return compat_ksys_msgrcv(first, ipck.msgp, second,
173 : ipck.msgtyp, third);
174 : }
175 0 : return compat_ksys_msgrcv(first, ptr, second, fifth, third);
176 : }
177 0 : case MSGGET:
178 0 : return ksys_msgget(first, second);
179 : case MSGCTL:
180 0 : return compat_ksys_old_msgctl(first, second, compat_ptr(ptr));
181 :
182 0 : case SHMAT: {
183 0 : int err;
184 0 : unsigned long raddr;
185 :
186 0 : if (version == 1)
187 : return -EINVAL;
188 0 : err = do_shmat(first, compat_ptr(ptr), second, &raddr,
189 : COMPAT_SHMLBA);
190 0 : if (err < 0)
191 : return err;
192 0 : return put_user(raddr, (compat_ulong_t __user *)compat_ptr(third));
193 : }
194 : case SHMDT:
195 0 : return ksys_shmdt(compat_ptr(ptr));
196 0 : case SHMGET:
197 0 : return ksys_shmget(first, (unsigned int)second, third);
198 : case SHMCTL:
199 0 : return compat_ksys_old_shmctl(first, second, compat_ptr(ptr));
200 : }
201 :
202 : return -ENOSYS;
203 : }
204 :
205 0 : COMPAT_SYSCALL_DEFINE6(ipc, u32, call, int, first, int, second,
206 : u32, third, compat_uptr_t, ptr, u32, fifth)
207 : {
208 0 : return compat_ksys_ipc(call, first, second, third, ptr, fifth);
209 : }
210 : #endif
211 : #endif
|