18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  Copyright (C) 2007
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Author: Eric Biederman <ebiederm@xmision.com>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/module.h>
98c2ecf20Sopenharmony_ci#include <linux/ipc.h>
108c2ecf20Sopenharmony_ci#include <linux/nsproxy.h>
118c2ecf20Sopenharmony_ci#include <linux/sysctl.h>
128c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
138c2ecf20Sopenharmony_ci#include <linux/ipc_namespace.h>
148c2ecf20Sopenharmony_ci#include <linux/msg.h>
158c2ecf20Sopenharmony_ci#include "util.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_cistatic void *get_ipc(struct ctl_table *table)
188c2ecf20Sopenharmony_ci{
198c2ecf20Sopenharmony_ci	char *which = table->data;
208c2ecf20Sopenharmony_ci	struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
218c2ecf20Sopenharmony_ci	which = (which - (char *)&init_ipc_ns) + (char *)ipc_ns;
228c2ecf20Sopenharmony_ci	return which;
238c2ecf20Sopenharmony_ci}
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_SYSCTL
268c2ecf20Sopenharmony_cistatic int proc_ipc_dointvec(struct ctl_table *table, int write,
278c2ecf20Sopenharmony_ci		void *buffer, size_t *lenp, loff_t *ppos)
288c2ecf20Sopenharmony_ci{
298c2ecf20Sopenharmony_ci	struct ctl_table ipc_table;
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	memcpy(&ipc_table, table, sizeof(ipc_table));
328c2ecf20Sopenharmony_ci	ipc_table.data = get_ipc(table);
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	return proc_dointvec(&ipc_table, write, buffer, lenp, ppos);
358c2ecf20Sopenharmony_ci}
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic int proc_ipc_dointvec_minmax(struct ctl_table *table, int write,
388c2ecf20Sopenharmony_ci		void *buffer, size_t *lenp, loff_t *ppos)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	struct ctl_table ipc_table;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	memcpy(&ipc_table, table, sizeof(ipc_table));
438c2ecf20Sopenharmony_ci	ipc_table.data = get_ipc(table);
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic int proc_ipc_dointvec_minmax_orphans(struct ctl_table *table, int write,
498c2ecf20Sopenharmony_ci		void *buffer, size_t *lenp, loff_t *ppos)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	struct ipc_namespace *ns = current->nsproxy->ipc_ns;
528c2ecf20Sopenharmony_ci	int err = proc_ipc_dointvec_minmax(table, write, buffer, lenp, ppos);
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	if (err < 0)
558c2ecf20Sopenharmony_ci		return err;
568c2ecf20Sopenharmony_ci	if (ns->shm_rmid_forced)
578c2ecf20Sopenharmony_ci		shm_destroy_orphaned(ns);
588c2ecf20Sopenharmony_ci	return err;
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic int proc_ipc_doulongvec_minmax(struct ctl_table *table, int write,
628c2ecf20Sopenharmony_ci		void *buffer, size_t *lenp, loff_t *ppos)
638c2ecf20Sopenharmony_ci{
648c2ecf20Sopenharmony_ci	struct ctl_table ipc_table;
658c2ecf20Sopenharmony_ci	memcpy(&ipc_table, table, sizeof(ipc_table));
668c2ecf20Sopenharmony_ci	ipc_table.data = get_ipc(table);
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	return proc_doulongvec_minmax(&ipc_table, write, buffer,
698c2ecf20Sopenharmony_ci					lenp, ppos);
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic int proc_ipc_auto_msgmni(struct ctl_table *table, int write,
738c2ecf20Sopenharmony_ci		void *buffer, size_t *lenp, loff_t *ppos)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	struct ctl_table ipc_table;
768c2ecf20Sopenharmony_ci	int dummy = 0;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	memcpy(&ipc_table, table, sizeof(ipc_table));
798c2ecf20Sopenharmony_ci	ipc_table.data = &dummy;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	if (write)
828c2ecf20Sopenharmony_ci		pr_info_once("writing to auto_msgmni has no effect");
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistatic int proc_ipc_sem_dointvec(struct ctl_table *table, int write,
888c2ecf20Sopenharmony_ci	void *buffer, size_t *lenp, loff_t *ppos)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	int ret, semmni;
918c2ecf20Sopenharmony_ci	struct ipc_namespace *ns = current->nsproxy->ipc_ns;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	semmni = ns->sem_ctls[3];
948c2ecf20Sopenharmony_ci	ret = proc_ipc_dointvec(table, write, buffer, lenp, ppos);
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	if (!ret)
978c2ecf20Sopenharmony_ci		ret = sem_check_semmni(current->nsproxy->ipc_ns);
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	/*
1008c2ecf20Sopenharmony_ci	 * Reset the semmni value if an error happens.
1018c2ecf20Sopenharmony_ci	 */
1028c2ecf20Sopenharmony_ci	if (ret)
1038c2ecf20Sopenharmony_ci		ns->sem_ctls[3] = semmni;
1048c2ecf20Sopenharmony_ci	return ret;
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci#else
1088c2ecf20Sopenharmony_ci#define proc_ipc_doulongvec_minmax NULL
1098c2ecf20Sopenharmony_ci#define proc_ipc_dointvec	   NULL
1108c2ecf20Sopenharmony_ci#define proc_ipc_dointvec_minmax   NULL
1118c2ecf20Sopenharmony_ci#define proc_ipc_dointvec_minmax_orphans   NULL
1128c2ecf20Sopenharmony_ci#define proc_ipc_auto_msgmni	   NULL
1138c2ecf20Sopenharmony_ci#define proc_ipc_sem_dointvec	   NULL
1148c2ecf20Sopenharmony_ci#endif
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ciint ipc_mni = IPCMNI;
1178c2ecf20Sopenharmony_ciint ipc_mni_shift = IPCMNI_SHIFT;
1188c2ecf20Sopenharmony_ciint ipc_min_cycle = RADIX_TREE_MAP_SIZE;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistatic struct ctl_table ipc_kern_table[] = {
1218c2ecf20Sopenharmony_ci	{
1228c2ecf20Sopenharmony_ci		.procname	= "shmmax",
1238c2ecf20Sopenharmony_ci		.data		= &init_ipc_ns.shm_ctlmax,
1248c2ecf20Sopenharmony_ci		.maxlen		= sizeof(init_ipc_ns.shm_ctlmax),
1258c2ecf20Sopenharmony_ci		.mode		= 0644,
1268c2ecf20Sopenharmony_ci		.proc_handler	= proc_ipc_doulongvec_minmax,
1278c2ecf20Sopenharmony_ci	},
1288c2ecf20Sopenharmony_ci	{
1298c2ecf20Sopenharmony_ci		.procname	= "shmall",
1308c2ecf20Sopenharmony_ci		.data		= &init_ipc_ns.shm_ctlall,
1318c2ecf20Sopenharmony_ci		.maxlen		= sizeof(init_ipc_ns.shm_ctlall),
1328c2ecf20Sopenharmony_ci		.mode		= 0644,
1338c2ecf20Sopenharmony_ci		.proc_handler	= proc_ipc_doulongvec_minmax,
1348c2ecf20Sopenharmony_ci	},
1358c2ecf20Sopenharmony_ci	{
1368c2ecf20Sopenharmony_ci		.procname	= "shmmni",
1378c2ecf20Sopenharmony_ci		.data		= &init_ipc_ns.shm_ctlmni,
1388c2ecf20Sopenharmony_ci		.maxlen		= sizeof(init_ipc_ns.shm_ctlmni),
1398c2ecf20Sopenharmony_ci		.mode		= 0644,
1408c2ecf20Sopenharmony_ci		.proc_handler	= proc_ipc_dointvec_minmax,
1418c2ecf20Sopenharmony_ci		.extra1		= SYSCTL_ZERO,
1428c2ecf20Sopenharmony_ci		.extra2		= &ipc_mni,
1438c2ecf20Sopenharmony_ci	},
1448c2ecf20Sopenharmony_ci	{
1458c2ecf20Sopenharmony_ci		.procname	= "shm_rmid_forced",
1468c2ecf20Sopenharmony_ci		.data		= &init_ipc_ns.shm_rmid_forced,
1478c2ecf20Sopenharmony_ci		.maxlen		= sizeof(init_ipc_ns.shm_rmid_forced),
1488c2ecf20Sopenharmony_ci		.mode		= 0644,
1498c2ecf20Sopenharmony_ci		.proc_handler	= proc_ipc_dointvec_minmax_orphans,
1508c2ecf20Sopenharmony_ci		.extra1		= SYSCTL_ZERO,
1518c2ecf20Sopenharmony_ci		.extra2		= SYSCTL_ONE,
1528c2ecf20Sopenharmony_ci	},
1538c2ecf20Sopenharmony_ci	{
1548c2ecf20Sopenharmony_ci		.procname	= "msgmax",
1558c2ecf20Sopenharmony_ci		.data		= &init_ipc_ns.msg_ctlmax,
1568c2ecf20Sopenharmony_ci		.maxlen		= sizeof(init_ipc_ns.msg_ctlmax),
1578c2ecf20Sopenharmony_ci		.mode		= 0644,
1588c2ecf20Sopenharmony_ci		.proc_handler	= proc_ipc_dointvec_minmax,
1598c2ecf20Sopenharmony_ci		.extra1		= SYSCTL_ZERO,
1608c2ecf20Sopenharmony_ci		.extra2		= SYSCTL_INT_MAX,
1618c2ecf20Sopenharmony_ci	},
1628c2ecf20Sopenharmony_ci	{
1638c2ecf20Sopenharmony_ci		.procname	= "msgmni",
1648c2ecf20Sopenharmony_ci		.data		= &init_ipc_ns.msg_ctlmni,
1658c2ecf20Sopenharmony_ci		.maxlen		= sizeof(init_ipc_ns.msg_ctlmni),
1668c2ecf20Sopenharmony_ci		.mode		= 0644,
1678c2ecf20Sopenharmony_ci		.proc_handler	= proc_ipc_dointvec_minmax,
1688c2ecf20Sopenharmony_ci		.extra1		= SYSCTL_ZERO,
1698c2ecf20Sopenharmony_ci		.extra2		= &ipc_mni,
1708c2ecf20Sopenharmony_ci	},
1718c2ecf20Sopenharmony_ci	{
1728c2ecf20Sopenharmony_ci		.procname	= "auto_msgmni",
1738c2ecf20Sopenharmony_ci		.data		= NULL,
1748c2ecf20Sopenharmony_ci		.maxlen		= sizeof(int),
1758c2ecf20Sopenharmony_ci		.mode		= 0644,
1768c2ecf20Sopenharmony_ci		.proc_handler	= proc_ipc_auto_msgmni,
1778c2ecf20Sopenharmony_ci		.extra1		= SYSCTL_ZERO,
1788c2ecf20Sopenharmony_ci		.extra2		= SYSCTL_ONE,
1798c2ecf20Sopenharmony_ci	},
1808c2ecf20Sopenharmony_ci	{
1818c2ecf20Sopenharmony_ci		.procname	=  "msgmnb",
1828c2ecf20Sopenharmony_ci		.data		= &init_ipc_ns.msg_ctlmnb,
1838c2ecf20Sopenharmony_ci		.maxlen		= sizeof(init_ipc_ns.msg_ctlmnb),
1848c2ecf20Sopenharmony_ci		.mode		= 0644,
1858c2ecf20Sopenharmony_ci		.proc_handler	= proc_ipc_dointvec_minmax,
1868c2ecf20Sopenharmony_ci		.extra1		= SYSCTL_ZERO,
1878c2ecf20Sopenharmony_ci		.extra2		= SYSCTL_INT_MAX,
1888c2ecf20Sopenharmony_ci	},
1898c2ecf20Sopenharmony_ci	{
1908c2ecf20Sopenharmony_ci		.procname	= "sem",
1918c2ecf20Sopenharmony_ci		.data		= &init_ipc_ns.sem_ctls,
1928c2ecf20Sopenharmony_ci		.maxlen		= 4*sizeof(int),
1938c2ecf20Sopenharmony_ci		.mode		= 0644,
1948c2ecf20Sopenharmony_ci		.proc_handler	= proc_ipc_sem_dointvec,
1958c2ecf20Sopenharmony_ci	},
1968c2ecf20Sopenharmony_ci#ifdef CONFIG_CHECKPOINT_RESTORE
1978c2ecf20Sopenharmony_ci	{
1988c2ecf20Sopenharmony_ci		.procname	= "sem_next_id",
1998c2ecf20Sopenharmony_ci		.data		= &init_ipc_ns.ids[IPC_SEM_IDS].next_id,
2008c2ecf20Sopenharmony_ci		.maxlen		= sizeof(init_ipc_ns.ids[IPC_SEM_IDS].next_id),
2018c2ecf20Sopenharmony_ci		.mode		= 0644,
2028c2ecf20Sopenharmony_ci		.proc_handler	= proc_ipc_dointvec_minmax,
2038c2ecf20Sopenharmony_ci		.extra1		= SYSCTL_ZERO,
2048c2ecf20Sopenharmony_ci		.extra2		= SYSCTL_INT_MAX,
2058c2ecf20Sopenharmony_ci	},
2068c2ecf20Sopenharmony_ci	{
2078c2ecf20Sopenharmony_ci		.procname	= "msg_next_id",
2088c2ecf20Sopenharmony_ci		.data		= &init_ipc_ns.ids[IPC_MSG_IDS].next_id,
2098c2ecf20Sopenharmony_ci		.maxlen		= sizeof(init_ipc_ns.ids[IPC_MSG_IDS].next_id),
2108c2ecf20Sopenharmony_ci		.mode		= 0644,
2118c2ecf20Sopenharmony_ci		.proc_handler	= proc_ipc_dointvec_minmax,
2128c2ecf20Sopenharmony_ci		.extra1		= SYSCTL_ZERO,
2138c2ecf20Sopenharmony_ci		.extra2		= SYSCTL_INT_MAX,
2148c2ecf20Sopenharmony_ci	},
2158c2ecf20Sopenharmony_ci	{
2168c2ecf20Sopenharmony_ci		.procname	= "shm_next_id",
2178c2ecf20Sopenharmony_ci		.data		= &init_ipc_ns.ids[IPC_SHM_IDS].next_id,
2188c2ecf20Sopenharmony_ci		.maxlen		= sizeof(init_ipc_ns.ids[IPC_SHM_IDS].next_id),
2198c2ecf20Sopenharmony_ci		.mode		= 0644,
2208c2ecf20Sopenharmony_ci		.proc_handler	= proc_ipc_dointvec_minmax,
2218c2ecf20Sopenharmony_ci		.extra1		= SYSCTL_ZERO,
2228c2ecf20Sopenharmony_ci		.extra2		= SYSCTL_INT_MAX,
2238c2ecf20Sopenharmony_ci	},
2248c2ecf20Sopenharmony_ci#endif
2258c2ecf20Sopenharmony_ci	{}
2268c2ecf20Sopenharmony_ci};
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_cistatic struct ctl_table ipc_root_table[] = {
2298c2ecf20Sopenharmony_ci	{
2308c2ecf20Sopenharmony_ci		.procname	= "kernel",
2318c2ecf20Sopenharmony_ci		.mode		= 0555,
2328c2ecf20Sopenharmony_ci		.child		= ipc_kern_table,
2338c2ecf20Sopenharmony_ci	},
2348c2ecf20Sopenharmony_ci	{}
2358c2ecf20Sopenharmony_ci};
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_cistatic int __init ipc_sysctl_init(void)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	register_sysctl_table(ipc_root_table);
2408c2ecf20Sopenharmony_ci	return 0;
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_cidevice_initcall(ipc_sysctl_init);
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_cistatic int __init ipc_mni_extend(char *str)
2468c2ecf20Sopenharmony_ci{
2478c2ecf20Sopenharmony_ci	ipc_mni = IPCMNI_EXTEND;
2488c2ecf20Sopenharmony_ci	ipc_mni_shift = IPCMNI_EXTEND_SHIFT;
2498c2ecf20Sopenharmony_ci	ipc_min_cycle = IPCMNI_EXTEND_MIN_CYCLE;
2508c2ecf20Sopenharmony_ci	pr_info("IPCMNI extended to %d.\n", ipc_mni);
2518c2ecf20Sopenharmony_ci	return 0;
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ciearly_param("ipcmni_extend", ipc_mni_extend);
254