xref: /openbmc/linux/ipc/ipc_sysctl.c (revision 6d08a2567c0b9103c3ff946df17ad4be9a917e2f)
1a5494dcdSEric W. Biederman /*
2a5494dcdSEric W. Biederman  *  Copyright (C) 2007
3a5494dcdSEric W. Biederman  *
4a5494dcdSEric W. Biederman  *  Author: Eric Biederman <ebiederm@xmision.com>
5a5494dcdSEric W. Biederman  *
6a5494dcdSEric W. Biederman  *  This program is free software; you can redistribute it and/or
7a5494dcdSEric W. Biederman  *  modify it under the terms of the GNU General Public License as
8a5494dcdSEric W. Biederman  *  published by the Free Software Foundation, version 2 of the
9a5494dcdSEric W. Biederman  *  License.
10a5494dcdSEric W. Biederman  */
11a5494dcdSEric W. Biederman 
12a5494dcdSEric W. Biederman #include <linux/module.h>
13a5494dcdSEric W. Biederman #include <linux/ipc.h>
14a5494dcdSEric W. Biederman #include <linux/nsproxy.h>
15a5494dcdSEric W. Biederman #include <linux/sysctl.h>
16a5494dcdSEric W. Biederman #include <linux/uaccess.h>
17ae5e1b22SPavel Emelyanov #include <linux/ipc_namespace.h>
186546bc42SNadia Derbey #include <linux/msg.h>
196546bc42SNadia Derbey #include "util.h"
20a5494dcdSEric W. Biederman 
21a5494dcdSEric W. Biederman static void *get_ipc(ctl_table *table)
22a5494dcdSEric W. Biederman {
23a5494dcdSEric W. Biederman 	char *which = table->data;
24a5494dcdSEric W. Biederman 	struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
25a5494dcdSEric W. Biederman 	which = (which - (char *)&init_ipc_ns) + (char *)ipc_ns;
26a5494dcdSEric W. Biederman 	return which;
27a5494dcdSEric W. Biederman }
28a5494dcdSEric W. Biederman 
2911dea190SSerge E. Hallyn #ifdef CONFIG_PROC_SYSCTL
308d65af78SAlexey Dobriyan static int proc_ipc_dointvec(ctl_table *table, int write,
31a5494dcdSEric W. Biederman 	void __user *buffer, size_t *lenp, loff_t *ppos)
32a5494dcdSEric W. Biederman {
33a5494dcdSEric W. Biederman 	struct ctl_table ipc_table;
34b34a6b1dSVasiliy Kulikov 
35a5494dcdSEric W. Biederman 	memcpy(&ipc_table, table, sizeof(ipc_table));
36a5494dcdSEric W. Biederman 	ipc_table.data = get_ipc(table);
37a5494dcdSEric W. Biederman 
388d65af78SAlexey Dobriyan 	return proc_dointvec(&ipc_table, write, buffer, lenp, ppos);
39a5494dcdSEric W. Biederman }
40a5494dcdSEric W. Biederman 
41b34a6b1dSVasiliy Kulikov static int proc_ipc_dointvec_minmax(ctl_table *table, int write,
42b34a6b1dSVasiliy Kulikov 	void __user *buffer, size_t *lenp, loff_t *ppos)
43b34a6b1dSVasiliy Kulikov {
44b34a6b1dSVasiliy Kulikov 	struct ctl_table ipc_table;
45b34a6b1dSVasiliy Kulikov 
46b34a6b1dSVasiliy Kulikov 	memcpy(&ipc_table, table, sizeof(ipc_table));
47b34a6b1dSVasiliy Kulikov 	ipc_table.data = get_ipc(table);
48b34a6b1dSVasiliy Kulikov 
49b34a6b1dSVasiliy Kulikov 	return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
50b34a6b1dSVasiliy Kulikov }
51b34a6b1dSVasiliy Kulikov 
52b34a6b1dSVasiliy Kulikov static int proc_ipc_dointvec_minmax_orphans(ctl_table *table, int write,
53b34a6b1dSVasiliy Kulikov 	void __user *buffer, size_t *lenp, loff_t *ppos)
54b34a6b1dSVasiliy Kulikov {
55b34a6b1dSVasiliy Kulikov 	struct ipc_namespace *ns = current->nsproxy->ipc_ns;
56b34a6b1dSVasiliy Kulikov 	int err = proc_ipc_dointvec_minmax(table, write, buffer, lenp, ppos);
57b34a6b1dSVasiliy Kulikov 
58b34a6b1dSVasiliy Kulikov 	if (err < 0)
59b34a6b1dSVasiliy Kulikov 		return err;
60b34a6b1dSVasiliy Kulikov 	if (ns->shm_rmid_forced)
61b34a6b1dSVasiliy Kulikov 		shm_destroy_orphaned(ns);
62b34a6b1dSVasiliy Kulikov 	return err;
63b34a6b1dSVasiliy Kulikov }
64b34a6b1dSVasiliy Kulikov 
659bf76ca3SMathias Krause static int proc_ipc_callback_dointvec_minmax(ctl_table *table, int write,
668d65af78SAlexey Dobriyan 	void __user *buffer, size_t *lenp, loff_t *ppos)
6791cfb2b4SNadia Derbey {
686546bc42SNadia Derbey 	struct ctl_table ipc_table;
6991cfb2b4SNadia Derbey 	size_t lenp_bef = *lenp;
7091cfb2b4SNadia Derbey 	int rc;
7191cfb2b4SNadia Derbey 
726546bc42SNadia Derbey 	memcpy(&ipc_table, table, sizeof(ipc_table));
736546bc42SNadia Derbey 	ipc_table.data = get_ipc(table);
746546bc42SNadia Derbey 
759bf76ca3SMathias Krause 	rc = proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
7691cfb2b4SNadia Derbey 
7791cfb2b4SNadia Derbey 	if (write && !rc && lenp_bef == *lenp)
789eefe520SNadia Derbey 		/*
799eefe520SNadia Derbey 		 * Tunable has successfully been changed by hand. Disable its
809eefe520SNadia Derbey 		 * automatic adjustment. This simply requires unregistering
819eefe520SNadia Derbey 		 * the notifiers that trigger recalculation.
829eefe520SNadia Derbey 		 */
839eefe520SNadia Derbey 		unregister_ipcns_notifier(current->nsproxy->ipc_ns);
8491cfb2b4SNadia Derbey 
8591cfb2b4SNadia Derbey 	return rc;
8691cfb2b4SNadia Derbey }
8791cfb2b4SNadia Derbey 
88a5494dcdSEric W. Biederman static int proc_ipc_doulongvec_minmax(ctl_table *table, int write,
898d65af78SAlexey Dobriyan 	void __user *buffer, size_t *lenp, loff_t *ppos)
90a5494dcdSEric W. Biederman {
91a5494dcdSEric W. Biederman 	struct ctl_table ipc_table;
92a5494dcdSEric W. Biederman 	memcpy(&ipc_table, table, sizeof(ipc_table));
93a5494dcdSEric W. Biederman 	ipc_table.data = get_ipc(table);
94a5494dcdSEric W. Biederman 
958d65af78SAlexey Dobriyan 	return proc_doulongvec_minmax(&ipc_table, write, buffer,
96a5494dcdSEric W. Biederman 					lenp, ppos);
97a5494dcdSEric W. Biederman }
98a5494dcdSEric W. Biederman 
994c2c3b4aSakpm@linux-foundation.org /*
1004c2c3b4aSakpm@linux-foundation.org  * Routine that is called when the file "auto_msgmni" has successfully been
1014c2c3b4aSakpm@linux-foundation.org  * written.
1024c2c3b4aSakpm@linux-foundation.org  * Two values are allowed:
1034c2c3b4aSakpm@linux-foundation.org  * 0: unregister msgmni's callback routine from the ipc namespace notifier
1044c2c3b4aSakpm@linux-foundation.org  *    chain. This means that msgmni won't be recomputed anymore upon memory
1054c2c3b4aSakpm@linux-foundation.org  *    add/remove or ipc namespace creation/removal.
1064c2c3b4aSakpm@linux-foundation.org  * 1: register back the callback routine.
1074c2c3b4aSakpm@linux-foundation.org  */
1084c2c3b4aSakpm@linux-foundation.org static void ipc_auto_callback(int val)
1094c2c3b4aSakpm@linux-foundation.org {
1104c2c3b4aSakpm@linux-foundation.org 	if (!val)
1114c2c3b4aSakpm@linux-foundation.org 		unregister_ipcns_notifier(current->nsproxy->ipc_ns);
1124c2c3b4aSakpm@linux-foundation.org 	else {
1134c2c3b4aSakpm@linux-foundation.org 		/*
1144c2c3b4aSakpm@linux-foundation.org 		 * Re-enable automatic recomputing only if not already
1154c2c3b4aSakpm@linux-foundation.org 		 * enabled.
1164c2c3b4aSakpm@linux-foundation.org 		 */
1174c2c3b4aSakpm@linux-foundation.org 		recompute_msgmni(current->nsproxy->ipc_ns);
1184c2c3b4aSakpm@linux-foundation.org 		cond_register_ipcns_notifier(current->nsproxy->ipc_ns);
1194c2c3b4aSakpm@linux-foundation.org 	}
1204c2c3b4aSakpm@linux-foundation.org }
1214c2c3b4aSakpm@linux-foundation.org 
1229eefe520SNadia Derbey static int proc_ipcauto_dointvec_minmax(ctl_table *table, int write,
1238d65af78SAlexey Dobriyan 	void __user *buffer, size_t *lenp, loff_t *ppos)
1249eefe520SNadia Derbey {
1259eefe520SNadia Derbey 	struct ctl_table ipc_table;
1269eefe520SNadia Derbey 	size_t lenp_bef = *lenp;
1279eefe520SNadia Derbey 	int oldval;
1289eefe520SNadia Derbey 	int rc;
1299eefe520SNadia Derbey 
1309eefe520SNadia Derbey 	memcpy(&ipc_table, table, sizeof(ipc_table));
1319eefe520SNadia Derbey 	ipc_table.data = get_ipc(table);
1329eefe520SNadia Derbey 	oldval = *((int *)(ipc_table.data));
1339eefe520SNadia Derbey 
1348d65af78SAlexey Dobriyan 	rc = proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
1359eefe520SNadia Derbey 
1369eefe520SNadia Derbey 	if (write && !rc && lenp_bef == *lenp) {
1379eefe520SNadia Derbey 		int newval = *((int *)(ipc_table.data));
1389eefe520SNadia Derbey 		/*
1399eefe520SNadia Derbey 		 * The file "auto_msgmni" has correctly been set.
1409eefe520SNadia Derbey 		 * React by (un)registering the corresponding tunable, if the
1419eefe520SNadia Derbey 		 * value has changed.
1429eefe520SNadia Derbey 		 */
1439eefe520SNadia Derbey 		if (newval != oldval)
1449eefe520SNadia Derbey 			ipc_auto_callback(newval);
1459eefe520SNadia Derbey 	}
1469eefe520SNadia Derbey 
1479eefe520SNadia Derbey 	return rc;
1489eefe520SNadia Derbey }
1499eefe520SNadia Derbey 
150a5494dcdSEric W. Biederman #else
151a5494dcdSEric W. Biederman #define proc_ipc_doulongvec_minmax NULL
152a5494dcdSEric W. Biederman #define proc_ipc_dointvec	   NULL
153b34a6b1dSVasiliy Kulikov #define proc_ipc_dointvec_minmax   NULL
154b34a6b1dSVasiliy Kulikov #define proc_ipc_dointvec_minmax_orphans   NULL
1559bf76ca3SMathias Krause #define proc_ipc_callback_dointvec_minmax  NULL
1569eefe520SNadia Derbey #define proc_ipcauto_dointvec_minmax NULL
157a5494dcdSEric W. Biederman #endif
158a5494dcdSEric W. Biederman 
1599eefe520SNadia Derbey static int zero;
1609eefe520SNadia Derbey static int one = 1;
16103f59566SStanislav Kinsbursky static int int_max = INT_MAX;
1629eefe520SNadia Derbey 
163a5494dcdSEric W. Biederman static struct ctl_table ipc_kern_table[] = {
164a5494dcdSEric W. Biederman 	{
165a5494dcdSEric W. Biederman 		.procname	= "shmmax",
166a5494dcdSEric W. Biederman 		.data		= &init_ipc_ns.shm_ctlmax,
167a5494dcdSEric W. Biederman 		.maxlen		= sizeof(init_ipc_ns.shm_ctlmax),
168a5494dcdSEric W. Biederman 		.mode		= 0644,
169a5494dcdSEric W. Biederman 		.proc_handler	= proc_ipc_doulongvec_minmax,
170a5494dcdSEric W. Biederman 	},
171a5494dcdSEric W. Biederman 	{
172a5494dcdSEric W. Biederman 		.procname	= "shmall",
173a5494dcdSEric W. Biederman 		.data		= &init_ipc_ns.shm_ctlall,
174a5494dcdSEric W. Biederman 		.maxlen		= sizeof(init_ipc_ns.shm_ctlall),
175a5494dcdSEric W. Biederman 		.mode		= 0644,
176a5494dcdSEric W. Biederman 		.proc_handler	= proc_ipc_doulongvec_minmax,
177a5494dcdSEric W. Biederman 	},
178a5494dcdSEric W. Biederman 	{
179a5494dcdSEric W. Biederman 		.procname	= "shmmni",
180a5494dcdSEric W. Biederman 		.data		= &init_ipc_ns.shm_ctlmni,
181a5494dcdSEric W. Biederman 		.maxlen		= sizeof(init_ipc_ns.shm_ctlmni),
182a5494dcdSEric W. Biederman 		.mode		= 0644,
183a5494dcdSEric W. Biederman 		.proc_handler	= proc_ipc_dointvec,
184a5494dcdSEric W. Biederman 	},
185a5494dcdSEric W. Biederman 	{
186b34a6b1dSVasiliy Kulikov 		.procname	= "shm_rmid_forced",
187b34a6b1dSVasiliy Kulikov 		.data		= &init_ipc_ns.shm_rmid_forced,
188b34a6b1dSVasiliy Kulikov 		.maxlen		= sizeof(init_ipc_ns.shm_rmid_forced),
189b34a6b1dSVasiliy Kulikov 		.mode		= 0644,
190b34a6b1dSVasiliy Kulikov 		.proc_handler	= proc_ipc_dointvec_minmax_orphans,
191b34a6b1dSVasiliy Kulikov 		.extra1		= &zero,
192b34a6b1dSVasiliy Kulikov 		.extra2		= &one,
193b34a6b1dSVasiliy Kulikov 	},
194b34a6b1dSVasiliy Kulikov 	{
195a5494dcdSEric W. Biederman 		.procname	= "msgmax",
196a5494dcdSEric W. Biederman 		.data		= &init_ipc_ns.msg_ctlmax,
197a5494dcdSEric W. Biederman 		.maxlen		= sizeof(init_ipc_ns.msg_ctlmax),
198a5494dcdSEric W. Biederman 		.mode		= 0644,
1999bf76ca3SMathias Krause 		.proc_handler	= proc_ipc_dointvec_minmax,
2009bf76ca3SMathias Krause 		.extra1		= &zero,
2019bf76ca3SMathias Krause 		.extra2		= &int_max,
202a5494dcdSEric W. Biederman 	},
203a5494dcdSEric W. Biederman 	{
204a5494dcdSEric W. Biederman 		.procname	= "msgmni",
205a5494dcdSEric W. Biederman 		.data		= &init_ipc_ns.msg_ctlmni,
206a5494dcdSEric W. Biederman 		.maxlen		= sizeof(init_ipc_ns.msg_ctlmni),
207a5494dcdSEric W. Biederman 		.mode		= 0644,
2089bf76ca3SMathias Krause 		.proc_handler	= proc_ipc_callback_dointvec_minmax,
2099bf76ca3SMathias Krause 		.extra1		= &zero,
2109bf76ca3SMathias Krause 		.extra2		= &int_max,
211a5494dcdSEric W. Biederman 	},
212a5494dcdSEric W. Biederman 	{
213a5494dcdSEric W. Biederman 		.procname	=  "msgmnb",
214a5494dcdSEric W. Biederman 		.data		= &init_ipc_ns.msg_ctlmnb,
215a5494dcdSEric W. Biederman 		.maxlen		= sizeof(init_ipc_ns.msg_ctlmnb),
216a5494dcdSEric W. Biederman 		.mode		= 0644,
2179bf76ca3SMathias Krause 		.proc_handler	= proc_ipc_dointvec_minmax,
2189bf76ca3SMathias Krause 		.extra1		= &zero,
2199bf76ca3SMathias Krause 		.extra2		= &int_max,
220a5494dcdSEric W. Biederman 	},
221a5494dcdSEric W. Biederman 	{
222a5494dcdSEric W. Biederman 		.procname	= "sem",
223a5494dcdSEric W. Biederman 		.data		= &init_ipc_ns.sem_ctls,
224a5494dcdSEric W. Biederman 		.maxlen		= 4*sizeof(int),
225a5494dcdSEric W. Biederman 		.mode		= 0644,
226a5494dcdSEric W. Biederman 		.proc_handler	= proc_ipc_dointvec,
227a5494dcdSEric W. Biederman 	},
2289eefe520SNadia Derbey 	{
2299eefe520SNadia Derbey 		.procname	= "auto_msgmni",
2309eefe520SNadia Derbey 		.data		= &init_ipc_ns.auto_msgmni,
2319eefe520SNadia Derbey 		.maxlen		= sizeof(int),
2329eefe520SNadia Derbey 		.mode		= 0644,
2339eefe520SNadia Derbey 		.proc_handler	= proc_ipcauto_dointvec_minmax,
2349eefe520SNadia Derbey 		.extra1		= &zero,
2359eefe520SNadia Derbey 		.extra2		= &one,
2369eefe520SNadia Derbey 	},
23703f59566SStanislav Kinsbursky #ifdef CONFIG_CHECKPOINT_RESTORE
23803f59566SStanislav Kinsbursky 	{
23903f59566SStanislav Kinsbursky 		.procname	= "sem_next_id",
24003f59566SStanislav Kinsbursky 		.data		= &init_ipc_ns.ids[IPC_SEM_IDS].next_id,
24103f59566SStanislav Kinsbursky 		.maxlen		= sizeof(init_ipc_ns.ids[IPC_SEM_IDS].next_id),
24203f59566SStanislav Kinsbursky 		.mode		= 0644,
24303f59566SStanislav Kinsbursky 		.proc_handler	= proc_ipc_dointvec_minmax,
24403f59566SStanislav Kinsbursky 		.extra1		= &zero,
24503f59566SStanislav Kinsbursky 		.extra2		= &int_max,
24603f59566SStanislav Kinsbursky 	},
24703f59566SStanislav Kinsbursky 	{
24803f59566SStanislav Kinsbursky 		.procname	= "msg_next_id",
24903f59566SStanislav Kinsbursky 		.data		= &init_ipc_ns.ids[IPC_MSG_IDS].next_id,
25003f59566SStanislav Kinsbursky 		.maxlen		= sizeof(init_ipc_ns.ids[IPC_MSG_IDS].next_id),
25103f59566SStanislav Kinsbursky 		.mode		= 0644,
25203f59566SStanislav Kinsbursky 		.proc_handler	= proc_ipc_dointvec_minmax,
25303f59566SStanislav Kinsbursky 		.extra1		= &zero,
25403f59566SStanislav Kinsbursky 		.extra2		= &int_max,
25503f59566SStanislav Kinsbursky 	},
25603f59566SStanislav Kinsbursky 	{
25703f59566SStanislav Kinsbursky 		.procname	= "shm_next_id",
25803f59566SStanislav Kinsbursky 		.data		= &init_ipc_ns.ids[IPC_SHM_IDS].next_id,
25903f59566SStanislav Kinsbursky 		.maxlen		= sizeof(init_ipc_ns.ids[IPC_SHM_IDS].next_id),
26003f59566SStanislav Kinsbursky 		.mode		= 0644,
26103f59566SStanislav Kinsbursky 		.proc_handler	= proc_ipc_dointvec_minmax,
26203f59566SStanislav Kinsbursky 		.extra1		= &zero,
26303f59566SStanislav Kinsbursky 		.extra2		= &int_max,
26403f59566SStanislav Kinsbursky 	},
26503f59566SStanislav Kinsbursky #endif
266a5494dcdSEric W. Biederman 	{}
267a5494dcdSEric W. Biederman };
268a5494dcdSEric W. Biederman 
269a5494dcdSEric W. Biederman static struct ctl_table ipc_root_table[] = {
270a5494dcdSEric W. Biederman 	{
271a5494dcdSEric W. Biederman 		.procname	= "kernel",
272a5494dcdSEric W. Biederman 		.mode		= 0555,
273a5494dcdSEric W. Biederman 		.child		= ipc_kern_table,
274a5494dcdSEric W. Biederman 	},
275a5494dcdSEric W. Biederman 	{}
276a5494dcdSEric W. Biederman };
277a5494dcdSEric W. Biederman 
278a5494dcdSEric W. Biederman static int __init ipc_sysctl_init(void)
279a5494dcdSEric W. Biederman {
2800b4d4147SEric W. Biederman 	register_sysctl_table(ipc_root_table);
281a5494dcdSEric W. Biederman 	return 0;
282a5494dcdSEric W. Biederman }
283a5494dcdSEric W. Biederman 
284*6d08a256SDavidlohr Bueso device_initcall(ipc_sysctl_init);
285