syscall.c 4.4 KB

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