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