1 // SPDX-License-Identifier: GPL-2.0-only
5 * Author: Eric Biederman <ebiederm@xmision.com>
8 #include <linux/module.h>
10 #include <linux/nsproxy.h>
11 #include <linux/sysctl.h>
12 #include <linux/uaccess.h>
13 #include <linux/capability.h>
14 #include <linux/ipc_namespace.h>
15 #include <linux/msg.h>
16 #include <linux/slab.h>
19 static int proc_ipc_dointvec_minmax_orphans(struct ctl_table *table, int write,
20 void *buffer, size_t *lenp, loff_t *ppos)
22 struct ipc_namespace *ns = table->extra1;
23 struct ctl_table ipc_table;
26 memcpy(&ipc_table, table, sizeof(ipc_table));
28 ipc_table.extra1 = SYSCTL_ZERO;
29 ipc_table.extra2 = SYSCTL_ONE;
31 err = proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
35 if (ns->shm_rmid_forced)
36 shm_destroy_orphaned(ns);
40 static int proc_ipc_auto_msgmni(struct ctl_table *table, int write,
41 void *buffer, size_t *lenp, loff_t *ppos)
43 struct ctl_table ipc_table;
46 memcpy(&ipc_table, table, sizeof(ipc_table));
47 ipc_table.data = &dummy;
50 pr_info_once("writing to auto_msgmni has no effect");
52 return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
55 static int proc_ipc_sem_dointvec(struct ctl_table *table, int write,
56 void *buffer, size_t *lenp, loff_t *ppos)
58 struct ipc_namespace *ns = table->extra1;
59 struct ctl_table ipc_table;
62 memcpy(&ipc_table, table, sizeof(ipc_table));
64 ipc_table.extra1 = NULL;
65 ipc_table.extra2 = NULL;
67 semmni = ns->sem_ctls[3];
68 ret = proc_dointvec(table, write, buffer, lenp, ppos);
71 ret = sem_check_semmni(current->nsproxy->ipc_ns);
74 * Reset the semmni value if an error happens.
77 ns->sem_ctls[3] = semmni;
81 #ifdef CONFIG_CHECKPOINT_RESTORE
82 static int proc_ipc_dointvec_minmax_checkpoint_restore(struct ctl_table *table,
83 int write, void *buffer, size_t *lenp, loff_t *ppos)
85 struct ipc_namespace *ns = table->extra1;
86 struct ctl_table ipc_table;
88 if (write && !checkpoint_restore_ns_capable(ns->user_ns))
91 memcpy(&ipc_table, table, sizeof(ipc_table));
93 ipc_table.extra1 = SYSCTL_ZERO;
94 ipc_table.extra2 = SYSCTL_INT_MAX;
96 return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
100 int ipc_mni = IPCMNI;
101 int ipc_mni_shift = IPCMNI_SHIFT;
102 int ipc_min_cycle = RADIX_TREE_MAP_SIZE;
104 static struct ctl_table ipc_sysctls[] = {
106 .procname = "shmmax",
107 .data = &init_ipc_ns.shm_ctlmax,
108 .maxlen = sizeof(init_ipc_ns.shm_ctlmax),
110 .proc_handler = proc_doulongvec_minmax,
113 .procname = "shmall",
114 .data = &init_ipc_ns.shm_ctlall,
115 .maxlen = sizeof(init_ipc_ns.shm_ctlall),
117 .proc_handler = proc_doulongvec_minmax,
120 .procname = "shmmni",
121 .data = &init_ipc_ns.shm_ctlmni,
122 .maxlen = sizeof(init_ipc_ns.shm_ctlmni),
124 .proc_handler = proc_dointvec_minmax,
125 .extra1 = SYSCTL_ZERO,
129 .procname = "shm_rmid_forced",
130 .data = &init_ipc_ns.shm_rmid_forced,
131 .maxlen = sizeof(init_ipc_ns.shm_rmid_forced),
133 .proc_handler = proc_ipc_dointvec_minmax_orphans,
136 .procname = "msgmax",
137 .data = &init_ipc_ns.msg_ctlmax,
138 .maxlen = sizeof(init_ipc_ns.msg_ctlmax),
140 .proc_handler = proc_dointvec_minmax,
141 .extra1 = SYSCTL_ZERO,
142 .extra2 = SYSCTL_INT_MAX,
145 .procname = "msgmni",
146 .data = &init_ipc_ns.msg_ctlmni,
147 .maxlen = sizeof(init_ipc_ns.msg_ctlmni),
149 .proc_handler = proc_dointvec_minmax,
150 .extra1 = SYSCTL_ZERO,
154 .procname = "auto_msgmni",
156 .maxlen = sizeof(int),
158 .proc_handler = proc_ipc_auto_msgmni,
159 .extra1 = SYSCTL_ZERO,
160 .extra2 = SYSCTL_ONE,
163 .procname = "msgmnb",
164 .data = &init_ipc_ns.msg_ctlmnb,
165 .maxlen = sizeof(init_ipc_ns.msg_ctlmnb),
167 .proc_handler = proc_dointvec_minmax,
168 .extra1 = SYSCTL_ZERO,
169 .extra2 = SYSCTL_INT_MAX,
173 .data = &init_ipc_ns.sem_ctls,
174 .maxlen = 4*sizeof(int),
176 .proc_handler = proc_ipc_sem_dointvec,
178 #ifdef CONFIG_CHECKPOINT_RESTORE
180 .procname = "sem_next_id",
181 .data = &init_ipc_ns.ids[IPC_SEM_IDS].next_id,
182 .maxlen = sizeof(init_ipc_ns.ids[IPC_SEM_IDS].next_id),
184 .proc_handler = proc_ipc_dointvec_minmax_checkpoint_restore,
187 .procname = "msg_next_id",
188 .data = &init_ipc_ns.ids[IPC_MSG_IDS].next_id,
189 .maxlen = sizeof(init_ipc_ns.ids[IPC_MSG_IDS].next_id),
191 .proc_handler = proc_ipc_dointvec_minmax_checkpoint_restore,
194 .procname = "shm_next_id",
195 .data = &init_ipc_ns.ids[IPC_SHM_IDS].next_id,
196 .maxlen = sizeof(init_ipc_ns.ids[IPC_SHM_IDS].next_id),
198 .proc_handler = proc_ipc_dointvec_minmax_checkpoint_restore,
204 static struct ctl_table_set *set_lookup(struct ctl_table_root *root)
206 return ¤t->nsproxy->ipc_ns->ipc_set;
209 static int set_is_seen(struct ctl_table_set *set)
211 return ¤t->nsproxy->ipc_ns->ipc_set == set;
214 static struct ctl_table_root set_root = {
215 .lookup = set_lookup,
218 bool setup_ipc_sysctls(struct ipc_namespace *ns)
220 struct ctl_table *tbl;
222 setup_sysctl_set(&ns->ipc_set, &set_root, set_is_seen);
224 tbl = kmemdup(ipc_sysctls, sizeof(ipc_sysctls), GFP_KERNEL);
228 for (i = 0; i < ARRAY_SIZE(ipc_sysctls); i++) {
229 if (tbl[i].data == &init_ipc_ns.shm_ctlmax) {
230 tbl[i].data = &ns->shm_ctlmax;
232 } else if (tbl[i].data == &init_ipc_ns.shm_ctlall) {
233 tbl[i].data = &ns->shm_ctlall;
235 } else if (tbl[i].data == &init_ipc_ns.shm_ctlmni) {
236 tbl[i].data = &ns->shm_ctlmni;
238 } else if (tbl[i].data == &init_ipc_ns.shm_rmid_forced) {
239 tbl[i].data = &ns->shm_rmid_forced;
242 } else if (tbl[i].data == &init_ipc_ns.msg_ctlmax) {
243 tbl[i].data = &ns->msg_ctlmax;
245 } else if (tbl[i].data == &init_ipc_ns.msg_ctlmni) {
246 tbl[i].data = &ns->msg_ctlmni;
248 } else if (tbl[i].data == &init_ipc_ns.msg_ctlmnb) {
249 tbl[i].data = &ns->msg_ctlmnb;
251 } else if (tbl[i].data == &init_ipc_ns.sem_ctls) {
252 tbl[i].data = &ns->sem_ctls;
254 #ifdef CONFIG_CHECKPOINT_RESTORE
255 } else if (tbl[i].data == &init_ipc_ns.ids[IPC_SEM_IDS].next_id) {
256 tbl[i].data = &ns->ids[IPC_SEM_IDS].next_id;
259 } else if (tbl[i].data == &init_ipc_ns.ids[IPC_MSG_IDS].next_id) {
260 tbl[i].data = &ns->ids[IPC_MSG_IDS].next_id;
263 } else if (tbl[i].data == &init_ipc_ns.ids[IPC_SHM_IDS].next_id) {
264 tbl[i].data = &ns->ids[IPC_SHM_IDS].next_id;
272 ns->ipc_sysctls = __register_sysctl_table(&ns->ipc_set, "kernel", tbl);
274 if (!ns->ipc_sysctls) {
276 retire_sysctl_set(&ns->ipc_set);
283 void retire_ipc_sysctls(struct ipc_namespace *ns)
285 struct ctl_table *tbl;
287 tbl = ns->ipc_sysctls->ctl_table_arg;
288 unregister_sysctl_table(ns->ipc_sysctls);
289 retire_sysctl_set(&ns->ipc_set);
293 static int __init ipc_sysctl_init(void)
295 if (!setup_ipc_sysctls(&init_ipc_ns)) {
296 pr_warn("ipc sysctl registration failed\n");
302 device_initcall(ipc_sysctl_init);
304 static int __init ipc_mni_extend(char *str)
306 ipc_mni = IPCMNI_EXTEND;
307 ipc_mni_shift = IPCMNI_EXTEND_SHIFT;
308 ipc_min_cycle = IPCMNI_EXTEND_MIN_CYCLE;
309 pr_info("IPCMNI extended to %d.\n", ipc_mni);
312 early_param("ipcmni_extend", ipc_mni_extend);