diff options
author | Arnd Bergmann <arnd@arndb.de> | 2019-09-05 10:48:38 -0400 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2019-09-07 15:42:25 -0400 |
commit | fb377eb80c80339b580831a3c0fcce34a4c9d1ad (patch) | |
tree | ec74cca6e1cb4ccd8516491822bb76fd9ff94996 | |
parent | 78e05972c5e6c8e9ca4c00ccc6985409da69f904 (diff) |
ipc: fix sparc64 ipc() wrapper
Matt bisected a sparc64 specific issue with semctl, shmctl and msgctl
to a commit from my y2038 series in linux-5.1, as I missed the custom
sys_ipc() wrapper that sparc64 uses in place of the generic version that
I patched.
The problem is that the sys_{sem,shm,msg}ctl() functions in the kernel
now do not allow being called with the IPC_64 flag any more, resulting
in a -EINVAL error when they don't recognize the command.
Instead, the correct way to do this now is to call the internal
ksys_old_{sem,shm,msg}ctl() functions to select the API version.
As we generally move towards these functions anyway, change all of
sparc_ipc() to consistently use those in place of the sys_*() versions,
and move the required ksys_*() declarations into linux/syscalls.h
The IS_ENABLED(CONFIG_SYSVIPC) check is required to avoid link
errors when ipc is disabled.
Reported-by: Matt Turner <mattst88@gmail.com>
Fixes: 275f22148e87 ("ipc: rename old-style shmctl/semctl/msgctl syscalls")
Cc: stable@vger.kernel.org
Tested-by: Matt Turner <mattst88@gmail.com>
Tested-by: Anatoly Pugachev <matorola@gmail.com>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
-rw-r--r-- | arch/sparc/kernel/sys_sparc_64.c | 33 | ||||
-rw-r--r-- | include/linux/syscalls.h | 19 | ||||
-rw-r--r-- | ipc/util.h | 25 |
3 files changed, 39 insertions, 38 deletions
diff --git a/arch/sparc/kernel/sys_sparc_64.c b/arch/sparc/kernel/sys_sparc_64.c index ccc88926bc00..9f41a6f5a032 100644 --- a/arch/sparc/kernel/sys_sparc_64.c +++ b/arch/sparc/kernel/sys_sparc_64.c | |||
@@ -336,25 +336,28 @@ SYSCALL_DEFINE6(sparc_ipc, unsigned int, call, int, first, unsigned long, second | |||
336 | { | 336 | { |
337 | long err; | 337 | long err; |
338 | 338 | ||
339 | if (!IS_ENABLED(CONFIG_SYSVIPC)) | ||
340 | return -ENOSYS; | ||
341 | |||
339 | /* No need for backward compatibility. We can start fresh... */ | 342 | /* No need for backward compatibility. We can start fresh... */ |
340 | if (call <= SEMTIMEDOP) { | 343 | if (call <= SEMTIMEDOP) { |
341 | switch (call) { | 344 | switch (call) { |
342 | case SEMOP: | 345 | case SEMOP: |
343 | err = sys_semtimedop(first, ptr, | 346 | err = ksys_semtimedop(first, ptr, |
344 | (unsigned int)second, NULL); | 347 | (unsigned int)second, NULL); |
345 | goto out; | 348 | goto out; |
346 | case SEMTIMEDOP: | 349 | case SEMTIMEDOP: |
347 | err = sys_semtimedop(first, ptr, (unsigned int)second, | 350 | err = ksys_semtimedop(first, ptr, (unsigned int)second, |
348 | (const struct __kernel_timespec __user *) | 351 | (const struct __kernel_timespec __user *) |
349 | (unsigned long) fifth); | 352 | (unsigned long) fifth); |
350 | goto out; | 353 | goto out; |
351 | case SEMGET: | 354 | case SEMGET: |
352 | err = sys_semget(first, (int)second, (int)third); | 355 | err = ksys_semget(first, (int)second, (int)third); |
353 | goto out; | 356 | goto out; |
354 | case SEMCTL: { | 357 | case SEMCTL: { |
355 | err = sys_semctl(first, second, | 358 | err = ksys_old_semctl(first, second, |
356 | (int)third | IPC_64, | 359 | (int)third | IPC_64, |
357 | (unsigned long) ptr); | 360 | (unsigned long) ptr); |
358 | goto out; | 361 | goto out; |
359 | } | 362 | } |
360 | default: | 363 | default: |
@@ -365,18 +368,18 @@ SYSCALL_DEFINE6(sparc_ipc, unsigned int, call, int, first, unsigned long, second | |||
365 | if (call <= MSGCTL) { | 368 | if (call <= MSGCTL) { |
366 | switch (call) { | 369 | switch (call) { |
367 | case MSGSND: | 370 | case MSGSND: |
368 | err = sys_msgsnd(first, ptr, (size_t)second, | 371 | err = ksys_msgsnd(first, ptr, (size_t)second, |
369 | (int)third); | 372 | (int)third); |
370 | goto out; | 373 | goto out; |
371 | case MSGRCV: | 374 | case MSGRCV: |
372 | err = sys_msgrcv(first, ptr, (size_t)second, fifth, | 375 | err = ksys_msgrcv(first, ptr, (size_t)second, fifth, |
373 | (int)third); | 376 | (int)third); |
374 | goto out; | 377 | goto out; |
375 | case MSGGET: | 378 | case MSGGET: |
376 | err = sys_msgget((key_t)first, (int)second); | 379 | err = ksys_msgget((key_t)first, (int)second); |
377 | goto out; | 380 | goto out; |
378 | case MSGCTL: | 381 | case MSGCTL: |
379 | err = sys_msgctl(first, (int)second | IPC_64, ptr); | 382 | err = ksys_old_msgctl(first, (int)second | IPC_64, ptr); |
380 | goto out; | 383 | goto out; |
381 | default: | 384 | default: |
382 | err = -ENOSYS; | 385 | err = -ENOSYS; |
@@ -396,13 +399,13 @@ SYSCALL_DEFINE6(sparc_ipc, unsigned int, call, int, first, unsigned long, second | |||
396 | goto out; | 399 | goto out; |
397 | } | 400 | } |
398 | case SHMDT: | 401 | case SHMDT: |
399 | err = sys_shmdt(ptr); | 402 | err = ksys_shmdt(ptr); |
400 | goto out; | 403 | goto out; |
401 | case SHMGET: | 404 | case SHMGET: |
402 | err = sys_shmget(first, (size_t)second, (int)third); | 405 | err = ksys_shmget(first, (size_t)second, (int)third); |
403 | goto out; | 406 | goto out; |
404 | case SHMCTL: | 407 | case SHMCTL: |
405 | err = sys_shmctl(first, (int)second | IPC_64, ptr); | 408 | err = ksys_old_shmctl(first, (int)second | IPC_64, ptr); |
406 | goto out; | 409 | goto out; |
407 | default: | 410 | default: |
408 | err = -ENOSYS; | 411 | err = -ENOSYS; |
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 88145da7d140..f7c561c4dcdd 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h | |||
@@ -1402,4 +1402,23 @@ static inline unsigned int ksys_personality(unsigned int personality) | |||
1402 | return old; | 1402 | return old; |
1403 | } | 1403 | } |
1404 | 1404 | ||
1405 | /* for __ARCH_WANT_SYS_IPC */ | ||
1406 | long ksys_semtimedop(int semid, struct sembuf __user *tsops, | ||
1407 | unsigned int nsops, | ||
1408 | const struct __kernel_timespec __user *timeout); | ||
1409 | long ksys_semget(key_t key, int nsems, int semflg); | ||
1410 | long ksys_old_semctl(int semid, int semnum, int cmd, unsigned long arg); | ||
1411 | long ksys_msgget(key_t key, int msgflg); | ||
1412 | long ksys_old_msgctl(int msqid, int cmd, struct msqid_ds __user *buf); | ||
1413 | long ksys_msgrcv(int msqid, struct msgbuf __user *msgp, size_t msgsz, | ||
1414 | long msgtyp, int msgflg); | ||
1415 | long ksys_msgsnd(int msqid, struct msgbuf __user *msgp, size_t msgsz, | ||
1416 | int msgflg); | ||
1417 | long ksys_shmget(key_t key, size_t size, int shmflg); | ||
1418 | long ksys_shmdt(char __user *shmaddr); | ||
1419 | long ksys_old_shmctl(int shmid, int cmd, struct shmid_ds __user *buf); | ||
1420 | long compat_ksys_semtimedop(int semid, struct sembuf __user *tsems, | ||
1421 | unsigned int nsops, | ||
1422 | const struct old_timespec32 __user *timeout); | ||
1423 | |||
1405 | #endif | 1424 | #endif |
diff --git a/ipc/util.h b/ipc/util.h index 0fcf8e719b76..5766c61aed0e 100644 --- a/ipc/util.h +++ b/ipc/util.h | |||
@@ -276,29 +276,7 @@ static inline int compat_ipc_parse_version(int *cmd) | |||
276 | *cmd &= ~IPC_64; | 276 | *cmd &= ~IPC_64; |
277 | return version; | 277 | return version; |
278 | } | 278 | } |
279 | #endif | ||
280 | 279 | ||
281 | /* for __ARCH_WANT_SYS_IPC */ | ||
282 | long ksys_semtimedop(int semid, struct sembuf __user *tsops, | ||
283 | unsigned int nsops, | ||
284 | const struct __kernel_timespec __user *timeout); | ||
285 | long ksys_semget(key_t key, int nsems, int semflg); | ||
286 | long ksys_old_semctl(int semid, int semnum, int cmd, unsigned long arg); | ||
287 | long ksys_msgget(key_t key, int msgflg); | ||
288 | long ksys_old_msgctl(int msqid, int cmd, struct msqid_ds __user *buf); | ||
289 | long ksys_msgrcv(int msqid, struct msgbuf __user *msgp, size_t msgsz, | ||
290 | long msgtyp, int msgflg); | ||
291 | long ksys_msgsnd(int msqid, struct msgbuf __user *msgp, size_t msgsz, | ||
292 | int msgflg); | ||
293 | long ksys_shmget(key_t key, size_t size, int shmflg); | ||
294 | long ksys_shmdt(char __user *shmaddr); | ||
295 | long ksys_old_shmctl(int shmid, int cmd, struct shmid_ds __user *buf); | ||
296 | |||
297 | /* for CONFIG_ARCH_WANT_OLD_COMPAT_IPC */ | ||
298 | long compat_ksys_semtimedop(int semid, struct sembuf __user *tsems, | ||
299 | unsigned int nsops, | ||
300 | const struct old_timespec32 __user *timeout); | ||
301 | #ifdef CONFIG_COMPAT | ||
302 | long compat_ksys_old_semctl(int semid, int semnum, int cmd, int arg); | 280 | long compat_ksys_old_semctl(int semid, int semnum, int cmd, int arg); |
303 | long compat_ksys_old_msgctl(int msqid, int cmd, void __user *uptr); | 281 | long compat_ksys_old_msgctl(int msqid, int cmd, void __user *uptr); |
304 | long compat_ksys_msgrcv(int msqid, compat_uptr_t msgp, compat_ssize_t msgsz, | 282 | long compat_ksys_msgrcv(int msqid, compat_uptr_t msgp, compat_ssize_t msgsz, |
@@ -306,6 +284,7 @@ long compat_ksys_msgrcv(int msqid, compat_uptr_t msgp, compat_ssize_t msgsz, | |||
306 | long compat_ksys_msgsnd(int msqid, compat_uptr_t msgp, | 284 | long compat_ksys_msgsnd(int msqid, compat_uptr_t msgp, |
307 | compat_ssize_t msgsz, int msgflg); | 285 | compat_ssize_t msgsz, int msgflg); |
308 | long compat_ksys_old_shmctl(int shmid, int cmd, void __user *uptr); | 286 | long compat_ksys_old_shmctl(int shmid, int cmd, void __user *uptr); |
309 | #endif /* CONFIG_COMPAT */ | 287 | |
288 | #endif | ||
310 | 289 | ||
311 | #endif | 290 | #endif |