Branch data 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 : 0 : if (!IS_ENABLED(CONFIG_COMPAT_32BIT_TIME))
145 : : return -ENOSYS;
146 : 0 : 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
|