Linux Audio

Check our new training course

Loading...
v3.5.6
 
  1/*
  2 *  Copyright (C) 2007
  3 *
  4 *  Author: Eric Biederman <ebiederm@xmision.com>
  5 *
  6 *  This program is free software; you can redistribute it and/or
  7 *  modify it under the terms of the GNU General Public License as
  8 *  published by the Free Software Foundation, version 2 of the
  9 *  License.
 10 */
 11
 12#include <linux/module.h>
 13#include <linux/ipc.h>
 14#include <linux/nsproxy.h>
 15#include <linux/sysctl.h>
 16#include <linux/uaccess.h>
 17#include <linux/ipc_namespace.h>
 18#include <linux/msg.h>
 19#include "util.h"
 20
 21static void *get_ipc(ctl_table *table)
 22{
 23	char *which = table->data;
 24	struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
 25	which = (which - (char *)&init_ipc_ns) + (char *)ipc_ns;
 26	return which;
 27}
 28
 29#ifdef CONFIG_PROC_SYSCTL
 30static int proc_ipc_dointvec(ctl_table *table, int write,
 31	void __user *buffer, size_t *lenp, loff_t *ppos)
 32{
 33	struct ctl_table ipc_table;
 34
 35	memcpy(&ipc_table, table, sizeof(ipc_table));
 36	ipc_table.data = get_ipc(table);
 37
 38	return proc_dointvec(&ipc_table, write, buffer, lenp, ppos);
 39}
 40
 41static int proc_ipc_dointvec_minmax(ctl_table *table, int write,
 42	void __user *buffer, size_t *lenp, loff_t *ppos)
 43{
 44	struct ctl_table ipc_table;
 45
 46	memcpy(&ipc_table, table, sizeof(ipc_table));
 47	ipc_table.data = get_ipc(table);
 48
 49	return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
 50}
 51
 52static int proc_ipc_dointvec_minmax_orphans(ctl_table *table, int write,
 53	void __user *buffer, size_t *lenp, loff_t *ppos)
 54{
 55	struct ipc_namespace *ns = current->nsproxy->ipc_ns;
 56	int err = proc_ipc_dointvec_minmax(table, write, buffer, lenp, ppos);
 57
 58	if (err < 0)
 59		return err;
 60	if (ns->shm_rmid_forced)
 61		shm_destroy_orphaned(ns);
 62	return err;
 63}
 64
 65static int proc_ipc_callback_dointvec(ctl_table *table, int write,
 66	void __user *buffer, size_t *lenp, loff_t *ppos)
 67{
 68	struct ctl_table ipc_table;
 69	size_t lenp_bef = *lenp;
 70	int rc;
 71
 72	memcpy(&ipc_table, table, sizeof(ipc_table));
 73	ipc_table.data = get_ipc(table);
 74
 75	rc = proc_dointvec(&ipc_table, write, buffer, lenp, ppos);
 76
 77	if (write && !rc && lenp_bef == *lenp)
 78		/*
 79		 * Tunable has successfully been changed by hand. Disable its
 80		 * automatic adjustment. This simply requires unregistering
 81		 * the notifiers that trigger recalculation.
 82		 */
 83		unregister_ipcns_notifier(current->nsproxy->ipc_ns);
 84
 85	return rc;
 86}
 87
 88static int proc_ipc_doulongvec_minmax(ctl_table *table, int write,
 89	void __user *buffer, size_t *lenp, loff_t *ppos)
 90{
 91	struct ctl_table ipc_table;
 
 
 92	memcpy(&ipc_table, table, sizeof(ipc_table));
 93	ipc_table.data = get_ipc(table);
 94
 95	return proc_doulongvec_minmax(&ipc_table, write, buffer,
 96					lenp, ppos);
 97}
 98
 99/*
100 * Routine that is called when the file "auto_msgmni" has successfully been
101 * written.
102 * Two values are allowed:
103 * 0: unregister msgmni's callback routine from the ipc namespace notifier
104 *    chain. This means that msgmni won't be recomputed anymore upon memory
105 *    add/remove or ipc namespace creation/removal.
106 * 1: register back the callback routine.
107 */
108static void ipc_auto_callback(int val)
109{
110	if (!val)
111		unregister_ipcns_notifier(current->nsproxy->ipc_ns);
112	else {
113		/*
114		 * Re-enable automatic recomputing only if not already
115		 * enabled.
116		 */
117		recompute_msgmni(current->nsproxy->ipc_ns);
118		cond_register_ipcns_notifier(current->nsproxy->ipc_ns);
119	}
120}
121
122static int proc_ipcauto_dointvec_minmax(ctl_table *table, int write,
123	void __user *buffer, size_t *lenp, loff_t *ppos)
124{
125	struct ctl_table ipc_table;
126	size_t lenp_bef = *lenp;
127	int oldval;
128	int rc;
129
130	memcpy(&ipc_table, table, sizeof(ipc_table));
131	ipc_table.data = get_ipc(table);
132	oldval = *((int *)(ipc_table.data));
133
134	rc = proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
 
135
136	if (write && !rc && lenp_bef == *lenp) {
137		int newval = *((int *)(ipc_table.data));
138		/*
139		 * The file "auto_msgmni" has correctly been set.
140		 * React by (un)registering the corresponding tunable, if the
141		 * value has changed.
142		 */
143		if (newval != oldval)
144			ipc_auto_callback(newval);
145	}
146
147	return rc;
 
 
 
 
 
148}
149
150#else
151#define proc_ipc_doulongvec_minmax NULL
152#define proc_ipc_dointvec	   NULL
153#define proc_ipc_dointvec_minmax   NULL
154#define proc_ipc_dointvec_minmax_orphans   NULL
155#define proc_ipc_callback_dointvec NULL
156#define proc_ipcauto_dointvec_minmax NULL
157#endif
158
159static int zero;
160static int one = 1;
 
