Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * sys_ipc() is the old de-multiplexer for the SysV IPC calls.
0004  *
0005  * This is really horribly ugly, and new architectures should just wire up
0006  * the individual syscalls instead.
0007  */
0008 #include <linux/unistd.h>
0009 #include <linux/syscalls.h>
0010 #include <linux/security.h>
0011 #include <linux/ipc_namespace.h>
0012 #include "util.h"
0013 
0014 #ifdef __ARCH_WANT_SYS_IPC
0015 #include <linux/errno.h>
0016 #include <linux/ipc.h>
0017 #include <linux/shm.h>
0018 #include <linux/uaccess.h>
0019 
0020 int ksys_ipc(unsigned int call, int first, unsigned long second,
0021     unsigned long third, void __user * ptr, long fifth)
0022 {
0023     int version, ret;
0024 
0025     version = call >> 16; /* hack for backward compatibility */
0026     call &= 0xffff;
0027 
0028     switch (call) {
0029     case SEMOP:
0030         return ksys_semtimedop(first, (struct sembuf __user *)ptr,
0031                        second, NULL);
0032     case SEMTIMEDOP:
0033         if (IS_ENABLED(CONFIG_64BIT))
0034             return ksys_semtimedop(first, ptr, second,
0035                     (const struct __kernel_timespec __user *)fifth);
0036         else if (IS_ENABLED(CONFIG_COMPAT_32BIT_TIME))
0037             return compat_ksys_semtimedop(first, ptr, second,
0038                     (const struct old_timespec32 __user *)fifth);
0039         else
0040             return -ENOSYS;
0041 
0042     case SEMGET:
0043         return ksys_semget(first, second, third);
0044     case SEMCTL: {
0045         unsigned long arg;
0046         if (!ptr)
0047             return -EINVAL;
0048         if (get_user(arg, (unsigned long __user *) ptr))
0049             return -EFAULT;
0050         return ksys_old_semctl(first, second, third, arg);
0051     }
0052 
0053     case MSGSND:
0054         return ksys_msgsnd(first, (struct msgbuf __user *) ptr,
0055                   second, third);
0056     case MSGRCV:
0057         switch (version) {
0058         case 0: {
0059             struct ipc_kludge tmp;
0060             if (!ptr)
0061                 return -EINVAL;
0062 
0063             if (copy_from_user(&tmp,
0064                        (struct ipc_kludge __user *) ptr,
0065                        sizeof(tmp)))
0066                 return -EFAULT;
0067             return ksys_msgrcv(first, tmp.msgp, second,
0068                        tmp.msgtyp, third);
0069         }
0070         default:
0071             return ksys_msgrcv(first,
0072                        (struct msgbuf __user *) ptr,
0073                        second, fifth, third);
0074         }
0075     case MSGGET:
0076         return ksys_msgget((key_t) first, second);
0077     case MSGCTL:
0078         return ksys_old_msgctl(first, second,
0079                    (struct msqid_ds __user *)ptr);
0080 
0081     case SHMAT:
0082         switch (version) {
0083         default: {
0084             unsigned long raddr;
0085             ret = do_shmat(first, (char __user *)ptr,
0086                        second, &raddr, SHMLBA);
0087             if (ret)
0088                 return ret;
0089             return put_user(raddr, (unsigned long __user *) third);
0090         }
0091         case 1:
0092             /*
0093              * This was the entry point for kernel-originating calls
0094              * from iBCS2 in 2.2 days.
0095              */
0096             return -EINVAL;
0097         }
0098     case SHMDT:
0099         return ksys_shmdt((char __user *)ptr);
0100     case SHMGET:
0101         return ksys_shmget(first, second, third);
0102     case SHMCTL:
0103         return ksys_old_shmctl(first, second,
0104                    (struct shmid_ds __user *) ptr);
0105     default:
0106         return -ENOSYS;
0107     }
0108 }
0109 
0110 SYSCALL_DEFINE6(ipc, unsigned int, call, int, first, unsigned long, second,
0111         unsigned long, third, void __user *, ptr, long, fifth)
0112 {
0113     return ksys_ipc(call, first, second, third, ptr, fifth);
0114 }
0115 #endif
0116 
0117 #ifdef CONFIG_COMPAT
0118 #include <linux/compat.h>
0119 
0120 #ifndef COMPAT_SHMLBA
0121 #define COMPAT_SHMLBA   SHMLBA
0122 #endif
0123 
0124 struct compat_ipc_kludge {
0125     compat_uptr_t msgp;
0126     compat_long_t msgtyp;
0127 };
0128 
0129 #ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC
0130 int compat_ksys_ipc(u32 call, int first, int second,
0131     u32 third, compat_uptr_t ptr, u32 fifth)
0132 {
0133     int version;
0134     u32 pad;
0135 
0136     version = call >> 16; /* hack for backward compatibility */
0137     call &= 0xffff;
0138 
0139     switch (call) {
0140     case SEMOP:
0141         /* struct sembuf is the same on 32 and 64bit :)) */
0142         return ksys_semtimedop(first, compat_ptr(ptr), second, NULL);
0143     case SEMTIMEDOP:
0144         if (!IS_ENABLED(CONFIG_COMPAT_32BIT_TIME))
0145             return -ENOSYS;
0146         return compat_ksys_semtimedop(first, compat_ptr(ptr), second,
0147                         compat_ptr(fifth));
0148     case SEMGET:
0149         return ksys_semget(first, second, third);
0150     case SEMCTL:
0151         if (!ptr)
0152             return -EINVAL;
0153         if (get_user(pad, (u32 __user *) compat_ptr(ptr)))
0154             return -EFAULT;
0155         return compat_ksys_old_semctl(first, second, third, pad);
0156 
0157     case MSGSND:
0158         return compat_ksys_msgsnd(first, ptr, second, third);
0159 
0160     case MSGRCV: {
0161         void __user *uptr = compat_ptr(ptr);
0162 
0163         if (first < 0 || second < 0)
0164             return -EINVAL;
0165 
0166         if (!version) {
0167             struct compat_ipc_kludge ipck;
0168             if (!uptr)
0169                 return -EINVAL;
0170             if (copy_from_user(&ipck, uptr, sizeof(ipck)))
0171                 return -EFAULT;
0172             return compat_ksys_msgrcv(first, ipck.msgp, second,
0173                          ipck.msgtyp, third);
0174         }
0175         return compat_ksys_msgrcv(first, ptr, second, fifth, third);
0176     }
0177     case MSGGET:
0178         return ksys_msgget(first, second);
0179     case MSGCTL:
0180         return compat_ksys_old_msgctl(first, second, compat_ptr(ptr));
0181 
0182     case SHMAT: {
0183         int err;
0184         unsigned long raddr;
0185 
0186         if (version == 1)
0187             return -EINVAL;
0188         err = do_shmat(first, compat_ptr(ptr), second, &raddr,
0189                    COMPAT_SHMLBA);
0190         if (err < 0)
0191             return err;
0192         return put_user(raddr, (compat_ulong_t __user *)compat_ptr(third));
0193     }
0194     case SHMDT:
0195         return ksys_shmdt(compat_ptr(ptr));
0196     case SHMGET:
0197         return ksys_shmget(first, (unsigned int)second, third);
0198     case SHMCTL:
0199         return compat_ksys_old_shmctl(first, second, compat_ptr(ptr));
0200     }
0201 
0202     return -ENOSYS;
0203 }
0204 
0205 COMPAT_SYSCALL_DEFINE6(ipc, u32, call, int, first, int, second,
0206     u32, third, compat_uptr_t, ptr, u32, fifth)
0207 {
0208     return compat_ksys_ipc(call, first, second, third, ptr, fifth);
0209 }
0210 #endif
0211 #endif