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