xref: /kernel/linux/linux-5.10/ipc/syscall.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * sys_ipc() is the old de-multiplexer for the SysV IPC calls.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * This is really horribly ugly, and new architectures should just wire up
68c2ecf20Sopenharmony_ci * the individual syscalls instead.
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci#include <linux/unistd.h>
98c2ecf20Sopenharmony_ci#include <linux/syscalls.h>
108c2ecf20Sopenharmony_ci#include <linux/security.h>
118c2ecf20Sopenharmony_ci#include <linux/ipc_namespace.h>
128c2ecf20Sopenharmony_ci#include "util.h"
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#ifdef __ARCH_WANT_SYS_IPC
158c2ecf20Sopenharmony_ci#include <linux/errno.h>
168c2ecf20Sopenharmony_ci#include <linux/ipc.h>
178c2ecf20Sopenharmony_ci#include <linux/shm.h>
188c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ciint ksys_ipc(unsigned int call, int first, unsigned long second,
218c2ecf20Sopenharmony_ci	unsigned long third, void __user * ptr, long fifth)
228c2ecf20Sopenharmony_ci{
238c2ecf20Sopenharmony_ci	int version, ret;
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	version = call >> 16; /* hack for backward compatibility */
268c2ecf20Sopenharmony_ci	call &= 0xffff;
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci	switch (call) {
298c2ecf20Sopenharmony_ci	case SEMOP:
308c2ecf20Sopenharmony_ci		return ksys_semtimedop(first, (struct sembuf __user *)ptr,
318c2ecf20Sopenharmony_ci				       second, NULL);
328c2ecf20Sopenharmony_ci	case SEMTIMEDOP:
338c2ecf20Sopenharmony_ci		if (IS_ENABLED(CONFIG_64BIT))
348c2ecf20Sopenharmony_ci			return ksys_semtimedop(first, ptr, second,
358c2ecf20Sopenharmony_ci			        (const struct __kernel_timespec __user *)fifth);
368c2ecf20Sopenharmony_ci		else if (IS_ENABLED(CONFIG_COMPAT_32BIT_TIME))
378c2ecf20Sopenharmony_ci			return compat_ksys_semtimedop(first, ptr, second,
388c2ecf20Sopenharmony_ci			        (const struct old_timespec32 __user *)fifth);
398c2ecf20Sopenharmony_ci		else
408c2ecf20Sopenharmony_ci			return -ENOSYS;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	case SEMGET:
438c2ecf20Sopenharmony_ci		return ksys_semget(first, second, third);
448c2ecf20Sopenharmony_ci	case SEMCTL: {
458c2ecf20Sopenharmony_ci		unsigned long arg;
468c2ecf20Sopenharmony_ci		if (!ptr)
478c2ecf20Sopenharmony_ci			return -EINVAL;
488c2ecf20Sopenharmony_ci		if (get_user(arg, (unsigned long __user *) ptr))
498c2ecf20Sopenharmony_ci			return -EFAULT;
508c2ecf20Sopenharmony_ci		return ksys_old_semctl(first, second, third, arg);
518c2ecf20Sopenharmony_ci	}
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	case MSGSND:
548c2ecf20Sopenharmony_ci		return ksys_msgsnd(first, (struct msgbuf __user *) ptr,
558c2ecf20Sopenharmony_ci				  second, third);
568c2ecf20Sopenharmony_ci	case MSGRCV:
578c2ecf20Sopenharmony_ci		switch (version) {
588c2ecf20Sopenharmony_ci		case 0: {
598c2ecf20Sopenharmony_ci			struct ipc_kludge tmp;
608c2ecf20Sopenharmony_ci			if (!ptr)
618c2ecf20Sopenharmony_ci				return -EINVAL;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci			if (copy_from_user(&tmp,
648c2ecf20Sopenharmony_ci					   (struct ipc_kludge __user *) ptr,
658c2ecf20Sopenharmony_ci					   sizeof(tmp)))
668c2ecf20Sopenharmony_ci				return -EFAULT;
678c2ecf20Sopenharmony_ci			return ksys_msgrcv(first, tmp.msgp, second,
688c2ecf20Sopenharmony_ci					   tmp.msgtyp, third);
698c2ecf20Sopenharmony_ci		}
708c2ecf20Sopenharmony_ci		default:
718c2ecf20Sopenharmony_ci			return ksys_msgrcv(first,
728c2ecf20Sopenharmony_ci					   (struct msgbuf __user *) ptr,
738c2ecf20Sopenharmony_ci					   second, fifth, third);
748c2ecf20Sopenharmony_ci		}
758c2ecf20Sopenharmony_ci	case MSGGET:
768c2ecf20Sopenharmony_ci		return ksys_msgget((key_t) first, second);
778c2ecf20Sopenharmony_ci	case MSGCTL:
788c2ecf20Sopenharmony_ci		return ksys_old_msgctl(first, second,
798c2ecf20Sopenharmony_ci				   (struct msqid_ds __user *)ptr);
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	case SHMAT:
828c2ecf20Sopenharmony_ci		switch (version) {
838c2ecf20Sopenharmony_ci		default: {
848c2ecf20Sopenharmony_ci			unsigned long raddr;
858c2ecf20Sopenharmony_ci			ret = do_shmat(first, (char __user *)ptr,
868c2ecf20Sopenharmony_ci				       second, &raddr, SHMLBA);
878c2ecf20Sopenharmony_ci			if (ret)
888c2ecf20Sopenharmony_ci				return ret;
898c2ecf20Sopenharmony_ci			return put_user(raddr, (unsigned long __user *) third);
908c2ecf20Sopenharmony_ci		}
918c2ecf20Sopenharmony_ci		case 1:
928c2ecf20Sopenharmony_ci			/*
938c2ecf20Sopenharmony_ci			 * This was the entry point for kernel-originating calls
948c2ecf20Sopenharmony_ci			 * from iBCS2 in 2.2 days.
958c2ecf20Sopenharmony_ci			 */
968c2ecf20Sopenharmony_ci			return -EINVAL;
978c2ecf20Sopenharmony_ci		}
988c2ecf20Sopenharmony_ci	case SHMDT:
998c2ecf20Sopenharmony_ci		return ksys_shmdt((char __user *)ptr);
1008c2ecf20Sopenharmony_ci	case SHMGET:
1018c2ecf20Sopenharmony_ci		return ksys_shmget(first, second, third);
1028c2ecf20Sopenharmony_ci	case SHMCTL:
1038c2ecf20Sopenharmony_ci		return ksys_old_shmctl(first, second,
1048c2ecf20Sopenharmony_ci				   (struct shmid_ds __user *) ptr);
1058c2ecf20Sopenharmony_ci	default:
1068c2ecf20Sopenharmony_ci		return -ENOSYS;
1078c2ecf20Sopenharmony_ci	}
1088c2ecf20Sopenharmony_ci}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ciSYSCALL_DEFINE6(ipc, unsigned int, call, int, first, unsigned long, second,
1118c2ecf20Sopenharmony_ci		unsigned long, third, void __user *, ptr, long, fifth)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci	return ksys_ipc(call, first, second, third, ptr, fifth);
1148c2ecf20Sopenharmony_ci}
1158c2ecf20Sopenharmony_ci#endif
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT
1188c2ecf20Sopenharmony_ci#include <linux/compat.h>
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci#ifndef COMPAT_SHMLBA
1218c2ecf20Sopenharmony_ci#define COMPAT_SHMLBA	SHMLBA
1228c2ecf20Sopenharmony_ci#endif
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_cistruct compat_ipc_kludge {
1258c2ecf20Sopenharmony_ci	compat_uptr_t msgp;
1268c2ecf20Sopenharmony_ci	compat_long_t msgtyp;
1278c2ecf20Sopenharmony_ci};
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci#ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC
1308c2ecf20Sopenharmony_ciint compat_ksys_ipc(u32 call, int first, int second,
1318c2ecf20Sopenharmony_ci	u32 third, compat_uptr_t ptr, u32 fifth)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	int version;
1348c2ecf20Sopenharmony_ci	u32 pad;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	version = call >> 16; /* hack for backward compatibility */
1378c2ecf20Sopenharmony_ci	call &= 0xffff;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	switch (call) {
1408c2ecf20Sopenharmony_ci	case SEMOP:
1418c2ecf20Sopenharmony_ci		/* struct sembuf is the same on 32 and 64bit :)) */
1428c2ecf20Sopenharmony_ci		return ksys_semtimedop(first, compat_ptr(ptr), second, NULL);
1438c2ecf20Sopenharmony_ci	case SEMTIMEDOP:
1448c2ecf20Sopenharmony_ci		if (!IS_ENABLED(CONFIG_COMPAT_32BIT_TIME))
1458c2ecf20Sopenharmony_ci			return -ENOSYS;
1468c2ecf20Sopenharmony_ci		return compat_ksys_semtimedop(first, compat_ptr(ptr), second,
1478c2ecf20Sopenharmony_ci						compat_ptr(fifth));
1488c2ecf20Sopenharmony_ci	case SEMGET:
1498c2ecf20Sopenharmony_ci		return ksys_semget(first, second, third);
1508c2ecf20Sopenharmony_ci	case SEMCTL:
1518c2ecf20Sopenharmony_ci		if (!ptr)
1528c2ecf20Sopenharmony_ci			return -EINVAL;
1538c2ecf20Sopenharmony_ci		if (get_user(pad, (u32 __user *) compat_ptr(ptr)))
1548c2ecf20Sopenharmony_ci			return -EFAULT;
1558c2ecf20Sopenharmony_ci		return compat_ksys_old_semctl(first, second, third, pad);
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	case MSGSND:
1588c2ecf20Sopenharmony_ci		return compat_ksys_msgsnd(first, ptr, second, third);
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	case MSGRCV: {
1618c2ecf20Sopenharmony_ci		void __user *uptr = compat_ptr(ptr);
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci		if (first < 0 || second < 0)
1648c2ecf20Sopenharmony_ci			return -EINVAL;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci		if (!version) {
1678c2ecf20Sopenharmony_ci			struct compat_ipc_kludge ipck;
1688c2ecf20Sopenharmony_ci			if (!uptr)
1698c2ecf20Sopenharmony_ci				return -EINVAL;
1708c2ecf20Sopenharmony_ci			if (copy_from_user(&ipck, uptr, sizeof(ipck)))
1718c2ecf20Sopenharmony_ci				return -EFAULT;
1728c2ecf20Sopenharmony_ci			return compat_ksys_msgrcv(first, ipck.msgp, second,
1738c2ecf20Sopenharmony_ci						 ipck.msgtyp, third);
1748c2ecf20Sopenharmony_ci		}
1758c2ecf20Sopenharmony_ci		return compat_ksys_msgrcv(first, ptr, second, fifth, third);
1768c2ecf20Sopenharmony_ci	}
1778c2ecf20Sopenharmony_ci	case MSGGET:
1788c2ecf20Sopenharmony_ci		return ksys_msgget(first, second);
1798c2ecf20Sopenharmony_ci	case MSGCTL:
1808c2ecf20Sopenharmony_ci		return compat_ksys_old_msgctl(first, second, compat_ptr(ptr));
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	case SHMAT: {
1838c2ecf20Sopenharmony_ci		int err;
1848c2ecf20Sopenharmony_ci		unsigned long raddr;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci		if (version == 1)
1878c2ecf20Sopenharmony_ci			return -EINVAL;
1888c2ecf20Sopenharmony_ci		err = do_shmat(first, compat_ptr(ptr), second, &raddr,
1898c2ecf20Sopenharmony_ci			       COMPAT_SHMLBA);
1908c2ecf20Sopenharmony_ci		if (err < 0)
1918c2ecf20Sopenharmony_ci			return err;
1928c2ecf20Sopenharmony_ci		return put_user(raddr, (compat_ulong_t __user *)compat_ptr(third));
1938c2ecf20Sopenharmony_ci	}
1948c2ecf20Sopenharmony_ci	case SHMDT:
1958c2ecf20Sopenharmony_ci		return ksys_shmdt(compat_ptr(ptr));
1968c2ecf20Sopenharmony_ci	case SHMGET:
1978c2ecf20Sopenharmony_ci		return ksys_shmget(first, (unsigned int)second, third);
1988c2ecf20Sopenharmony_ci	case SHMCTL:
1998c2ecf20Sopenharmony_ci		return compat_ksys_old_shmctl(first, second, compat_ptr(ptr));
2008c2ecf20Sopenharmony_ci	}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	return -ENOSYS;
2038c2ecf20Sopenharmony_ci}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ciCOMPAT_SYSCALL_DEFINE6(ipc, u32, call, int, first, int, second,
2068c2ecf20Sopenharmony_ci	u32, third, compat_uptr_t, ptr, u32, fifth)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	return compat_ksys_ipc(call, first, second, third, ptr, fifth);
2098c2ecf20Sopenharmony_ci}
2108c2ecf20Sopenharmony_ci#endif
2118c2ecf20Sopenharmony_ci#endif
212