syscall.c 4.3 KB

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