xref: /openbmc/linux/ipc/ipc_sysctl.c (revision 0889f44e281034e180daa6daf3e2d57c012452d4)
1b886d83cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2a5494dcdSEric W. Biederman /*
3a5494dcdSEric W. Biederman  *  Copyright (C) 2007
4a5494dcdSEric W. Biederman  *
5a5494dcdSEric W. Biederman  *  Author: Eric Biederman <ebiederm@xmision.com>
6a5494dcdSEric W. Biederman  */
7a5494dcdSEric W. Biederman 
8a5494dcdSEric W. Biederman #include <linux/module.h>
9a5494dcdSEric W. Biederman #include <linux/ipc.h>
10a5494dcdSEric W. Biederman #include <linux/nsproxy.h>
11a5494dcdSEric W. Biederman #include <linux/sysctl.h>
12a5494dcdSEric W. Biederman #include <linux/uaccess.h>
135563cabdSMichal Clapinski #include <linux/capability.h>
14ae5e1b22SPavel Emelyanov #include <linux/ipc_namespace.h>
156546bc42SNadia Derbey #include <linux/msg.h>
161f5c135eSAlexey Gladkov #include <linux/slab.h>
176546bc42SNadia Derbey #include "util.h"
18a5494dcdSEric W. Biederman 
19a5c5928bSJoe Perches static int proc_ipc_dointvec_minmax_orphans(struct ctl_table *table, int write,
2032927393SChristoph Hellwig 		void *buffer, size_t *lenp, loff_t *ppos)
21b34a6b1dSVasiliy Kulikov {
22dd141a49SAlexey Gladkov 	struct ipc_namespace *ns =
23dd141a49SAlexey Gladkov 		container_of(table->data, struct ipc_namespace, shm_rmid_forced);
241f5c135eSAlexey Gladkov 	int err;
251f5c135eSAlexey Gladkov 
26dd141a49SAlexey Gladkov 	err = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
27b34a6b1dSVasiliy Kulikov 
28b34a6b1dSVasiliy Kulikov 	if (err < 0)
29b34a6b1dSVasiliy Kulikov 		return err;
30b34a6b1dSVasiliy Kulikov 	if (ns->shm_rmid_forced)
31b34a6b1dSVasiliy Kulikov 		shm_destroy_orphaned(ns);
32b34a6b1dSVasiliy Kulikov 	return err;
33b34a6b1dSVasiliy Kulikov }
34b34a6b1dSVasiliy Kulikov 
350050ee05SManfred Spraul static int proc_ipc_auto_msgmni(struct ctl_table *table, int write,
3632927393SChristoph Hellwig 		void *buffer, size_t *lenp, loff_t *ppos)
379eefe520SNadia Derbey {
389eefe520SNadia Derbey 	struct ctl_table ipc_table;
390050ee05SManfred Spraul 	int dummy = 0;
409eefe520SNadia Derbey 
419eefe520SNadia Derbey 	memcpy(&ipc_table, table, sizeof(ipc_table));
420050ee05SManfred Spraul 	ipc_table.data = &dummy;
439eefe520SNadia Derbey 
440050ee05SManfred Spraul 	if (write)
450050ee05SManfred Spraul 		pr_info_once("writing to auto_msgmni has no effect");
469eefe520SNadia Derbey 
470050ee05SManfred Spraul 	return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
489eefe520SNadia Derbey }
499eefe520SNadia Derbey 
508c81ddd2SWaiman Long static int proc_ipc_sem_dointvec(struct ctl_table *table, int write,
51fff1662cSTobias Klauser 	void *buffer, size_t *lenp, loff_t *ppos)
528c81ddd2SWaiman Long {
53dd141a49SAlexey Gladkov 	struct ipc_namespace *ns =
54dd141a49SAlexey Gladkov 		container_of(table->data, struct ipc_namespace, sem_ctls);
558c81ddd2SWaiman Long 	int ret, semmni;
561f5c135eSAlexey Gladkov 
578c81ddd2SWaiman Long 	semmni = ns->sem_ctls[3];
581f5c135eSAlexey Gladkov 	ret = proc_dointvec(table, write, buffer, lenp, ppos);
598c81ddd2SWaiman Long 
608c81ddd2SWaiman Long 	if (!ret)
61def7343fSAlexey Gladkov 		ret = sem_check_semmni(ns);
628c81ddd2SWaiman Long 
638c81ddd2SWaiman Long 	/*
648c81ddd2SWaiman Long 	 * Reset the semmni value if an error happens.
658c81ddd2SWaiman Long 	 */
668c81ddd2SWaiman Long 	if (ret)
678c81ddd2SWaiman Long 		ns->sem_ctls[3] = semmni;
688c81ddd2SWaiman Long 	return ret;
698c81ddd2SWaiman Long }
708c81ddd2SWaiman Long 
715ac893b8SWaiman Long int ipc_mni = IPCMNI;
725ac893b8SWaiman Long int ipc_mni_shift = IPCMNI_SHIFT;
7399db46eaSManfred Spraul int ipc_min_cycle = RADIX_TREE_MAP_SIZE;
749eefe520SNadia Derbey 
751f5c135eSAlexey Gladkov static struct ctl_table ipc_sysctls[] = {
76a5494dcdSEric W. Biederman 	{
77a5494dcdSEric W. Biederman 		.procname	= "shmmax",
78a5494dcdSEric W. Biederman 		.data		= &init_ipc_ns.shm_ctlmax,
79a5494dcdSEric W. Biederman 		.maxlen		= sizeof(init_ipc_ns.shm_ctlmax),
80a5494dcdSEric W. Biederman 		.mode		= 0644,
811f5c135eSAlexey Gladkov 		.proc_handler	= proc_doulongvec_minmax,
82a5494dcdSEric W. Biederman 	},
83a5494dcdSEric W. Biederman 	{
84a5494dcdSEric W. Biederman 		.procname	= "shmall",
85a5494dcdSEric W. Biederman 		.data		= &init_ipc_ns.shm_ctlall,
86a5494dcdSEric W. Biederman 		.maxlen		= sizeof(init_ipc_ns.shm_ctlall),
87a5494dcdSEric W. Biederman 		.mode		= 0644,
881f5c135eSAlexey Gladkov 		.proc_handler	= proc_doulongvec_minmax,
89a5494dcdSEric W. Biederman 	},
90a5494dcdSEric W. Biederman 	{
91a5494dcdSEric W. Biederman 		.procname	= "shmmni",
92a5494dcdSEric W. Biederman 		.data		= &init_ipc_ns.shm_ctlmni,
93a5494dcdSEric W. Biederman 		.maxlen		= sizeof(init_ipc_ns.shm_ctlmni),
94a5494dcdSEric W. Biederman 		.mode		= 0644,
951f5c135eSAlexey Gladkov 		.proc_handler	= proc_dointvec_minmax,
96eec4844fSMatteo Croce 		.extra1		= SYSCTL_ZERO,
976730e658SWaiman Long 		.extra2		= &ipc_mni,
98a5494dcdSEric W. Biederman 	},
99a5494dcdSEric W. Biederman 	{
100b34a6b1dSVasiliy Kulikov 		.procname	= "shm_rmid_forced",
101b34a6b1dSVasiliy Kulikov 		.data		= &init_ipc_ns.shm_rmid_forced,
102b34a6b1dSVasiliy Kulikov 		.maxlen		= sizeof(init_ipc_ns.shm_rmid_forced),
103b34a6b1dSVasiliy Kulikov 		.mode		= 0644,
104b34a6b1dSVasiliy Kulikov 		.proc_handler	= proc_ipc_dointvec_minmax_orphans,
105dd141a49SAlexey Gladkov 		.extra1		= SYSCTL_ZERO,
106dd141a49SAlexey Gladkov 		.extra2		= SYSCTL_ONE,
107b34a6b1dSVasiliy Kulikov 	},
108b34a6b1dSVasiliy Kulikov 	{
109a5494dcdSEric W. Biederman 		.procname	= "msgmax",
110a5494dcdSEric W. Biederman 		.data		= &init_ipc_ns.msg_ctlmax,
111a5494dcdSEric W. Biederman 		.maxlen		= sizeof(init_ipc_ns.msg_ctlmax),
112a5494dcdSEric W. Biederman 		.mode		= 0644,
1131f5c135eSAlexey Gladkov 		.proc_handler	= proc_dointvec_minmax,
114eec4844fSMatteo Croce 		.extra1		= SYSCTL_ZERO,
115eec4844fSMatteo Croce 		.extra2		= SYSCTL_INT_MAX,
116a5494dcdSEric W. Biederman 	},
117a5494dcdSEric W. Biederman 	{
118a5494dcdSEric W. Biederman 		.procname	= "msgmni",
119a5494dcdSEric W. Biederman 		.data		= &init_ipc_ns.msg_ctlmni,
120a5494dcdSEric W. Biederman 		.maxlen		= sizeof(init_ipc_ns.msg_ctlmni),
121a5494dcdSEric W. Biederman 		.mode		= 0644,
1221f5c135eSAlexey Gladkov 		.proc_handler	= proc_dointvec_minmax,
123eec4844fSMatteo Croce 		.extra1		= SYSCTL_ZERO,
1246730e658SWaiman Long 		.extra2		= &ipc_mni,
125a5494dcdSEric W. Biederman 	},
126a5494dcdSEric W. Biederman 	{
1270050ee05SManfred Spraul 		.procname	= "auto_msgmni",
1280050ee05SManfred Spraul 		.data		= NULL,
1290050ee05SManfred Spraul 		.maxlen		= sizeof(int),
1300050ee05SManfred Spraul 		.mode		= 0644,
1310050ee05SManfred Spraul 		.proc_handler	= proc_ipc_auto_msgmni,
132eec4844fSMatteo Croce 		.extra1		= SYSCTL_ZERO,
133eec4844fSMatteo Croce 		.extra2		= SYSCTL_ONE,
1340050ee05SManfred Spraul 	},
1350050ee05SManfred Spraul 	{
136a5494dcdSEric W. Biederman 		.procname	=  "msgmnb",
137a5494dcdSEric W. Biederman 		.data		= &init_ipc_ns.msg_ctlmnb,
138a5494dcdSEric W. Biederman 		.maxlen		= sizeof(init_ipc_ns.msg_ctlmnb),
139a5494dcdSEric W. Biederman 		.mode		= 0644,
1401f5c135eSAlexey Gladkov 		.proc_handler	= proc_dointvec_minmax,
141eec4844fSMatteo Croce 		.extra1		= SYSCTL_ZERO,
142eec4844fSMatteo Croce 		.extra2		= SYSCTL_INT_MAX,
143a5494dcdSEric W. Biederman 	},
144a5494dcdSEric W. Biederman 	{
145a5494dcdSEric W. Biederman 		.procname	= "sem",
146a5494dcdSEric W. Biederman 		.data		= &init_ipc_ns.sem_ctls,
147a5494dcdSEric W. Biederman 		.maxlen		= 4*sizeof(int),
148a5494dcdSEric W. Biederman 		.mode		= 0644,
1498c81ddd2SWaiman Long 		.proc_handler	= proc_ipc_sem_dointvec,
150a5494dcdSEric W. Biederman 	},
15103f59566SStanislav Kinsbursky #ifdef CONFIG_CHECKPOINT_RESTORE
15203f59566SStanislav Kinsbursky 	{
15303f59566SStanislav Kinsbursky 		.procname	= "sem_next_id",
15403f59566SStanislav Kinsbursky 		.data		= &init_ipc_ns.ids[IPC_SEM_IDS].next_id,
15503f59566SStanislav Kinsbursky 		.maxlen		= sizeof(init_ipc_ns.ids[IPC_SEM_IDS].next_id),
156*0889f44eSAlexey Gladkov 		.mode		= 0444,
157*0889f44eSAlexey Gladkov 		.proc_handler	= proc_dointvec_minmax,
158*0889f44eSAlexey Gladkov 		.extra1		= SYSCTL_ZERO,
159*0889f44eSAlexey Gladkov 		.extra2		= SYSCTL_INT_MAX,
16003f59566SStanislav Kinsbursky 	},
16103f59566SStanislav Kinsbursky 	{
16203f59566SStanislav Kinsbursky 		.procname	= "msg_next_id",
16303f59566SStanislav Kinsbursky 		.data		= &init_ipc_ns.ids[IPC_MSG_IDS].next_id,
16403f59566SStanislav Kinsbursky 		.maxlen		= sizeof(init_ipc_ns.ids[IPC_MSG_IDS].next_id),
165*0889f44eSAlexey Gladkov 		.mode		= 0444,
166*0889f44eSAlexey Gladkov 		.proc_handler	= proc_dointvec_minmax,
167*0889f44eSAlexey Gladkov 		.extra1		= SYSCTL_ZERO,
168*0889f44eSAlexey Gladkov 		.extra2		= SYSCTL_INT_MAX,
16903f59566SStanislav Kinsbursky 	},
17003f59566SStanislav Kinsbursky 	{
17103f59566SStanislav Kinsbursky 		.procname	= "shm_next_id",
17203f59566SStanislav Kinsbursky 		.data		= &init_ipc_ns.ids[IPC_SHM_IDS].next_id,
17303f59566SStanislav Kinsbursky 		.maxlen		= sizeof(init_ipc_ns.ids[IPC_SHM_IDS].next_id),
174*0889f44eSAlexey Gladkov 		.mode		= 0444,
175*0889f44eSAlexey Gladkov 		.proc_handler	= proc_dointvec_minmax,
176*0889f44eSAlexey Gladkov 		.extra1		= SYSCTL_ZERO,
177*0889f44eSAlexey Gladkov 		.extra2		= SYSCTL_INT_MAX,
17803f59566SStanislav Kinsbursky 	},
17903f59566SStanislav Kinsbursky #endif
180a5494dcdSEric W. Biederman 	{}
181a5494dcdSEric W. Biederman };
182a5494dcdSEric W. Biederman 
1831f5c135eSAlexey Gladkov static struct ctl_table_set *set_lookup(struct ctl_table_root *root)
184a5494dcdSEric W. Biederman {
1851f5c135eSAlexey Gladkov 	return &current->nsproxy->ipc_ns->ipc_set;
1861f5c135eSAlexey Gladkov }
1871f5c135eSAlexey Gladkov 
1881f5c135eSAlexey Gladkov static int set_is_seen(struct ctl_table_set *set)
1891f5c135eSAlexey Gladkov {
1901f5c135eSAlexey Gladkov 	return &current->nsproxy->ipc_ns->ipc_set == set;
1911f5c135eSAlexey Gladkov }
1921f5c135eSAlexey Gladkov 
193*0889f44eSAlexey Gladkov static int ipc_permissions(struct ctl_table_header *head, struct ctl_table *table)
194*0889f44eSAlexey Gladkov {
195*0889f44eSAlexey Gladkov 	int mode = table->mode;
196*0889f44eSAlexey Gladkov 
197*0889f44eSAlexey Gladkov #ifdef CONFIG_CHECKPOINT_RESTORE
198*0889f44eSAlexey Gladkov 	struct ipc_namespace *ns = current->nsproxy->ipc_ns;
199*0889f44eSAlexey Gladkov 
200*0889f44eSAlexey Gladkov 	if (((table->data == &ns->ids[IPC_SEM_IDS].next_id) ||
201*0889f44eSAlexey Gladkov 	     (table->data == &ns->ids[IPC_MSG_IDS].next_id) ||
202*0889f44eSAlexey Gladkov 	     (table->data == &ns->ids[IPC_SHM_IDS].next_id)) &&
203*0889f44eSAlexey Gladkov 	    checkpoint_restore_ns_capable(ns->user_ns))
204*0889f44eSAlexey Gladkov 		mode = 0666;
205*0889f44eSAlexey Gladkov #endif
206*0889f44eSAlexey Gladkov 	return mode;
207*0889f44eSAlexey Gladkov }
208*0889f44eSAlexey Gladkov 
2091f5c135eSAlexey Gladkov static struct ctl_table_root set_root = {
2101f5c135eSAlexey Gladkov 	.lookup = set_lookup,
211*0889f44eSAlexey Gladkov 	.permissions = ipc_permissions,
212a5494dcdSEric W. Biederman };
213a5494dcdSEric W. Biederman 
2141f5c135eSAlexey Gladkov bool setup_ipc_sysctls(struct ipc_namespace *ns)
2151f5c135eSAlexey Gladkov {
2161f5c135eSAlexey Gladkov 	struct ctl_table *tbl;
2171f5c135eSAlexey Gladkov 
2181f5c135eSAlexey Gladkov 	setup_sysctl_set(&ns->ipc_set, &set_root, set_is_seen);
2191f5c135eSAlexey Gladkov 
2201f5c135eSAlexey Gladkov 	tbl = kmemdup(ipc_sysctls, sizeof(ipc_sysctls), GFP_KERNEL);
2211f5c135eSAlexey Gladkov 	if (tbl) {
2221f5c135eSAlexey Gladkov 		int i;
2231f5c135eSAlexey Gladkov 
2241f5c135eSAlexey Gladkov 		for (i = 0; i < ARRAY_SIZE(ipc_sysctls); i++) {
2251f5c135eSAlexey Gladkov 			if (tbl[i].data == &init_ipc_ns.shm_ctlmax) {
2261f5c135eSAlexey Gladkov 				tbl[i].data = &ns->shm_ctlmax;
2271f5c135eSAlexey Gladkov 
2281f5c135eSAlexey Gladkov 			} else if (tbl[i].data == &init_ipc_ns.shm_ctlall) {
2291f5c135eSAlexey Gladkov 				tbl[i].data = &ns->shm_ctlall;
2301f5c135eSAlexey Gladkov 
2311f5c135eSAlexey Gladkov 			} else if (tbl[i].data == &init_ipc_ns.shm_ctlmni) {
2321f5c135eSAlexey Gladkov 				tbl[i].data = &ns->shm_ctlmni;
2331f5c135eSAlexey Gladkov 
2341f5c135eSAlexey Gladkov 			} else if (tbl[i].data == &init_ipc_ns.shm_rmid_forced) {
2351f5c135eSAlexey Gladkov 				tbl[i].data = &ns->shm_rmid_forced;
2361f5c135eSAlexey Gladkov 
2371f5c135eSAlexey Gladkov 			} else if (tbl[i].data == &init_ipc_ns.msg_ctlmax) {
2381f5c135eSAlexey Gladkov 				tbl[i].data = &ns->msg_ctlmax;
2391f5c135eSAlexey Gladkov 
2401f5c135eSAlexey Gladkov 			} else if (tbl[i].data == &init_ipc_ns.msg_ctlmni) {
2411f5c135eSAlexey Gladkov 				tbl[i].data = &ns->msg_ctlmni;
2421f5c135eSAlexey Gladkov 
2431f5c135eSAlexey Gladkov 			} else if (tbl[i].data == &init_ipc_ns.msg_ctlmnb) {
2441f5c135eSAlexey Gladkov 				tbl[i].data = &ns->msg_ctlmnb;
2451f5c135eSAlexey Gladkov 
2461f5c135eSAlexey Gladkov 			} else if (tbl[i].data == &init_ipc_ns.sem_ctls) {
2471f5c135eSAlexey Gladkov 				tbl[i].data = &ns->sem_ctls;
2481f5c135eSAlexey Gladkov #ifdef CONFIG_CHECKPOINT_RESTORE
2491f5c135eSAlexey Gladkov 			} else if (tbl[i].data == &init_ipc_ns.ids[IPC_SEM_IDS].next_id) {
2501f5c135eSAlexey Gladkov 				tbl[i].data = &ns->ids[IPC_SEM_IDS].next_id;
2511f5c135eSAlexey Gladkov 
2521f5c135eSAlexey Gladkov 			} else if (tbl[i].data == &init_ipc_ns.ids[IPC_MSG_IDS].next_id) {
2531f5c135eSAlexey Gladkov 				tbl[i].data = &ns->ids[IPC_MSG_IDS].next_id;
2541f5c135eSAlexey Gladkov 
2551f5c135eSAlexey Gladkov 			} else if (tbl[i].data == &init_ipc_ns.ids[IPC_SHM_IDS].next_id) {
2561f5c135eSAlexey Gladkov 				tbl[i].data = &ns->ids[IPC_SHM_IDS].next_id;
2571f5c135eSAlexey Gladkov #endif
2581f5c135eSAlexey Gladkov 			} else {
2591f5c135eSAlexey Gladkov 				tbl[i].data = NULL;
2601f5c135eSAlexey Gladkov 			}
2611f5c135eSAlexey Gladkov 		}
2621f5c135eSAlexey Gladkov 
2631f5c135eSAlexey Gladkov 		ns->ipc_sysctls = __register_sysctl_table(&ns->ipc_set, "kernel", tbl);
2641f5c135eSAlexey Gladkov 	}
2651f5c135eSAlexey Gladkov 	if (!ns->ipc_sysctls) {
2661f5c135eSAlexey Gladkov 		kfree(tbl);
2671f5c135eSAlexey Gladkov 		retire_sysctl_set(&ns->ipc_set);
2681f5c135eSAlexey Gladkov 		return false;
2691f5c135eSAlexey Gladkov 	}
2701f5c135eSAlexey Gladkov 
2711f5c135eSAlexey Gladkov 	return true;
2721f5c135eSAlexey Gladkov }
2731f5c135eSAlexey Gladkov 
2741f5c135eSAlexey Gladkov void retire_ipc_sysctls(struct ipc_namespace *ns)
2751f5c135eSAlexey Gladkov {
2761f5c135eSAlexey Gladkov 	struct ctl_table *tbl;
2771f5c135eSAlexey Gladkov 
2781f5c135eSAlexey Gladkov 	tbl = ns->ipc_sysctls->ctl_table_arg;
2791f5c135eSAlexey Gladkov 	unregister_sysctl_table(ns->ipc_sysctls);
2801f5c135eSAlexey Gladkov 	retire_sysctl_set(&ns->ipc_set);
2811f5c135eSAlexey Gladkov 	kfree(tbl);
2821f5c135eSAlexey Gladkov }
2831f5c135eSAlexey Gladkov 
284a5494dcdSEric W. Biederman static int __init ipc_sysctl_init(void)
285a5494dcdSEric W. Biederman {
2861f5c135eSAlexey Gladkov 	if (!setup_ipc_sysctls(&init_ipc_ns)) {
2871f5c135eSAlexey Gladkov 		pr_warn("ipc sysctl registration failed\n");
2881f5c135eSAlexey Gladkov 		return -ENOMEM;
2891f5c135eSAlexey Gladkov 	}
290a5494dcdSEric W. Biederman 	return 0;
291a5494dcdSEric W. Biederman }
292a5494dcdSEric W. Biederman 
2936d08a256SDavidlohr Bueso device_initcall(ipc_sysctl_init);
2945ac893b8SWaiman Long 
2955ac893b8SWaiman Long static int __init ipc_mni_extend(char *str)
2965ac893b8SWaiman Long {
2975ac893b8SWaiman Long 	ipc_mni = IPCMNI_EXTEND;
2985ac893b8SWaiman Long 	ipc_mni_shift = IPCMNI_EXTEND_SHIFT;
29999db46eaSManfred Spraul 	ipc_min_cycle = IPCMNI_EXTEND_MIN_CYCLE;
3005ac893b8SWaiman Long 	pr_info("IPCMNI extended to %d.\n", ipc_mni);
3015ac893b8SWaiman Long 	return 0;
3025ac893b8SWaiman Long }
3035ac893b8SWaiman Long early_param("ipcmni_extend", ipc_mni_extend);
304