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