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
=
23 container_of(table
->data
, struct ipc_namespace
, shm_rmid_forced
);
26 err
= proc_dointvec_minmax(table
, write
, buffer
, lenp
, ppos
);
30 if (ns
->shm_rmid_forced
)
31 shm_destroy_orphaned(ns
);
35 static int proc_ipc_auto_msgmni(struct ctl_table
*table
, int write
,
36 void *buffer
, size_t *lenp
, loff_t
*ppos
)
38 struct ctl_table ipc_table
;
41 memcpy(&ipc_table
, table
, sizeof(ipc_table
));
42 ipc_table
.data
= &dummy
;
45 pr_info_once("writing to auto_msgmni has no effect");
47 return proc_dointvec_minmax(&ipc_table
, write
, buffer
, lenp
, ppos
);
50 static int proc_ipc_sem_dointvec(struct ctl_table
*table
, int write
,
51 void *buffer
, size_t *lenp
, loff_t
*ppos
)
53 struct ipc_namespace
*ns
=
54 container_of(table
->data
, struct ipc_namespace
, sem_ctls
);
57 semmni
= ns
->sem_ctls
[3];
58 ret
= proc_dointvec(table
, write
, buffer
, lenp
, ppos
);
61 ret
= sem_check_semmni(ns
);
64 * Reset the semmni value if an error happens.
67 ns
->sem_ctls
[3] = semmni
;
72 int ipc_mni_shift
= IPCMNI_SHIFT
;
73 int ipc_min_cycle
= RADIX_TREE_MAP_SIZE
;
75 static struct ctl_table ipc_sysctls
[] = {
78 .data
= &init_ipc_ns
.shm_ctlmax
,
79 .maxlen
= sizeof(init_ipc_ns
.shm_ctlmax
),
81 .proc_handler
= proc_doulongvec_minmax
,
85 .data
= &init_ipc_ns
.shm_ctlall
,
86 .maxlen
= sizeof(init_ipc_ns
.shm_ctlall
),
88 .proc_handler
= proc_doulongvec_minmax
,
92 .data
= &init_ipc_ns
.shm_ctlmni
,
93 .maxlen
= sizeof(init_ipc_ns
.shm_ctlmni
),
95 .proc_handler
= proc_dointvec_minmax
,
96 .extra1
= SYSCTL_ZERO
,
100 .procname
= "shm_rmid_forced",
101 .data
= &init_ipc_ns
.shm_rmid_forced
,
102 .maxlen
= sizeof(init_ipc_ns
.shm_rmid_forced
),
104 .proc_handler
= proc_ipc_dointvec_minmax_orphans
,
105 .extra1
= SYSCTL_ZERO
,
106 .extra2
= SYSCTL_ONE
,
109 .procname
= "msgmax",
110 .data
= &init_ipc_ns
.msg_ctlmax
,
111 .maxlen
= sizeof(init_ipc_ns
.msg_ctlmax
),
113 .proc_handler
= proc_dointvec_minmax
,
114 .extra1
= SYSCTL_ZERO
,
115 .extra2
= SYSCTL_INT_MAX
,
118 .procname
= "msgmni",
119 .data
= &init_ipc_ns
.msg_ctlmni
,
120 .maxlen
= sizeof(init_ipc_ns
.msg_ctlmni
),
122 .proc_handler
= proc_dointvec_minmax
,
123 .extra1
= SYSCTL_ZERO
,
127 .procname
= "auto_msgmni",
129 .maxlen
= sizeof(int),
131 .proc_handler
= proc_ipc_auto_msgmni
,
132 .extra1
= SYSCTL_ZERO
,
133 .extra2
= SYSCTL_ONE
,
136 .procname
= "msgmnb",
137 .data
= &init_ipc_ns
.msg_ctlmnb
,
138 .maxlen
= sizeof(init_ipc_ns
.msg_ctlmnb
),
140 .proc_handler
= proc_dointvec_minmax
,
141 .extra1
= SYSCTL_ZERO
,
142 .extra2
= SYSCTL_INT_MAX
,
146 .data
= &init_ipc_ns
.sem_ctls
,
147 .maxlen
= 4*sizeof(int),
149 .proc_handler
= proc_ipc_sem_dointvec
,
151 #ifdef CONFIG_CHECKPOINT_RESTORE
153 .procname
= "sem_next_id",
154 .data
= &init_ipc_ns
.ids
[IPC_SEM_IDS
].next_id
,
155 .maxlen
= sizeof(init_ipc_ns
.ids
[IPC_SEM_IDS
].next_id
),
157 .proc_handler
= proc_dointvec_minmax
,
158 .extra1
= SYSCTL_ZERO
,
159 .extra2
= SYSCTL_INT_MAX
,
162 .procname
= "msg_next_id",
163 .data
= &init_ipc_ns
.ids
[IPC_MSG_IDS
].next_id
,
164 .maxlen
= sizeof(init_ipc_ns
.ids
[IPC_MSG_IDS
].next_id
),
166 .proc_handler
= proc_dointvec_minmax
,
167 .extra1
= SYSCTL_ZERO
,
168 .extra2
= SYSCTL_INT_MAX
,
171 .procname
= "shm_next_id",
172 .data
= &init_ipc_ns
.ids
[IPC_SHM_IDS
].next_id
,
173 .maxlen
= sizeof(init_ipc_ns
.ids
[IPC_SHM_IDS
].next_id
),
175 .proc_handler
= proc_dointvec_minmax
,
176 .extra1
= SYSCTL_ZERO
,
177 .extra2
= SYSCTL_INT_MAX
,
183 static struct ctl_table_set
*set_lookup(struct ctl_table_root
*root
)
185 return ¤t
->nsproxy
->ipc_ns
->ipc_set
;
188 static int set_is_seen(struct ctl_table_set
*set
)
190 return ¤t
->nsproxy
->ipc_ns
->ipc_set
== set
;
193 static int ipc_permissions(struct ctl_table_header
*head
, struct ctl_table
*table
)
195 int mode
= table
->mode
;
197 #ifdef CONFIG_CHECKPOINT_RESTORE
198 struct ipc_namespace
*ns
= current
->nsproxy
->ipc_ns
;
200 if (((table
->data
== &ns
->ids
[IPC_SEM_IDS
].next_id
) ||
201 (table
->data
== &ns
->ids
[IPC_MSG_IDS
].next_id
) ||
202 (table
->data
== &ns
->ids
[IPC_SHM_IDS
].next_id
)) &&
203 checkpoint_restore_ns_capable(ns
->user_ns
))
209 static struct ctl_table_root set_root
= {
210 .lookup
= set_lookup
,
211 .permissions
= ipc_permissions
,
214 bool setup_ipc_sysctls(struct ipc_namespace
*ns
)
216 struct ctl_table
*tbl
;
218 setup_sysctl_set(&ns
->ipc_set
, &set_root
, set_is_seen
);
220 tbl
= kmemdup(ipc_sysctls
, sizeof(ipc_sysctls
), GFP_KERNEL
);
224 for (i
= 0; i
< ARRAY_SIZE(ipc_sysctls
); i
++) {
225 if (tbl
[i
].data
== &init_ipc_ns
.shm_ctlmax
)
226 tbl
[i
].data
= &ns
->shm_ctlmax
;
228 else if (tbl
[i
].data
== &init_ipc_ns
.shm_ctlall
)
229 tbl
[i
].data
= &ns
->shm_ctlall
;
231 else if (tbl
[i
].data
== &init_ipc_ns
.shm_ctlmni
)
232 tbl
[i
].data
= &ns
->shm_ctlmni
;
234 else if (tbl
[i
].data
== &init_ipc_ns
.shm_rmid_forced
)
235 tbl
[i
].data
= &ns
->shm_rmid_forced
;
237 else if (tbl
[i
].data
== &init_ipc_ns
.msg_ctlmax
)
238 tbl
[i
].data
= &ns
->msg_ctlmax
;
240 else if (tbl
[i
].data
== &init_ipc_ns
.msg_ctlmni
)
241 tbl
[i
].data
= &ns
->msg_ctlmni
;
243 else if (tbl
[i
].data
== &init_ipc_ns
.msg_ctlmnb
)
244 tbl
[i
].data
= &ns
->msg_ctlmnb
;
246 else if (tbl
[i
].data
== &init_ipc_ns
.sem_ctls
)
247 tbl
[i
].data
= &ns
->sem_ctls
;
248 #ifdef CONFIG_CHECKPOINT_RESTORE
249 else if (tbl
[i
].data
== &init_ipc_ns
.ids
[IPC_SEM_IDS
].next_id
)
250 tbl
[i
].data
= &ns
->ids
[IPC_SEM_IDS
].next_id
;
252 else if (tbl
[i
].data
== &init_ipc_ns
.ids
[IPC_MSG_IDS
].next_id
)
253 tbl
[i
].data
= &ns
->ids
[IPC_MSG_IDS
].next_id
;
255 else if (tbl
[i
].data
== &init_ipc_ns
.ids
[IPC_SHM_IDS
].next_id
)
256 tbl
[i
].data
= &ns
->ids
[IPC_SHM_IDS
].next_id
;
262 ns
->ipc_sysctls
= __register_sysctl_table(&ns
->ipc_set
,
264 ARRAY_SIZE(ipc_sysctls
));
266 if (!ns
->ipc_sysctls
) {
268 retire_sysctl_set(&ns
->ipc_set
);
275 void retire_ipc_sysctls(struct ipc_namespace
*ns
)
277 struct ctl_table
*tbl
;
279 tbl
= ns
->ipc_sysctls
->ctl_table_arg
;
280 unregister_sysctl_table(ns
->ipc_sysctls
);
281 retire_sysctl_set(&ns
->ipc_set
);
285 static int __init
ipc_sysctl_init(void)
287 if (!setup_ipc_sysctls(&init_ipc_ns
)) {
288 pr_warn("ipc sysctl registration failed\n");
294 device_initcall(ipc_sysctl_init
);
296 static int __init
ipc_mni_extend(char *str
)
298 ipc_mni
= IPCMNI_EXTEND
;
299 ipc_mni_shift
= IPCMNI_EXTEND_SHIFT
;
300 ipc_min_cycle
= IPCMNI_EXTEND_MIN_CYCLE
;
301 pr_info("IPCMNI extended to %d.\n", ipc_mni
);
304 early_param("ipcmni_extend", ipc_mni_extend
);