4 * Author: Eric Biederman <ebiederm@xmision.com>
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
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>
21 static void *get_ipc(ctl_table
*table
)
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
;
30 * Routine that is called when a tunable has successfully been changed by
31 * hand and it has a callback routine registered on the ipc namespace notifier
32 * chain: we don't want such tunables to be recomputed anymore upon memory
33 * add/remove or ipc namespace creation/removal.
34 * They can come back to a recomputable state by being set to a <0 value.
36 static void tunable_set_callback(int val
)
39 unregister_ipcns_notifier(current
->nsproxy
->ipc_ns
);
42 * Re-enable automatic recomputing only if not already
45 recompute_msgmni(current
->nsproxy
->ipc_ns
);
46 cond_register_ipcns_notifier(current
->nsproxy
->ipc_ns
);
51 static int proc_ipc_dointvec(ctl_table
*table
, int write
, struct file
*filp
,
52 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
54 struct ctl_table ipc_table
;
55 memcpy(&ipc_table
, table
, sizeof(ipc_table
));
56 ipc_table
.data
= get_ipc(table
);
58 return proc_dointvec(&ipc_table
, write
, filp
, buffer
, lenp
, ppos
);
61 static int proc_ipc_callback_dointvec(ctl_table
*table
, int write
,
62 struct file
*filp
, void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
64 struct ctl_table ipc_table
;
65 size_t lenp_bef
= *lenp
;
68 memcpy(&ipc_table
, table
, sizeof(ipc_table
));
69 ipc_table
.data
= get_ipc(table
);
71 rc
= proc_dointvec(&ipc_table
, write
, filp
, buffer
, lenp
, ppos
);
73 if (write
&& !rc
&& lenp_bef
== *lenp
)
74 tunable_set_callback(*((int *)(ipc_table
.data
)));
79 static int proc_ipc_doulongvec_minmax(ctl_table
*table
, int write
,
80 struct file
*filp
, void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
82 struct ctl_table ipc_table
;
83 memcpy(&ipc_table
, table
, sizeof(ipc_table
));
84 ipc_table
.data
= get_ipc(table
);
86 return proc_doulongvec_minmax(&ipc_table
, write
, filp
, buffer
,
91 #define proc_ipc_doulongvec_minmax NULL
92 #define proc_ipc_dointvec NULL
93 #define proc_ipc_callback_dointvec NULL
96 #ifdef CONFIG_SYSCTL_SYSCALL
97 /* The generic sysctl ipc data routine. */
98 static int sysctl_ipc_data(ctl_table
*table
, int __user
*name
, int nlen
,
99 void __user
*oldval
, size_t __user
*oldlenp
,
100 void __user
*newval
, size_t newlen
)
105 /* Get out of I don't have a variable */
106 if (!table
->data
|| !table
->maxlen
)
109 data
= get_ipc(table
);
113 if (oldval
&& oldlenp
) {
114 if (get_user(len
, oldlenp
))
117 if (len
> table
->maxlen
)
119 if (copy_to_user(oldval
, data
, len
))
121 if (put_user(len
, oldlenp
))
126 if (newval
&& newlen
) {
127 if (newlen
> table
->maxlen
)
128 newlen
= table
->maxlen
;
130 if (copy_from_user(data
, newval
, newlen
))
136 static int sysctl_ipc_registered_data(ctl_table
*table
, int __user
*name
,
137 int nlen
, void __user
*oldval
, size_t __user
*oldlenp
,
138 void __user
*newval
, size_t newlen
)
142 rc
= sysctl_ipc_data(table
, name
, nlen
, oldval
, oldlenp
, newval
,
145 if (newval
&& newlen
&& rc
> 0) {
147 * Tunable has successfully been changed from userland
149 int *data
= get_ipc(table
);
151 tunable_set_callback(*data
);
157 #define sysctl_ipc_data NULL
158 #define sysctl_ipc_registered_data NULL
161 static struct ctl_table ipc_kern_table
[] = {
163 .ctl_name
= KERN_SHMMAX
,
164 .procname
= "shmmax",
165 .data
= &init_ipc_ns
.shm_ctlmax
,
166 .maxlen
= sizeof (init_ipc_ns
.shm_ctlmax
),
168 .proc_handler
= proc_ipc_doulongvec_minmax
,
169 .strategy
= sysctl_ipc_data
,
172 .ctl_name
= KERN_SHMALL
,
173 .procname
= "shmall",
174 .data
= &init_ipc_ns
.shm_ctlall
,
175 .maxlen
= sizeof (init_ipc_ns
.shm_ctlall
),
177 .proc_handler
= proc_ipc_doulongvec_minmax
,
178 .strategy
= sysctl_ipc_data
,
181 .ctl_name
= KERN_SHMMNI
,
182 .procname
= "shmmni",
183 .data
= &init_ipc_ns
.shm_ctlmni
,
184 .maxlen
= sizeof (init_ipc_ns
.shm_ctlmni
),
186 .proc_handler
= proc_ipc_dointvec
,
187 .strategy
= sysctl_ipc_data
,
190 .ctl_name
= KERN_MSGMAX
,
191 .procname
= "msgmax",
192 .data
= &init_ipc_ns
.msg_ctlmax
,
193 .maxlen
= sizeof (init_ipc_ns
.msg_ctlmax
),
195 .proc_handler
= proc_ipc_dointvec
,
196 .strategy
= sysctl_ipc_data
,
199 .ctl_name
= KERN_MSGMNI
,
200 .procname
= "msgmni",
201 .data
= &init_ipc_ns
.msg_ctlmni
,
202 .maxlen
= sizeof (init_ipc_ns
.msg_ctlmni
),
204 .proc_handler
= proc_ipc_callback_dointvec
,
205 .strategy
= sysctl_ipc_registered_data
,
208 .ctl_name
= KERN_MSGMNB
,
209 .procname
= "msgmnb",
210 .data
= &init_ipc_ns
.msg_ctlmnb
,
211 .maxlen
= sizeof (init_ipc_ns
.msg_ctlmnb
),
213 .proc_handler
= proc_ipc_dointvec
,
214 .strategy
= sysctl_ipc_data
,
217 .ctl_name
= KERN_SEM
,
219 .data
= &init_ipc_ns
.sem_ctls
,
220 .maxlen
= 4*sizeof (int),
222 .proc_handler
= proc_ipc_dointvec
,
223 .strategy
= sysctl_ipc_data
,
228 static struct ctl_table ipc_root_table
[] = {
230 .ctl_name
= CTL_KERN
,
231 .procname
= "kernel",
233 .child
= ipc_kern_table
,
238 static int __init
ipc_sysctl_init(void)
240 register_sysctl_table(ipc_root_table
);
244 __initcall(ipc_sysctl_init
);