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
  20int ksys_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))
  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 old_timespec32 __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_old_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_old_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_old_shmctl(first, second,
 104                                   (struct shmid_ds __user *) ptr);
 105        default:
 106                return -ENOSYS;
 107        }
 108}
 109
 110SYSCALL_DEFINE6(ipc, unsigned int, call, int, first, unsigned long, second,
 111                unsigned long, third, void __user *, ptr, long, fifth)
 112{
 113        return ksys_ipc(call, first, second, third, ptr, fifth);
 114}
 115#endif
 116
 117#ifdef CONFIG_COMPAT
 118#include <linux/compat.h>
 119
 120#ifndef COMPAT_SHMLBA
 121#define COMPAT_SHMLBA   SHMLBA
 122#endif
 123
 124struct compat_ipc_kludge {
 125        compat_uptr_t msgp;
 126        compat_long_t msgtyp;
 127};
 128
 129#ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC
 130int compat_ksys_ipc(u32 call, int first, int second,
 131        u32 third, compat_uptr_t ptr, u32 fifth)
 132{
 133        int version;
 134        u32 pad;
 135
 136        version = call >> 16; /* hack for backward compatibility */
 137        call &= 0xffff;
 138
 139        switch (call) {
 140        case SEMOP:
 141                /* struct sembuf is the same on 32 and 64bit :)) */
 142                return ksys_semtimedop(first, compat_ptr(ptr), second, NULL);
 143        case SEMTIMEDOP:
 144                if (!IS_ENABLED(CONFIG_COMPAT_32BIT_TIME))
 145                        return -ENOSYS;
 146                return compat_ksys_semtimedop(first, compat_ptr(ptr), second,
 147                                                compat_ptr(fifth));
 148        case SEMGET:
 149                return ksys_semget(first, second, third);
 150        case SEMCTL:
 151                if (!ptr)
 152                        return -EINVAL;
 153                if (get_user(pad, (u32 __user *) compat_ptr(ptr)))
 154                        return -EFAULT;
 155                return compat_ksys_old_semctl(first, second, third, pad);
 156
 157        case MSGSND:
 158                return compat_ksys_msgsnd(first, ptr, second, third);
 159
 160        case MSGRCV: {
 161                void __user *uptr = compat_ptr(ptr);
 162
 163                if (first < 0 || second < 0)
 164                        return -EINVAL;
 165
 166                if (!version) {
 167                        struct compat_ipc_kludge ipck;
 168                        if (!uptr)
 169                                return -EINVAL;
 170                        if (copy_from_user(&ipck, uptr, sizeof(ipck)))
 171                                return -EFAULT;
 172                        return compat_ksys_msgrcv(first, ipck.msgp, second,
 173                                                 ipck.msgtyp, third);
 174                }
 175                return compat_ksys_msgrcv(first, ptr, second, fifth, third);
 176        }
 177        case MSGGET:
 178                return ksys_msgget(first, second);
 179        case MSGCTL:
 180                return compat_ksys_old_msgctl(first, second, compat_ptr(ptr));
 181
 182        case SHMAT: {
 183                int err;
 184                unsigned long raddr;
 185
 186                if (version == 1)
 187                        return -EINVAL;
 188                err = do_shmat(first, compat_ptr(ptr), second, &raddr,
 189                               COMPAT_SHMLBA);
 190                if (err < 0)
 191                        return err;
 192                return put_user(raddr, (compat_ulong_t __user *)compat_ptr(third));
 193        }
 194        case SHMDT:
 195                return ksys_shmdt(compat_ptr(ptr));
 196        case SHMGET:
 197                return ksys_shmget(first, (unsigned int)second, third);
 198        case SHMCTL:
 199                return compat_ksys_old_shmctl(first, second, compat_ptr(ptr));
 200        }
 201
 202        return -ENOSYS;
 203}
 204
 205COMPAT_SYSCALL_DEFINE6(ipc, u32, call, int, first, int, second,
 206        u32, third, compat_uptr_t, ptr, u32, fifth)
 207{
 208        return compat_ksys_ipc(call, first, second, third, ptr, fifth);
 209}
 210#endif
 211#endif
 212