xref: /openbmc/linux/ipc/ipc_sysctl.c (revision b34a6b1da371ed8af1221459a18c67970f7e3d53)
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;
34*b34a6b1dSVasiliy 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 
41*b34a6b1dSVasiliy Kulikov static int proc_ipc_dointvec_minmax(ctl_table *table, int write,
42*b34a6b1dSVasiliy Kulikov 	void __user *buffer, size_t *lenp, loff_t *ppos)
43*b34a6b1dSVasiliy Kulikov {
44*b34a6b1dSVasiliy Kulikov 	struct ctl_table ipc_table;
45*b34a6b1dSVasiliy Kulikov 
46*b34a6b1dSVasiliy Kulikov 	memcpy(&ipc_table, table, sizeof(ipc_table));
47*b34a6b1dSVasiliy Kulikov 	ipc_table.data = get_ipc(table);
48*b34a6b1dSVasiliy Kulikov 
49*b34a6b1dSVasiliy Kulikov 	return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
50*b34a6b1dSVasiliy Kulikov }
51*b34a6b1dSVasiliy Kulikov 
52*b34a6b1dSVasiliy Kulikov static int proc_ipc_dointvec_minmax_orphans(ctl_table *table, int write,
53*b34a6b1dSVasiliy Kulikov 	void __user *buffer, size_t *lenp, loff_t *ppos)
54*b34a6b1dSVasiliy Kulikov {
55*b34a6b1dSVasiliy Kulikov 	struct ipc_namespace *ns = current->nsproxy->ipc_ns;
56*b34a6b1dSVasiliy Kulikov 	int err = proc_ipc_dointvec_minmax(table, write, buffer, lenp, ppos);
57*b34a6b1dSVasiliy Kulikov 
58*b34a6b1dSVasiliy Kulikov 	if (err < 0)
59*b34a6b1dSVasiliy Kulikov 		return err;
60*b34a6b1dSVasiliy Kulikov 	if (ns->shm_rmid_forced)
61*b34a6b1dSVasiliy Kulikov 		shm_destroy_orphaned(ns);
62*b34a6b1dSVasiliy Kulikov 	return err;
63*b34a6b1dSVasiliy Kulikov }
64*b34a6b1dSVasiliy Kulikov 
6591cfb2b4SNadia Derbey static int proc_ipc_callback_dointvec(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 
758d65af78SAlexey Dobriyan 	rc = proc_dointvec(&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
153*b34a6b1dSVasiliy Kulikov #define proc_ipc_dointvec_minmax   NULL
154*b34a6b1dSVasiliy Kulikov #define proc_ipc_dointvec_minmax_orphans   NULL
15591cfb2b4SNadia Derbey #define proc_ipc_callback_dointvec 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;
1619eefe520SNadia Derbey 
162a5494dcdSEric W. Biederman static struct ctl_table ipc_kern_table[] = {
163a5494dcdSEric W. Biederman 	{
164a5494dcdSEric W. Biederman 		.procname	= "shmmax",
165a5494dcdSEric W. Biederman 		.data		= &init_ipc_ns.shm_ctlmax,
166a5494dcdSEric W. Biederman 		.maxlen		= sizeof (init_ipc_ns.shm_ctlmax),
167a5494dcdSEric W. Biederman 		.mode		= 0644,
168a5494dcdSEric W. Biederman 		.proc_handler	= proc_ipc_doulongvec_minmax,
169a5494dcdSEric W. Biederman 	},
170a5494dcdSEric W. Biederman 	{
171a5494dcdSEric W. Biederman 		.procname	= "shmall",
172a5494dcdSEric W. Biederman 		.data		= &init_ipc_ns.shm_ctlall,
173a5494dcdSEric W. Biederman 		.maxlen		= sizeof (init_ipc_ns.shm_ctlall),
174a5494dcdSEric W. Biederman 		.mode		= 0644,
175a5494dcdSEric W. Biederman 		.proc_handler	= proc_ipc_doulongvec_minmax,
176a5494dcdSEric W. Biederman 	},
177a5494dcdSEric W. Biederman 	{
178a5494dcdSEric W. Biederman 		.procname	= "shmmni",
179a5494dcdSEric W. Biederman 		.data		= &init_ipc_ns.shm_ctlmni,
180a5494dcdSEric W. Biederman 		.maxlen		= sizeof (init_ipc_ns.shm_ctlmni),
181a5494dcdSEric W. Biederman 		.mode		= 0644,
182a5494dcdSEric W. Biederman 		.proc_handler	= proc_ipc_dointvec,
183a5494dcdSEric W. Biederman 	},
184a5494dcdSEric W. Biederman 	{
185*b34a6b1dSVasiliy Kulikov 		.procname	= "shm_rmid_forced",
186*b34a6b1dSVasiliy Kulikov 		.data		= &init_ipc_ns.shm_rmid_forced,
187*b34a6b1dSVasiliy Kulikov 		.maxlen		= sizeof(init_ipc_ns.shm_rmid_forced),
188*b34a6b1dSVasiliy Kulikov 		.mode		= 0644,
189*b34a6b1dSVasiliy Kulikov 		.proc_handler	= proc_ipc_dointvec_minmax_orphans,
190*b34a6b1dSVasiliy Kulikov 		.extra1		= &zero,
191*b34a6b1dSVasiliy Kulikov 		.extra2		= &one,
192*b34a6b1dSVasiliy Kulikov 	},
193*b34a6b1dSVasiliy Kulikov 	{
194a5494dcdSEric W. Biederman 		.procname	= "msgmax",
195a5494dcdSEric W. Biederman 		.data		= &init_ipc_ns.msg_ctlmax,
196a5494dcdSEric W. Biederman 		.maxlen		= sizeof (init_ipc_ns.msg_ctlmax),
197a5494dcdSEric W. Biederman 		.mode		= 0644,
198a5494dcdSEric W. Biederman 		.proc_handler	= proc_ipc_dointvec,
199a5494dcdSEric W. Biederman 	},
200a5494dcdSEric W. Biederman 	{
201a5494dcdSEric W. Biederman 		.procname	= "msgmni",
202a5494dcdSEric W. Biederman 		.data		= &init_ipc_ns.msg_ctlmni,
203a5494dcdSEric W. Biederman 		.maxlen		= sizeof (init_ipc_ns.msg_ctlmni),
204a5494dcdSEric W. Biederman 		.mode		= 0644,
20591cfb2b4SNadia Derbey 		.proc_handler	= proc_ipc_callback_dointvec,
206a5494dcdSEric W. Biederman 	},
207a5494dcdSEric W. Biederman 	{
208a5494dcdSEric W. Biederman 		.procname	=  "msgmnb",
209a5494dcdSEric W. Biederman 		.data		= &init_ipc_ns.msg_ctlmnb,
210a5494dcdSEric W. Biederman 		.maxlen		= sizeof (init_ipc_ns.msg_ctlmnb),
211a5494dcdSEric W. Biederman 		.mode		= 0644,
212a5494dcdSEric W. Biederman 		.proc_handler	= proc_ipc_dointvec,
213a5494dcdSEric W. Biederman 	},
214a5494dcdSEric W. Biederman 	{
215a5494dcdSEric W. Biederman 		.procname	= "sem",
216a5494dcdSEric W. Biederman 		.data		= &init_ipc_ns.sem_ctls,
217a5494dcdSEric W. Biederman 		.maxlen		= 4*sizeof (int),
218a5494dcdSEric W. Biederman 		.mode		= 0644,
219a5494dcdSEric W. Biederman 		.proc_handler	= proc_ipc_dointvec,
220a5494dcdSEric W. Biederman 	},
2219eefe520SNadia Derbey 	{
2229eefe520SNadia Derbey 		.procname	= "auto_msgmni",
2239eefe520SNadia Derbey 		.data		= &init_ipc_ns.auto_msgmni,
2249eefe520SNadia Derbey 		.maxlen		= sizeof(int),
2259eefe520SNadia Derbey 		.mode		= 0644,
2269eefe520SNadia Derbey 		.proc_handler	= proc_ipcauto_dointvec_minmax,
2279eefe520SNadia Derbey 		.extra1		= &zero,
2289eefe520SNadia Derbey 		.extra2		= &one,
2299eefe520SNadia Derbey 	},
230a5494dcdSEric W. Biederman 	{}
231a5494dcdSEric W. Biederman };
232a5494dcdSEric W. Biederman 
233a5494dcdSEric W. Biederman static struct ctl_table ipc_root_table[] = {
234a5494dcdSEric W. Biederman 	{
235a5494dcdSEric W. Biederman 		.procname	= "kernel",
236a5494dcdSEric W. Biederman 		.mode		= 0555,
237a5494dcdSEric W. Biederman 		.child		= ipc_kern_table,
238a5494dcdSEric W. Biederman 	},
239a5494dcdSEric W. Biederman 	{}
240a5494dcdSEric W. Biederman };
241a5494dcdSEric W. Biederman 
242a5494dcdSEric W. Biederman static int __init ipc_sysctl_init(void)
243a5494dcdSEric W. Biederman {
2440b4d4147SEric W. Biederman 	register_sysctl_table(ipc_root_table);
245a5494dcdSEric W. Biederman 	return 0;
246a5494dcdSEric W. Biederman }
247a5494dcdSEric W. Biederman 
248a5494dcdSEric W. Biederman __initcall(ipc_sysctl_init);
249