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
,
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 void ipc_set_ownership(struct ctl_table_header
*head
,
194 kuid_t
*uid
, kgid_t
*gid
)
196 struct ipc_namespace
*ns
=
197 container_of(head
->set
, struct ipc_namespace
, ipc_set
);
199 kuid_t ns_root_uid
= make_kuid(ns
->user_ns
, 0);
200 kgid_t ns_root_gid
= make_kgid(ns
->user_ns
, 0);
202 *uid
= uid_valid(ns_root_uid
) ? ns_root_uid
: GLOBAL_ROOT_UID
;
203 *gid
= gid_valid(ns_root_gid
) ? ns_root_gid
: GLOBAL_ROOT_GID
;
206 static int ipc_permissions(struct ctl_table_header
*head
, const struct ctl_table
*table
)
208 int mode
= table
->mode
;
210 #ifdef CONFIG_CHECKPOINT_RESTORE
211 struct ipc_namespace
*ns
=
212 container_of(head
->set
, struct ipc_namespace
, ipc_set
);
214 if (((table
->data
== &ns
->ids
[IPC_SEM_IDS
].next_id
) ||
215 (table
->data
== &ns
->ids
[IPC_MSG_IDS
].next_id
) ||
216 (table
->data
== &ns
->ids
[IPC_SHM_IDS
].next_id
)) &&
217 checkpoint_restore_ns_capable(ns
->user_ns
))
225 ipc_set_ownership(head
, &ns_root_uid
, &ns_root_gid
);
227 if (uid_eq(current_euid(), ns_root_uid
))
230 else if (in_egroup_p(ns_root_gid
))
236 return (mode
<< 6) | (mode
<< 3) | mode
;
239 static struct ctl_table_root set_root
= {
240 .lookup
= set_lookup
,
241 .permissions
= ipc_permissions
,
242 .set_ownership
= ipc_set_ownership
,
245 bool setup_ipc_sysctls(struct ipc_namespace
*ns
)
247 struct ctl_table
*tbl
;
249 setup_sysctl_set(&ns
->ipc_set
, &set_root
, set_is_seen
);
251 tbl
= kmemdup(ipc_sysctls
, sizeof(ipc_sysctls
), GFP_KERNEL
);
255 for (i
= 0; i
< ARRAY_SIZE(ipc_sysctls
); i
++) {
256 if (tbl
[i
].data
== &init_ipc_ns
.shm_ctlmax
)
257 tbl
[i
].data
= &ns
->shm_ctlmax
;
259 else if (tbl
[i
].data
== &init_ipc_ns
.shm_ctlall
)
260 tbl
[i
].data
= &ns
->shm_ctlall
;
262 else if (tbl
[i
].data
== &init_ipc_ns
.shm_ctlmni
)
263 tbl
[i
].data
= &ns
->shm_ctlmni
;
265 else if (tbl
[i
].data
== &init_ipc_ns
.shm_rmid_forced
)
266 tbl
[i
].data
= &ns
->shm_rmid_forced
;
268 else if (tbl
[i
].data
== &init_ipc_ns
.msg_ctlmax
)
269 tbl
[i
].data
= &ns
->msg_ctlmax
;
271 else if (tbl
[i
].data
== &init_ipc_ns
.msg_ctlmni
)
272 tbl
[i
].data
= &ns
->msg_ctlmni
;
274 else if (tbl
[i
].data
== &init_ipc_ns
.msg_ctlmnb
)
275 tbl
[i
].data
= &ns
->msg_ctlmnb
;
277 else if (tbl
[i
].data
== &init_ipc_ns
.sem_ctls
)
278 tbl
[i
].data
= &ns
->sem_ctls
;
279 #ifdef CONFIG_CHECKPOINT_RESTORE
280 else if (tbl
[i
].data
== &init_ipc_ns
.ids
[IPC_SEM_IDS
].next_id
)
281 tbl
[i
].data
= &ns
->ids
[IPC_SEM_IDS
].next_id
;
283 else if (tbl
[i
].data
== &init_ipc_ns
.ids
[IPC_MSG_IDS
].next_id
)
284 tbl
[i
].data
= &ns
->ids
[IPC_MSG_IDS
].next_id
;
286 else if (tbl
[i
].data
== &init_ipc_ns
.ids
[IPC_SHM_IDS
].next_id
)
287 tbl
[i
].data
= &ns
->ids
[IPC_SHM_IDS
].next_id
;
293 ns
->ipc_sysctls
= __register_sysctl_table(&ns
->ipc_set
, "kernel", tbl
,
294 ARRAY_SIZE(ipc_sysctls
));
296 if (!ns
->ipc_sysctls
) {
298 retire_sysctl_set(&ns
->ipc_set
);
305 void retire_ipc_sysctls(struct ipc_namespace
*ns
)
307 const struct ctl_table
*tbl
;
309 tbl
= ns
->ipc_sysctls
->ctl_table_arg
;
310 unregister_sysctl_table(ns
->ipc_sysctls
);
311 retire_sysctl_set(&ns
->ipc_set
);
315 static int __init
ipc_sysctl_init(void)
317 if (!setup_ipc_sysctls(&init_ipc_ns
)) {
318 pr_warn("ipc sysctl registration failed\n");
324 device_initcall(ipc_sysctl_init
);
326 static int __init
ipc_mni_extend(char *str
)
328 ipc_mni
= IPCMNI_EXTEND
;
329 ipc_mni_shift
= IPCMNI_EXTEND_SHIFT
;
330 ipc_min_cycle
= IPCMNI_EXTEND_MIN_CYCLE
;
331 pr_info("IPCMNI extended to %d.\n", ipc_mni
);
334 early_param("ipcmni_extend", ipc_mni_extend
);