ipc: check checkpoint_restore_ns_capable() to modify C/R proc files
[linux-2.6-block.git] / ipc / ipc_sysctl.c
CommitLineData
b886d83c 1// SPDX-License-Identifier: GPL-2.0-only
a5494dcd
EB
2/*
3 * Copyright (C) 2007
4 *
5 * Author: Eric Biederman <ebiederm@xmision.com>
a5494dcd
EB
6 */
7
8#include <linux/module.h>
9#include <linux/ipc.h>
10#include <linux/nsproxy.h>
11#include <linux/sysctl.h>
12#include <linux/uaccess.h>
5563cabd 13#include <linux/capability.h>
ae5e1b22 14#include <linux/ipc_namespace.h>
6546bc42
ND
15#include <linux/msg.h>
16#include "util.h"
a5494dcd 17
a5c5928b 18static void *get_ipc(struct ctl_table *table)
a5494dcd
EB
19{
20 char *which = table->data;
21 struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
22 which = (which - (char *)&init_ipc_ns) + (char *)ipc_ns;
23 return which;
24}
a5494dcd 25
11dea190 26#ifdef CONFIG_PROC_SYSCTL
a5c5928b 27static int proc_ipc_dointvec(struct ctl_table *table, int write,
32927393 28 void *buffer, size_t *lenp, loff_t *ppos)
a5494dcd
EB
29{
30 struct ctl_table ipc_table;
b34a6b1d 31
a5494dcd
EB
32 memcpy(&ipc_table, table, sizeof(ipc_table));
33 ipc_table.data = get_ipc(table);
34
8d65af78 35 return proc_dointvec(&ipc_table, write, buffer, lenp, ppos);
a5494dcd
EB
36}
37
a5c5928b 38static int proc_ipc_dointvec_minmax(struct ctl_table *table, int write,
32927393 39 void *buffer, size_t *lenp, loff_t *ppos)
b34a6b1d
VK
40{
41 struct ctl_table ipc_table;
42
43 memcpy(&ipc_table, table, sizeof(ipc_table));
44 ipc_table.data = get_ipc(table);
45
46 return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
47}
48
a5c5928b 49static int proc_ipc_dointvec_minmax_orphans(struct ctl_table *table, int write,
32927393 50 void *buffer, size_t *lenp, loff_t *ppos)
b34a6b1d
VK
51{
52 struct ipc_namespace *ns = current->nsproxy->ipc_ns;
53 int err = proc_ipc_dointvec_minmax(table, write, buffer, lenp, ppos);
54
55 if (err < 0)
56 return err;
57 if (ns->shm_rmid_forced)
58 shm_destroy_orphaned(ns);
59 return err;
60}
61
a5c5928b 62static int proc_ipc_doulongvec_minmax(struct ctl_table *table, int write,
32927393 63 void *buffer, size_t *lenp, loff_t *ppos)
a5494dcd
EB
64{
65 struct ctl_table ipc_table;
66 memcpy(&ipc_table, table, sizeof(ipc_table));
67 ipc_table.data = get_ipc(table);
68
8d65af78 69 return proc_doulongvec_minmax(&ipc_table, write, buffer,
a5494dcd
EB
70 lenp, ppos);
71}
72
0050ee05 73static int proc_ipc_auto_msgmni(struct ctl_table *table, int write,
32927393 74 void *buffer, size_t *lenp, loff_t *ppos)
9eefe520
ND
75{
76 struct ctl_table ipc_table;
0050ee05 77 int dummy = 0;
9eefe520
ND
78
79 memcpy(&ipc_table, table, sizeof(ipc_table));
0050ee05
MS
80 ipc_table.data = &dummy;
81
82 if (write)
83 pr_info_once("writing to auto_msgmni has no effect");
84
85 return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
9eefe520
ND
86}
87
8c81ddd2 88static int proc_ipc_sem_dointvec(struct ctl_table *table, int write,
fff1662c 89 void *buffer, size_t *lenp, loff_t *ppos)
8c81ddd2
WL
90{
91 int ret, semmni;
92 struct ipc_namespace *ns = current->nsproxy->ipc_ns;
93
94 semmni = ns->sem_ctls[3];
95 ret = proc_ipc_dointvec(table, write, buffer, lenp, ppos);
96
97 if (!ret)
98 ret = sem_check_semmni(current->nsproxy->ipc_ns);
99
100 /*
101 * Reset the semmni value if an error happens.
102 */
103 if (ret)
104 ns->sem_ctls[3] = semmni;
105 return ret;
106}
107
5563cabd
MC
108#ifdef CONFIG_CHECKPOINT_RESTORE
109static int proc_ipc_dointvec_minmax_checkpoint_restore(struct ctl_table *table,
110 int write, void *buffer, size_t *lenp, loff_t *ppos)
111{
112 struct user_namespace *user_ns = current->nsproxy->ipc_ns->user_ns;
113
114 if (write && !checkpoint_restore_ns_capable(user_ns))
115 return -EPERM;
116
117 return proc_ipc_dointvec_minmax(table, write, buffer, lenp, ppos);
118}
119#endif
120
a5494dcd
EB
121#else
122#define proc_ipc_doulongvec_minmax NULL
123#define proc_ipc_dointvec NULL
b34a6b1d
VK
124#define proc_ipc_dointvec_minmax NULL
125#define proc_ipc_dointvec_minmax_orphans NULL
0050ee05 126#define proc_ipc_auto_msgmni NULL
8c81ddd2 127#define proc_ipc_sem_dointvec NULL
5563cabd
MC
128#ifdef CONFIG_CHECKPOINT_RESTORE
129#define proc_ipc_dointvec_minmax_checkpoint_restore NULL
130#endif /* CONFIG_CHECKPOINT_RESTORE */
a5494dcd
EB
131#endif
132
5ac893b8
WL
133int ipc_mni = IPCMNI;
134int ipc_mni_shift = IPCMNI_SHIFT;
99db46ea 135int ipc_min_cycle = RADIX_TREE_MAP_SIZE;
9eefe520 136
a5494dcd
EB
137static struct ctl_table ipc_kern_table[] = {
138 {
a5494dcd
EB
139 .procname = "shmmax",
140 .data = &init_ipc_ns.shm_ctlmax,
239521f3 141 .maxlen = sizeof(init_ipc_ns.shm_ctlmax),
a5494dcd
EB
142 .mode = 0644,
143 .proc_handler = proc_ipc_doulongvec_minmax,
a5494dcd
EB
144 },
145 {
a5494dcd
EB
146 .procname = "shmall",
147 .data = &init_ipc_ns.shm_ctlall,
239521f3 148 .maxlen = sizeof(init_ipc_ns.shm_ctlall),
a5494dcd
EB
149 .mode = 0644,
150 .proc_handler = proc_ipc_doulongvec_minmax,
a5494dcd
EB
151 },
152 {
a5494dcd
EB
153 .procname = "shmmni",
154 .data = &init_ipc_ns.shm_ctlmni,
239521f3 155 .maxlen = sizeof(init_ipc_ns.shm_ctlmni),
a5494dcd 156 .mode = 0644,
6730e658 157 .proc_handler = proc_ipc_dointvec_minmax,
eec4844f 158 .extra1 = SYSCTL_ZERO,
6730e658 159 .extra2 = &ipc_mni,
a5494dcd 160 },
b34a6b1d
VK
161 {
162 .procname = "shm_rmid_forced",
163 .data = &init_ipc_ns.shm_rmid_forced,
164 .maxlen = sizeof(init_ipc_ns.shm_rmid_forced),
165 .mode = 0644,
166 .proc_handler = proc_ipc_dointvec_minmax_orphans,
eec4844f
MC
167 .extra1 = SYSCTL_ZERO,
168 .extra2 = SYSCTL_ONE,
b34a6b1d 169 },
a5494dcd 170 {
a5494dcd
EB
171 .procname = "msgmax",
172 .data = &init_ipc_ns.msg_ctlmax,
239521f3 173 .maxlen = sizeof(init_ipc_ns.msg_ctlmax),
a5494dcd 174 .mode = 0644,
9bf76ca3 175 .proc_handler = proc_ipc_dointvec_minmax,
eec4844f
MC
176 .extra1 = SYSCTL_ZERO,
177 .extra2 = SYSCTL_INT_MAX,
a5494dcd
EB
178 },
179 {
a5494dcd
EB
180 .procname = "msgmni",
181 .data = &init_ipc_ns.msg_ctlmni,
239521f3 182 .maxlen = sizeof(init_ipc_ns.msg_ctlmni),
a5494dcd 183 .mode = 0644,
0050ee05 184 .proc_handler = proc_ipc_dointvec_minmax,
eec4844f 185 .extra1 = SYSCTL_ZERO,
6730e658 186 .extra2 = &ipc_mni,
a5494dcd 187 },
0050ee05
MS
188 {
189 .procname = "auto_msgmni",
190 .data = NULL,
191 .maxlen = sizeof(int),
192 .mode = 0644,
193 .proc_handler = proc_ipc_auto_msgmni,
eec4844f
MC
194 .extra1 = SYSCTL_ZERO,
195 .extra2 = SYSCTL_ONE,
0050ee05 196 },
a5494dcd 197 {
a5494dcd
EB
198 .procname = "msgmnb",
199 .data = &init_ipc_ns.msg_ctlmnb,
239521f3 200 .maxlen = sizeof(init_ipc_ns.msg_ctlmnb),
a5494dcd 201 .mode = 0644,
9bf76ca3 202 .proc_handler = proc_ipc_dointvec_minmax,
eec4844f
MC
203 .extra1 = SYSCTL_ZERO,
204 .extra2 = SYSCTL_INT_MAX,
a5494dcd
EB
205 },
206 {
a5494dcd
EB
207 .procname = "sem",
208 .data = &init_ipc_ns.sem_ctls,
239521f3 209 .maxlen = 4*sizeof(int),
a5494dcd 210 .mode = 0644,
8c81ddd2 211 .proc_handler = proc_ipc_sem_dointvec,
a5494dcd 212 },
03f59566
SK
213#ifdef CONFIG_CHECKPOINT_RESTORE
214 {
215 .procname = "sem_next_id",
216 .data = &init_ipc_ns.ids[IPC_SEM_IDS].next_id,
217 .maxlen = sizeof(init_ipc_ns.ids[IPC_SEM_IDS].next_id),
5563cabd
MC
218 .mode = 0666,
219 .proc_handler = proc_ipc_dointvec_minmax_checkpoint_restore,
eec4844f
MC
220 .extra1 = SYSCTL_ZERO,
221 .extra2 = SYSCTL_INT_MAX,
03f59566
SK
222 },
223 {
224 .procname = "msg_next_id",
225 .data = &init_ipc_ns.ids[IPC_MSG_IDS].next_id,
226 .maxlen = sizeof(init_ipc_ns.ids[IPC_MSG_IDS].next_id),
5563cabd
MC
227 .mode = 0666,
228 .proc_handler = proc_ipc_dointvec_minmax_checkpoint_restore,
eec4844f
MC
229 .extra1 = SYSCTL_ZERO,
230 .extra2 = SYSCTL_INT_MAX,
03f59566
SK
231 },
232 {
233 .procname = "shm_next_id",
234 .data = &init_ipc_ns.ids[IPC_SHM_IDS].next_id,
235 .maxlen = sizeof(init_ipc_ns.ids[IPC_SHM_IDS].next_id),
5563cabd
MC
236 .mode = 0666,
237 .proc_handler = proc_ipc_dointvec_minmax_checkpoint_restore,
eec4844f
MC
238 .extra1 = SYSCTL_ZERO,
239 .extra2 = SYSCTL_INT_MAX,
03f59566
SK
240 },
241#endif
a5494dcd
EB
242 {}
243};
244
245static struct ctl_table ipc_root_table[] = {
246 {
a5494dcd
EB
247 .procname = "kernel",
248 .mode = 0555,
249 .child = ipc_kern_table,
250 },
251 {}
252};
253
254static int __init ipc_sysctl_init(void)
255{
0b4d4147 256 register_sysctl_table(ipc_root_table);
a5494dcd
EB
257 return 0;
258}
259
6d08a256 260device_initcall(ipc_sysctl_init);
5ac893b8
WL
261
262static int __init ipc_mni_extend(char *str)
263{
264 ipc_mni = IPCMNI_EXTEND;
265 ipc_mni_shift = IPCMNI_EXTEND_SHIFT;
99db46ea 266 ipc_min_cycle = IPCMNI_EXTEND_MIN_CYCLE;
5ac893b8
WL
267 pr_info("IPCMNI extended to %d.\n", ipc_mni);
268 return 0;
269}
270early_param("ipcmni_extend", ipc_mni_extend);