Merge tag 'powerpc-5.19-2' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc...
[platform/kernel/linux-starfive.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                 ns->ipc_sysctls = __register_sysctl_table(&ns->ipc_set, "kernel", tbl);
263         }
264         if (!ns->ipc_sysctls) {
265                 kfree(tbl);
266                 retire_sysctl_set(&ns->ipc_set);
267                 return false;
268         }
269
270         return true;
271 }
272
273 void retire_ipc_sysctls(struct ipc_namespace *ns)
274 {
275         struct ctl_table *tbl;
276
277         tbl = ns->ipc_sysctls->ctl_table_arg;
278         unregister_sysctl_table(ns->ipc_sysctls);
279         retire_sysctl_set(&ns->ipc_set);
280         kfree(tbl);
281 }
282
283 static int __init ipc_sysctl_init(void)
284 {
285         if (!setup_ipc_sysctls(&init_ipc_ns)) {
286                 pr_warn("ipc sysctl registration failed\n");
287                 return -ENOMEM;
288         }
289         return 0;
290 }
291
292 device_initcall(ipc_sysctl_init);
293
294 static int __init ipc_mni_extend(char *str)
295 {
296         ipc_mni = IPCMNI_EXTEND;
297         ipc_mni_shift = IPCMNI_EXTEND_SHIFT;
298         ipc_min_cycle = IPCMNI_EXTEND_MIN_CYCLE;
299         pr_info("IPCMNI extended to %d.\n", ipc_mni);
300         return 0;
301 }
302 early_param("ipcmni_extend", ipc_mni_extend);