ipc: Check permissions for checkpoint_restart sysctls at open time
[linux-2.6-microblaze.git] / ipc / ipc_sysctl.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  *  Copyright (C) 2007
4  *
5  *  Author: Eric Biederman <ebiederm@xmision.com>
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>
13 #include <linux/capability.h>
14 #include <linux/ipc_namespace.h>
15 #include <linux/msg.h>
16 #include <linux/slab.h>
17 #include "util.h"
18
19 static int proc_ipc_dointvec_minmax_orphans(struct ctl_table *table, int write,
20                 void *buffer, size_t *lenp, loff_t *ppos)
21 {
22         struct ipc_namespace *ns =
23                 container_of(table->data, struct ipc_namespace, shm_rmid_forced);
24         int err;
25
26         err = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
27
28         if (err < 0)
29                 return err;
30         if (ns->shm_rmid_forced)
31                 shm_destroy_orphaned(ns);
32         return err;
33 }
34
35 static int proc_ipc_auto_msgmni(struct ctl_table *table, int write,
36                 void *buffer, size_t *lenp, loff_t *ppos)
37 {
38         struct ctl_table ipc_table;
39         int dummy = 0;
40
41         memcpy(&ipc_table, table, sizeof(ipc_table));
42         ipc_table.data = &dummy;
43
44         if (write)
45                 pr_info_once("writing to auto_msgmni has no effect");
46
47         return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
48 }
49
50 static int proc_ipc_sem_dointvec(struct ctl_table *table, int write,
51         void *buffer, size_t *lenp, loff_t *ppos)
52 {
53         struct ipc_namespace *ns =
54                 container_of(table->data, struct ipc_namespace, sem_ctls);
55         int ret, semmni;
56
57         semmni = ns->sem_ctls[3];
58         ret = proc_dointvec(table, write, buffer, lenp, ppos);
59
60         if (!ret)
61                 ret = sem_check_semmni(ns);
62
63         /*
64          * Reset the semmni value if an error happens.
65          */
66         if (ret)
67                 ns->sem_ctls[3] = semmni;
68         return ret;
69 }
70
71 int ipc_mni = IPCMNI;
72 int ipc_mni_shift = IPCMNI_SHIFT;
73 int ipc_min_cycle = RADIX_TREE_MAP_SIZE;
74
75 static struct ctl_table ipc_sysctls[] = {
76         {
77                 .procname       = "shmmax",
78                 .data           = &init_ipc_ns.shm_ctlmax,
79                 .maxlen         = sizeof(init_ipc_ns.shm_ctlmax),
80                 .mode           = 0644,
81                 .proc_handler   = proc_doulongvec_minmax,
82         },
83         {
84                 .procname       = "shmall",
85                 .data           = &init_ipc_ns.shm_ctlall,
86                 .maxlen         = sizeof(init_ipc_ns.shm_ctlall),
87                 .mode           = 0644,
88                 .proc_handler   = proc_doulongvec_minmax,
89         },
90         {
91                 .procname       = "shmmni",
92                 .data           = &init_ipc_ns.shm_ctlmni,
93                 .maxlen         = sizeof(init_ipc_ns.shm_ctlmni),
94                 .mode           = 0644,
95                 .proc_handler   = proc_dointvec_minmax,
96                 .extra1         = SYSCTL_ZERO,
97                 .extra2         = &ipc_mni,
98         },
99         {
100                 .procname       = "shm_rmid_forced",
101                 .data           = &init_ipc_ns.shm_rmid_forced,
102                 .maxlen         = sizeof(init_ipc_ns.shm_rmid_forced),
103                 .mode           = 0644,
104                 .proc_handler   = proc_ipc_dointvec_minmax_orphans,
105                 .extra1         = SYSCTL_ZERO,
106                 .extra2         = SYSCTL_ONE,
107         },
108         {
109                 .procname       = "msgmax",
110                 .data           = &init_ipc_ns.msg_ctlmax,
111                 .maxlen         = sizeof(init_ipc_ns.msg_ctlmax),
112                 .mode           = 0644,
113                 .proc_handler   = proc_dointvec_minmax,
114                 .extra1         = SYSCTL_ZERO,
115                 .extra2         = SYSCTL_INT_MAX,
116         },
117         {
118                 .procname       = "msgmni",
119                 .data           = &init_ipc_ns.msg_ctlmni,
120                 .maxlen         = sizeof(init_ipc_ns.msg_ctlmni),
121                 .mode           = 0644,
122                 .proc_handler   = proc_dointvec_minmax,
123                 .extra1         = SYSCTL_ZERO,
124                 .extra2         = &ipc_mni,
125         },
126         {
127                 .procname       = "auto_msgmni",
128                 .data           = NULL,
129                 .maxlen         = sizeof(int),
130                 .mode           = 0644,
131                 .proc_handler   = proc_ipc_auto_msgmni,
132                 .extra1         = SYSCTL_ZERO,
133                 .extra2         = SYSCTL_ONE,
134         },
135         {
136                 .procname       =  "msgmnb",
137                 .data           = &init_ipc_ns.msg_ctlmnb,
138                 .maxlen         = sizeof(init_ipc_ns.msg_ctlmnb),
139                 .mode           = 0644,
140                 .proc_handler   = proc_dointvec_minmax,
141                 .extra1         = SYSCTL_ZERO,
142                 .extra2         = SYSCTL_INT_MAX,
143         },
144         {
145                 .procname       = "sem",
146                 .data           = &init_ipc_ns.sem_ctls,
147                 .maxlen         = 4*sizeof(int),
148                 .mode           = 0644,
149                 .proc_handler   = proc_ipc_sem_dointvec,
150         },
151 #ifdef CONFIG_CHECKPOINT_RESTORE
152         {
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),
156                 .mode           = 0444,
157                 .proc_handler   = proc_dointvec_minmax,
158                 .extra1         = SYSCTL_ZERO,
159                 .extra2         = SYSCTL_INT_MAX,
160         },
161         {
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),
165                 .mode           = 0444,
166                 .proc_handler   = proc_dointvec_minmax,
167                 .extra1         = SYSCTL_ZERO,
168                 .extra2         = SYSCTL_INT_MAX,
169         },
170         {
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),
174                 .mode           = 0444,
175                 .proc_handler   = proc_dointvec_minmax,
176                 .extra1         = SYSCTL_ZERO,
177                 .extra2         = SYSCTL_INT_MAX,
178         },
179 #endif
180         {}
181 };
182
183 static struct ctl_table_set *set_lookup(struct ctl_table_root *root)
184 {
185         return &current->nsproxy->ipc_ns->ipc_set;
186 }
187
188 static int set_is_seen(struct ctl_table_set *set)
189 {
190         return &current->nsproxy->ipc_ns->ipc_set == set;
191 }
192
193 static int ipc_permissions(struct ctl_table_header *head, struct ctl_table *table)
194 {
195         int mode = table->mode;
196
197 #ifdef CONFIG_CHECKPOINT_RESTORE
198         struct ipc_namespace *ns = current->nsproxy->ipc_ns;
199
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))
204                 mode = 0666;
205 #endif
206         return mode;
207 }
208
209 static struct ctl_table_root set_root = {
210         .lookup = set_lookup,
211         .permissions = ipc_permissions,
212 };
213
214 bool setup_ipc_sysctls(struct ipc_namespace *ns)
215 {
216         struct ctl_table *tbl;
217
218         setup_sysctl_set(&ns->ipc_set, &set_root, set_is_seen);
219
220         tbl = kmemdup(ipc_sysctls, sizeof(ipc_sysctls), GFP_KERNEL);
221         if (tbl) {
222                 int i;
223
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;
227
228                         } else if (tbl[i].data == &init_ipc_ns.shm_ctlall) {
229                                 tbl[i].data = &ns->shm_ctlall;
230
231                         } else if (tbl[i].data == &init_ipc_ns.shm_ctlmni) {
232                                 tbl[i].data = &ns->shm_ctlmni;
233
234                         } else if (tbl[i].data == &init_ipc_ns.shm_rmid_forced) {
235                                 tbl[i].data = &ns->shm_rmid_forced;
236
237                         } else if (tbl[i].data == &init_ipc_ns.msg_ctlmax) {
238                                 tbl[i].data = &ns->msg_ctlmax;
239
240                         } else if (tbl[i].data == &init_ipc_ns.msg_ctlmni) {
241                                 tbl[i].data = &ns->msg_ctlmni;
242
243                         } else if (tbl[i].data == &init_ipc_ns.msg_ctlmnb) {
244                                 tbl[i].data = &ns->msg_ctlmnb;
245
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;
251
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;
254
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;
257 #endif
258                         } else {
259                                 tbl[i].data = NULL;
260                         }
261                 }
262
263                 ns->ipc_sysctls = __register_sysctl_table(&ns->ipc_set, "kernel", tbl);
264         }
265         if (!ns->ipc_sysctls) {
266                 kfree(tbl);
267                 retire_sysctl_set(&ns->ipc_set);
268                 return false;
269         }
270
271         return true;
272 }
273
274 void retire_ipc_sysctls(struct ipc_namespace *ns)
275 {
276         struct ctl_table *tbl;
277
278         tbl = ns->ipc_sysctls->ctl_table_arg;
279         unregister_sysctl_table(ns->ipc_sysctls);
280         retire_sysctl_set(&ns->ipc_set);
281         kfree(tbl);
282 }
283
284 static int __init ipc_sysctl_init(void)
285 {
286         if (!setup_ipc_sysctls(&init_ipc_ns)) {
287                 pr_warn("ipc sysctl registration failed\n");
288                 return -ENOMEM;
289         }
290         return 0;
291 }
292
293 device_initcall(ipc_sysctl_init);
294
295 static int __init ipc_mni_extend(char *str)
296 {
297         ipc_mni = IPCMNI_EXTEND;
298         ipc_mni_shift = IPCMNI_EXTEND_SHIFT;
299         ipc_min_cycle = IPCMNI_EXTEND_MIN_CYCLE;
300         pr_info("IPCMNI extended to %d.\n", ipc_mni);
301         return 0;
302 }
303 early_param("ipcmni_extend", ipc_mni_extend);