161
162static struct ctl_table ipc_kern_table[] = {
163	{
164		.procname	= "shmmax",
165		.data		= &init_ipc_ns.shm_ctlmax,
166		.maxlen		= sizeof (init_ipc_ns.shm_ctlmax),
167		.mode		= 0644,
168		.proc_handler	= proc_ipc_doulongvec_minmax,
169	},
170	{
171		.procname	= "shmall",
172		.data		= &init_ipc_ns.shm_ctlall,
173		.maxlen		= sizeof (init_ipc_ns.shm_ctlall),
174		.mode		= 0644,
175		.proc_handler	= proc_ipc_doulongvec_minmax,
176	},
177	{
178		.procname	= "shmmni",
179		.data		= &init_ipc_ns.shm_ctlmni,
180		.maxlen		= sizeof (init_ipc_ns.shm_ctlmni),
181		.mode		= 0644,
182		.proc_handler	= proc_ipc_dointvec,
 
 
183	},
184	{
185		.procname	= "shm_rmid_forced",
186		.data		= &init_ipc_ns.shm_rmid_forced,
187		.maxlen		= sizeof(init_ipc_ns.shm_rmid_forced),
188		.mode		= 0644,
189		.proc_handler	= proc_ipc_dointvec_minmax_orphans,
190		.extra1		= &zero,
191		.extra2		= &one,
192	},
193	{
194		.procname	= "msgmax",
195		.data		= &init_ipc_ns.msg_ctlmax,
196		.maxlen		= sizeof (init_ipc_ns.msg_ctlmax),
197		.mode		= 0644,
198		.proc_handler	= proc_ipc_dointvec,
 
 
199	},
200	{
201		.procname	= "msgmni",
202		.data		= &init_ipc_ns.msg_ctlmni,
203		.maxlen		= sizeof (init_ipc_ns.msg_ctlmni),
 
 
 
 
 
 
 
 
 
204		.mode		= 0644,
205		.proc_handler	= proc_ipc_callback_dointvec,
 
 
206	},
207	{
208		.procname	=  "msgmnb",
209		.data		= &init_ipc_ns.msg_ctlmnb,
210		.maxlen		= sizeof (init_ipc_ns.msg_ctlmnb),
211		.mode		= 0644,
212		.proc_handler	= proc_ipc_dointvec,
 
 
213	},
214	{
215		.procname	= "sem",
216		.data		= &init_ipc_ns.sem_ctls,
217		.maxlen		= 4*sizeof (int),
218		.mode		= 0644,
219		.proc_handler	= proc_ipc_dointvec,
220	},
 
221	{
222		.procname	= "auto_msgmni",
223		.data		= &init_ipc_ns.auto_msgmni,
224		.maxlen		= sizeof(int),
225		.mode		= 0644,
226		.proc_handler	= proc_ipcauto_dointvec_minmax,
227		.extra1		= &zero,
228		.extra2		= &one,
229	},
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230	{}
231};
232
233static struct ctl_table ipc_root_table[] = {
234	{
235		.procname	= "kernel",
236		.mode		= 0555,
237		.child		= ipc_kern_table,
238	},
239	{}
240};
241
242static int __init ipc_sysctl_init(void)
243{
244	register_sysctl_table(ipc_root_table);
245	return 0;
246}
247
248__initcall(ipc_sysctl_init);
 
 
 
 
 
 
 
 
 
 
v5.4
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 *  Copyright (C) 2007
  4 *
  5 *  Author: Eric Biederman <ebiederm@xmision.com>
 
 
 
 
 
  6 */
  7
  8#include <linux/module.h>
  9#include <linux/ipc.h>
 10#include <linux/nsproxy.h>
 11#include <linux/sysctl.h>
 12#include <linux/uaccess.h>
 13#include <linux/ipc_namespace.h>
 14#include <linux/msg.h>
 15#include "util.h"
 16
 17static void *get_ipc(struct ctl_table *table)
 18{
 19	char *which = table->data;
 20	struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
 21	which = (which - (char *)&init_ipc_ns) + (char *)ipc_ns;
 22	return which;
 23}
 24
 25#ifdef CONFIG_PROC_SYSCTL
 26static int proc_ipc_dointvec(struct ctl_table *table, int write,
 27	void __user *buffer, size_t *lenp, loff_t *ppos)
 28{
 29	struct ctl_table ipc_table;
 30
 31	memcpy(&ipc_table, table, sizeof(ipc_table));
 32	ipc_table.data = get_ipc(table);
 33
 34	return proc_dointvec(&ipc_table, write, buffer, lenp, ppos);
 35}
 36
 37static int proc_ipc_dointvec_minmax(struct ctl_table *table, int write,
 38	void __user *buffer, size_t *lenp, loff_t *ppos)
 39{
 40	struct ctl_table ipc_table;
 41
 42	memcpy(&ipc_table, table, sizeof(ipc_table));
 43	ipc_table.data = get_ipc(table);
 44
 45	return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
 46}
 47
 48static int proc_ipc_dointvec_minmax_orphans(struct ctl_table *table, int write,
 49	void __user *buffer, size_t *lenp, loff_t *ppos)
 50{
 51	struct ipc_namespace *ns = current->nsproxy->ipc_ns;
 52	int err = proc_ipc_dointvec_minmax(table, write, buffer, lenp, ppos);
 53
 54	if (err < 0)
 55		return err;
 56	if (ns->shm_rmid_forced)
 57		shm_destroy_orphaned(ns);
 58	return err;
 59}
 60
 61static int proc_ipc_doulongvec_minmax(struct ctl_table *table, int write,
 62	void __user *buffer, size_t *lenp, loff_t *ppos)
 63{
 64	struct ctl_table ipc_table;
 
 
 
 65	memcpy(&ipc_table, table, sizeof(ipc_table));
 66	ipc_table.data = get_ipc(table);
 67
 68	return proc_doulongvec_minmax(&ipc_table, write, buffer,
 69					lenp, ppos);
 
 
 
 
 
 
 
 
 
 70}
 71
 72static int proc_ipc_auto_msgmni(struct ctl_table *table, int write,
 73	void __user *buffer, size_t *lenp, loff_t *ppos)
 74{
 75	struct ctl_table ipc_table;
 76	int dummy = 0;
 77
 78	memcpy(&ipc_table, table, sizeof(ipc_table));
 79	ipc_table.data = &dummy;
 80
 81	if (write)
 82		pr_info_once("writing to auto_msgmni has no effect");
 
 83
 84	return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 85}
 86
 87static int proc_ipc_sem_dointvec(struct ctl_table *table, int write,
 88	void __user *buffer, size_t *lenp, loff_t *ppos)
 89{
 90	int ret, semmni;
 91	struct ipc_namespace *ns = current->nsproxy->ipc_ns;
 
 
 
 
 
 
 92
 93	semmni = ns->sem_ctls[3];
 94	ret = proc_ipc_dointvec(table, write, buffer, lenp, ppos);
 95
 96	if (!ret)
 97		ret = sem_check_semmni(current->nsproxy->ipc_ns);
 
 
 
 
 
 
 
 
 98
 99	/*
100	 * Reset the semmni value if an error happens.
101	 */
102	if (ret)
103		ns->sem_ctls[3] = semmni;
104	return ret;
105}
106
107#else
108#define proc_ipc_doulongvec_minmax NULL
109#define proc_ipc_dointvec	   NULL
110#define proc_ipc_dointvec_minmax   NULL
111#define proc_ipc_dointvec_minmax_orphans   NULL
112#define proc_ipc_auto_msgmni	   NULL
113#define proc_ipc_sem_dointvec	   NULL
114#endif
115
116int ipc_mni = IPCMNI;
117int ipc_mni_shift = IPCMNI_SHIFT;
118int ipc_min_cycle = RADIX_TREE_MAP_SIZE;
119
120static struct ctl_table ipc_kern_table[] = {
121	{
122		.procname	= "shmmax",
123		.data		= &init_ipc_ns.shm_ctlmax,
124		.maxlen		= sizeof(init_ipc_ns.shm_ctlmax),
125		.mode		= 0644,
126		.proc_handler	= proc_ipc_doulongvec_minmax,
127	},
128	{
129		.procname	= "shmall",
130		.data		= &init_ipc_ns.shm_ctlall,
131		.maxlen		= sizeof(init_ipc_ns.shm_ctlall),
132		.mode		= 0644,
133		.proc_handler	= proc_ipc_doulongvec_minmax,
134	},
135	{
136		.procname	= "shmmni",
137		.data		= &init_ipc_ns.shm_ctlmni,
138		.maxlen		= sizeof(init_ipc_ns.shm_ctlmni),
139		.mode		= 0644,
140		.proc_handler	= proc_ipc_dointvec_minmax,
141		.extra1		= SYSCTL_ZERO,
142		.extra2		= &ipc_mni,
143	},
144	{
145		.procname	= "shm_rmid_forced",
146		.data		= &init_ipc_ns.shm_rmid_forced,
147		.maxlen		= sizeof(init_ipc_ns.shm_rmid_forced),
148		.mode		= 0644,
149		.proc_handler	= proc_ipc_dointvec_minmax_orphans,
150		.extra1		= SYSCTL_ZERO,
151		.extra2		= SYSCTL_ONE,
152	},
153	{
154		.procname	= "msgmax",
155		.data		= &init_ipc_ns.msg_ctlmax,
156		.maxlen		= sizeof(init_ipc_ns.msg_ctlmax),
157		.mode		= 0644,
158		.proc_handler	= proc_ipc_dointvec_minmax,
159		.extra1		= SYSCTL_ZERO,
160		.extra2		= SYSCTL_INT_MAX,
161	},
162	{
163		.procname	= "msgmni",
164		.data		= &init_ipc_ns.msg_ctlmni,
165		.maxlen		= sizeof(init_ipc_ns.msg_ctlmni),
166		.mode		= 0644,
167		.proc_handler	= proc_ipc_dointvec_minmax,
168		.extra1		= SYSCTL_ZERO,
169		.extra2		= &ipc_mni,
170	},
171	{
172		.procname	= "auto_msgmni",
173		.data		= NULL,
174		.maxlen		= sizeof(int),
175		.mode		= 0644,
176		.proc_handler	= proc_ipc_auto_msgmni,
177		.extra1		= SYSCTL_ZERO,
178		.extra2		= SYSCTL_ONE,
179	},
180	{
181		.procname	=  "msgmnb",
182		.data		= &init_ipc_ns.msg_ctlmnb,
183		.maxlen		= sizeof(init_ipc_ns.msg_ctlmnb),
184		.mode		= 0644,
185		.proc_handler	= proc_ipc_dointvec_minmax,
186		.extra1		= SYSCTL_ZERO,
187		.extra2		= SYSCTL_INT_MAX,
188	},
189	{
190		.procname	= "sem",
191		.data		= &init_ipc_ns.sem_ctls,
192		.maxlen		= 4*sizeof(int),
193		.mode		= 0644,
194		.proc_handler	= proc_ipc_sem_dointvec,
195	},
196#ifdef CONFIG_CHECKPOINT_RESTORE
197	{
198		.procname	= "sem_next_id",
199		.data		= &init_ipc_ns.ids[IPC_SEM_IDS].next_id,
200		.maxlen		= sizeof(init_ipc_ns.ids[IPC_SEM_IDS].next_id),
201		.mode		= 0644,
202		.proc_handler	= proc_ipc_dointvec_minmax,
203		.extra1		= SYSCTL_ZERO,
204		.extra2		= SYSCTL_INT_MAX,
205	},
206	{
207		.procname	= "msg_next_id",
208		.data		= &init_ipc_ns.ids[IPC_MSG_IDS].next_id,
209		.maxlen		= sizeof(init_ipc_ns.ids[IPC_MSG_IDS].next_id),
210		.mode		= 0644,
211		.proc_handler	= proc_ipc_dointvec_minmax,
212		.extra1		= SYSCTL_ZERO,
213		.extra2		= SYSCTL_INT_MAX,
214	},
215	{
216		.procname	= "shm_next_id",
217		.data		= &init_ipc_ns.ids[IPC_SHM_IDS].next_id,
218		.maxlen		= sizeof(init_ipc_ns.ids[IPC_SHM_IDS].next_id),
219		.mode		= 0644,
220		.proc_handler	= proc_ipc_dointvec_minmax,
221		.extra1		= SYSCTL_ZERO,
222		.extra2		= SYSCTL_INT_MAX,
223	},
224#endif
225	{}
226};
227
228static struct ctl_table ipc_root_table[] = {
229	{
230		.procname	= "kernel",
231		.mode		= 0555,
232		.child		= ipc_kern_table,
233	},
234	{}
235};
236
237static int __init ipc_sysctl_init(void)
238{
239	register_sysctl_table(ipc_root_table);
240	return 0;
241}
242
243device_initcall(ipc_sysctl_init);
244
245static int __init ipc_mni_extend(char *str)
246{
247	ipc_mni = IPCMNI_EXTEND;
248	ipc_mni_shift = IPCMNI_EXTEND_SHIFT;
249	ipc_min_cycle = IPCMNI_EXTEND_MIN_CYCLE;
250	pr_info("IPCMNI extended to %d.\n", ipc_mni);
251	return 0;
252}
253early_param("ipcmni_extend", ipc_mni_extend);