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>
17 #include <linux/cred.h>
20 static int proc_ipc_dointvec_minmax_orphans(struct ctl_table
*table
, int write
,
21 void *buffer
, size_t *lenp
, loff_t
*ppos
)
23 struct ipc_namespace
*ns
=
24 container_of(table
->data
, struct ipc_namespace
, shm_rmid_forced
);
27 err
= proc_dointvec_minmax(table
, write
, buffer
, lenp
, ppos
);
31 if (ns
->shm_rmid_forced
)
32 shm_destroy_orphaned(ns
);
36 static int proc_ipc_auto_msgmni(struct ctl_table
*table
, int write
,
37 void *buffer
, size_t *lenp
, loff_t
*ppos
)
39 struct ctl_table ipc_table
;
42 memcpy(&ipc_table
, table
, sizeof(ipc_table
));
43 ipc_table
.data
= &dummy
;
46 pr_info_once("writing to auto_msgmni has no effect");
48 return proc_dointvec_minmax(&ipc_table
, write
, buffer
, lenp
, ppos
);
51 static int proc_ipc_sem_dointvec(struct ctl_table
*table
, int write
,
52 void *buffer
, size_t *lenp
, loff_t
*ppos
)
54 struct ipc_namespace
*ns
=
55 container_of(table
->data
, struct ipc_namespace
, sem_ctls
);
58 semmni
= ns
->sem_ctls
[3];
59 ret
= proc_dointvec(table
, write
, buffer
, lenp
, ppos
);
62 ret
= sem_check_semmni(ns
);
65 * Reset the semmni value if an error happens.
68 ns
->sem_ctls
[3] = semmni
;
73 int ipc_mni_shift
= IPCMNI_SHIFT
;
74 int ipc_min_cycle
= RADIX_TREE_MAP_SIZE
;
76 static struct ctl_table ipc_sysctls
[] = {
79 .data
= &init_ipc_ns
.shm_ctlmax
,
80 .maxlen
= sizeof(init_ipc_ns
.shm_ctlmax
),
82 .proc_handler
= proc_doulongvec_minmax
,
86 .data
= &init_ipc_ns
.shm_ctlall
,
87 .maxlen
= sizeof(init_ipc_ns
.shm_ctlall
),
89 .proc_handler
= proc_doulongvec_minmax
,
93 .data
= &init_ipc_ns
.shm_ctlmni
,
94 .maxlen
= sizeof(init_ipc_ns
.shm_ctlmni
),
96 .proc_handler
= proc_dointvec_minmax
,
97 .extra1
= SYSCTL_ZERO
,
101 .procname
= "shm_rmid_forced",
102 .data
= &init_ipc_ns
.shm_rmid_forced
,
103 .maxlen
= sizeof(init_ipc_ns
.shm_rmid_forced
),
105 .proc_handler
= proc_ipc_dointvec_minmax_orphans
,
106 .extra1
= SYSCTL_ZERO
,
107 .extra2
= SYSCTL_ONE
,
110 .procname
= "msgmax",
111 .data
= &init_ipc_ns
.msg_ctlmax
,
112 .maxlen
= sizeof(init_ipc_ns
.msg_ctlmax
),
114 .proc_handler
= proc_dointvec_minmax
,
115 .extra1
= SYSCTL_ZERO
,
116 .extra2
= SYSCTL_INT_MAX
,
119 .procname
= "msgmni",
120 .data
= &init_ipc_ns
.msg_ctlmni
,
121 .maxlen
= sizeof(init_ipc_ns
.msg_ctlmni
),
123 .proc_handler
= proc_dointvec_minmax
,
124 .extra1
= SYSCTL_ZERO
,
128 .procname
= "auto_msgmni",
130 .maxlen
= sizeof(int),
132 .proc_handler
= proc_ipc_auto_msgmni
,
133 .extra1
= SYSCTL_ZERO
,
134 .extra2
= SYSCTL_ONE
,
137 .procname
= "msgmnb",
138 .data
= &init_ipc_ns
.msg_ctlmnb
,
139 .maxlen
= sizeof(init_ipc_ns
.msg_ctlmnb
),
141 .proc_handler
= proc_dointvec_minmax
,
142 .extra1
= SYSCTL_ZERO
,
143 .extra2
= SYSCTL_INT_MAX
,
147 .data
= &init_ipc_ns
.sem_ctls
,
148 .maxlen
= 4*sizeof(int),
150 .proc_handler
= proc_ipc_sem_dointvec
,
152 #ifdef CONFIG_CHECKPOINT_RESTORE
154 .procname
= "sem_next_id",
155 .data
= &init_ipc_ns
.ids
[IPC_SEM_IDS
].next_id
,
156 .maxlen
= sizeof(init_ipc_ns
.ids
[IPC_SEM_IDS
].next_id
),
158 .proc_handler
= proc_dointvec_minmax
,
159 .extra1
= SYSCTL_ZERO
,
160 .extra2
= SYSCTL_INT_MAX
,
163 .procname
= "msg_next_id",
164 .data
= &init_ipc_ns
.ids
[IPC_MSG_IDS
].next_id
,
165 .maxlen
= sizeof(init_ipc_ns
.ids
[IPC_MSG_IDS
].next_id
),
167 .proc_handler
= proc_dointvec_minmax
,
168 .extra1
= SYSCTL_ZERO
,
169 .extra2
= SYSCTL_INT_MAX
,
172 .procname
= "shm_next_id",
173 .data
= &init_ipc_ns
.ids
[IPC_SHM_IDS
].next_id
,
174 .maxlen
= sizeof(init_ipc_ns
.ids
[IPC_SHM_IDS
].next_id
),
176 .proc_handler
= proc_dointvec_minmax
,
177 .extra1
= SYSCTL_ZERO
,
178 .extra2
= SYSCTL_INT_MAX
,
184 static struct ctl_table_set
*set_lookup(struct ctl_table_root
*root
)
186 return ¤t
->nsproxy
->ipc_ns
->ipc_set
;
189 static int set_is_seen(struct ctl_table_set
*set
)
191 return ¤t
->nsproxy
->ipc_ns
->ipc_set
== set
;
194 static void ipc_set_ownership(struct ctl_table_header
*head
,
195 struct ctl_table
*table
,
196 kuid_t
*uid
, kgid_t
*gid
)
198 struct ipc_namespace
*ns
=
199 container_of(head
->set
, struct ipc_namespace
, ipc_set
);
201 kuid_t ns_root_uid
= make_kuid(ns
->user_ns
, 0);
202 kgid_t ns_root_gid
= make_kgid(ns
->user_ns
, 0);
204 *uid
= uid_valid(ns_root_uid
) ? ns_root_uid
: GLOBAL_ROOT_UID
;
205 *gid
= gid_valid(ns_root_gid
) ? ns_root_gid
: GLOBAL_ROOT_GID
;
208 static int ipc_permissions(struct ctl_table_header
*head
, struct ctl_table
*table
)
210 int mode
= table
->mode
;
212 #ifdef CONFIG_CHECKPOINT_RESTORE
213 struct ipc_namespace
*ns
=
214 container_of(head
->set
, struct ipc_namespace
, ipc_set
);
216 if (((table
->data
== &ns
->ids
[IPC_SEM_IDS
].next_id
) ||
217 (table
->data
== &ns
->ids
[IPC_MSG_IDS
].next_id
) ||
218 (table
->data
== &ns
->ids
[IPC_SHM_IDS
].next_id
)) &&
219 checkpoint_restore_ns_capable(ns
->user_ns
))
227 ipc_set_ownership(head
, table
, &ns_root_uid
, &ns_root_gid
);
229 if (uid_eq(current_euid(), ns_root_uid
))
232 else if (in_egroup_p(ns_root_gid
))
238 return (mode
<< 6) | (mode
<< 3) | mode
;
241 static struct ctl_table_root set_root
= {
242 .lookup
= set_lookup
,
243 .permissions
= ipc_permissions
,
244 .set_ownership
= ipc_set_ownership
,
247 bool setup_ipc_sysctls(struct ipc_namespace
*ns
)
249 struct ctl_table
*tbl
;
251 setup_sysctl_set(&ns
->ipc_set
, &set_root
, set_is_seen
);
253 tbl
= kmemdup(ipc_sysctls
, sizeof(ipc_sysctls
), GFP_KERNEL
);
257 for (i
= 0; i
< ARRAY_SIZE(ipc_sysctls
); i
++) {
258 if (tbl
[i
].data
== &init_ipc_ns
.shm_ctlmax
)
259 tbl
[i
].data
= &ns
->shm_ctlmax
;
261 else if (tbl
[i
].data
== &init_ipc_ns
.shm_ctlall
)
262 tbl
[i
].data
= &ns
->shm_ctlall
;
264 else if (tbl
[i
].data
== &init_ipc_ns
.shm_ctlmni
)
265 tbl
[i
].data
= &ns
->shm_ctlmni
;
267 else if (tbl
[i
].data
== &init_ipc_ns
.shm_rmid_forced
)
268 tbl
[i
].data
= &ns
->shm_rmid_forced
;
270 else if (tbl
[i
].data
== &init_ipc_ns
.msg_ctlmax
)
271 tbl
[i
].data
= &ns
->msg_ctlmax
;
273 else if (tbl
[i
].data
== &init_ipc_ns
.msg_ctlmni
)
274 tbl
[i
].data
= &ns
->msg_ctlmni
;
276 else if (tbl
[i
].data
== &init_ipc_ns
.msg_ctlmnb
)
277 tbl
[i
].data
= &ns
->msg_ctlmnb
;
279 else if (tbl
[i
].data
== &init_ipc_ns
.sem_ctls
)
280 tbl
[i
].data
= &ns
->sem_ctls
;
281 #ifdef CONFIG_CHECKPOINT_RESTORE
282 else if (tbl
[i
].data
== &init_ipc_ns
.ids
[IPC_SEM_IDS
].next_id
)
283 tbl
[i
].data
= &ns
->ids
[IPC_SEM_IDS
].next_id
;
285 else if (tbl
[i
].data
== &init_ipc_ns
.ids
[IPC_MSG_IDS
].next_id
)
286 tbl
[i
].data
= &ns
->ids
[IPC_MSG_IDS
].next_id
;
288 else if (tbl
[i
].data
== &init_ipc_ns
.ids
[IPC_SHM_IDS
].next_id
)
289 tbl
[i
].data
= &ns
->ids
[IPC_SHM_IDS
].next_id
;
295 ns
->ipc_sysctls
= __register_sysctl_table(&ns
->ipc_set
, "kernel", tbl
,
296 ARRAY_SIZE(ipc_sysctls
));
298 if (!ns
->ipc_sysctls
) {
300 retire_sysctl_set(&ns
->ipc_set
);
307 void retire_ipc_sysctls(struct ipc_namespace
*ns
)
309 struct ctl_table
*tbl
;
311 tbl
= ns
->ipc_sysctls
->ctl_table_arg
;
312 unregister_sysctl_table(ns
->ipc_sysctls
);
313 retire_sysctl_set(&ns
->ipc_set
);
317 static int __init
ipc_sysctl_init(void)
319 if (!setup_ipc_sysctls(&init_ipc_ns
)) {
320 pr_warn("ipc sysctl registration failed\n");
326 device_initcall(ipc_sysctl_init
);
328 static int __init
ipc_mni_extend(char *str
)
330 ipc_mni
= IPCMNI_EXTEND
;
331 ipc_mni_shift
= IPCMNI_EXTEND_SHIFT
;
332 ipc_min_cycle
= IPCMNI_EXTEND_MIN_CYCLE
;
333 pr_info("IPCMNI extended to %d.\n", ipc_mni
);
336 early_param("ipcmni_extend", ipc_mni_extend
);