syscall.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  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. #ifdef __ARCH_WANT_SYS_IPC
  11. #include <linux/errno.h>
  12. #include <linux/ipc.h>
  13. #include <linux/shm.h>
  14. #include <linux/uaccess.h>
  15. SYSCALL_DEFINE6(ipc, unsigned int, call, int, first, unsigned long, second,
  16. unsigned long, third, void __user *, ptr, long, fifth)
  17. {
  18. int version, ret;
  19. version = call >> 16; /* hack for backward compatibility */
  20. call &= 0xffff;
  21. switch (call) {
  22. case SEMOP:
  23. return sys_semtimedop(first, (struct sembuf __user *)ptr,
  24. second, NULL);
  25. case SEMTIMEDOP:
  26. return sys_semtimedop(first, (struct sembuf __user *)ptr,
  27. second,
  28. (const struct timespec __user *)fifth);
  29. case SEMGET:
  30. return sys_semget(first, second, third);
  31. case SEMCTL: {
  32. unsigned long arg;
  33. if (!ptr)
  34. return -EINVAL;
  35. if (get_user(arg, (unsigned long __user *) ptr))
  36. return -EFAULT;
  37. return sys_semctl(first, second, third, arg);
  38. }
  39. case MSGSND:
  40. return sys_msgsnd(first, (struct msgbuf __user *) ptr,
  41. second, third);
  42. case MSGRCV:
  43. switch (version) {
  44. case 0: {
  45. struct ipc_kludge tmp;
  46. if (!ptr)
  47. return -EINVAL;
  48. if (copy_from_user(&tmp,
  49. (struct ipc_kludge __user *) ptr,
  50. sizeof(tmp)))
  51. return -EFAULT;
  52. return sys_msgrcv(first, tmp.msgp, second,
  53. tmp.msgtyp, third);
  54. }
  55. default:
  56. return sys_msgrcv(first,
  57. (struct msgbuf __user *) ptr,
  58. second, fifth, third);
  59. }
  60. case MSGGET:
  61. return sys_msgget((key_t) first, second);
  62. case MSGCTL:
  63. return sys_msgctl(first, second, (struct msqid_ds __user *)ptr);
  64. case SHMAT:
  65. switch (version) {
  66. default: {
  67. unsigned long raddr;
  68. ret = do_shmat(first, (char __user *)ptr,
  69. second, &raddr, SHMLBA);
  70. if (ret)
  71. return ret;
  72. return put_user(raddr, (unsigned long __user *) third);
  73. }
  74. case 1:
  75. /*
  76. * This was the entry point for kernel-originating calls
  77. * from iBCS2 in 2.2 days.
  78. */
  79. return -EINVAL;
  80. }
  81. case SHMDT:
  82. return sys_shmdt((char __user *)ptr);
  83. case SHMGET:
  84. return sys_shmget(first, second, third);
  85. case SHMCTL:
  86. return sys_shmctl(first, second,
  87. (struct shmid_ds __user *) ptr);
  88. default:
  89. return -ENOSYS;
  90. }
  91. }
  92. #endif
  93. #ifdef CONFIG_COMPAT
  94. #include <linux/compat.h>
  95. #ifndef COMPAT_SHMLBA
  96. #define COMPAT_SHMLBA SHMLBA
  97. #endif
  98. struct compat_ipc_kludge {
  99. compat_uptr_t msgp;
  100. compat_long_t msgtyp;
  101. };
  102. #ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC
  103. COMPAT_SYSCALL_DEFINE6(ipc, u32, call, int, first, int, second,
  104. u32, third, compat_uptr_t, ptr, u32, fifth)
  105. {
  106. int version;
  107. u32 pad;
  108. version = call >> 16; /* hack for backward compatibility */
  109. call &= 0xffff;
  110. switch (call) {
  111. case SEMOP:
  112. /* struct sembuf is the same on 32 and 64bit :)) */
  113. return sys_semtimedop(first, compat_ptr(ptr), second, NULL);
  114. case SEMTIMEDOP:
  115. return compat_sys_semtimedop(first, compat_ptr(ptr), second,
  116. compat_ptr(fifth));
  117. case SEMGET:
  118. return sys_semget(first, second, third);
  119. case SEMCTL:
  120. if (!ptr)
  121. return -EINVAL;
  122. if (get_user(pad, (u32 __user *) compat_ptr(ptr)))
  123. return -EFAULT;
  124. return compat_sys_semctl(first, second, third, pad);
  125. case MSGSND:
  126. return compat_sys_msgsnd(first, ptr, second, third);
  127. case MSGRCV: {
  128. void __user *uptr = compat_ptr(ptr);
  129. if (first < 0 || second < 0)
  130. return -EINVAL;
  131. if (!version) {
  132. struct compat_ipc_kludge ipck;
  133. if (!uptr)
  134. return -EINVAL;
  135. if (copy_from_user(&ipck, uptr, sizeof(ipck)))
  136. return -EFAULT;
  137. return compat_sys_msgrcv(first, ipck.msgp, second,
  138. ipck.msgtyp, third);
  139. }
  140. return compat_sys_msgrcv(first, ptr, second, fifth, third);
  141. }
  142. case MSGGET:
  143. return sys_msgget(first, second);
  144. case MSGCTL:
  145. return compat_sys_msgctl(first, second, compat_ptr(ptr));
  146. case SHMAT: {
  147. int err;
  148. unsigned long raddr;
  149. if (version == 1)
  150. return -EINVAL;
  151. err = do_shmat(first, compat_ptr(ptr), second, &raddr,
  152. COMPAT_SHMLBA);
  153. if (err < 0)
  154. return err;
  155. return put_user(raddr, (compat_ulong_t *)compat_ptr(third));
  156. }
  157. case SHMDT:
  158. return sys_shmdt(compat_ptr(ptr));
  159. case SHMGET:
  160. return sys_shmget(first, (unsigned)second, third);
  161. case SHMCTL:
  162. return compat_sys_shmctl(first, second, compat_ptr(ptr));
  163. }
  164. return -ENOSYS;
  165. }
  166. #endif
  167. #endif