Linux 6.0-rc1
[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/ipc_namespace.h>
14 #include <linux/msg.h>
15 #include "util.h"
16
17 static void *get_ipc(struct ctl_table *table)
18 {
19         char *which = table->data;
20         struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
21         which = (which - (char *)&init_ipc_ns) + (char *)ipc_ns;
22         return which;
23 }
24
25 #ifdef CONFIG_PROC_SYSCTL
26 static int proc_ipc_dointvec(struct ctl_table *table, int write,
27                 void *buffer, size_t *lenp, loff_t *ppos)
28 {
29         struct ctl_table ipc_table;
30
31         memcpy(&ipc_table, table, sizeof(ipc_table));
32         ipc_table.data = get_ipc(table);
33
34         return proc_dointvec(&ipc_table, write, buffer, lenp, ppos);
35 }
36
37 static int proc_ipc_dointvec_minmax(struct ctl_table *table, int write,
38                 void *buffer, size_t *lenp, loff_t *ppos)
39 {
40         struct ctl_table ipc_table;
41
42         memcpy(&ipc_table, table, sizeof(ipc_table));
43         ipc_table.data = get_ipc(table);
44
45         return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
46 }
47
48 static int proc_ipc_dointvec_minmax_orphans(struct ctl_table *table, int write,
49                 void *buffer, size_t *lenp, loff_t *ppos)
50 {
51         struct ipc_namespace *ns = current->nsproxy->ipc_ns;
52         int err = proc_ipc_dointvec_minmax(table, write, buffer, lenp, ppos);
53
54         if (err < 0)
55                 return err;
56         if (ns->shm_rmid_forced)
57                 shm_destroy_orphaned(ns);
58         return err;
59 }
60
61 static int proc_ipc_doulongvec_minmax(struct ctl_table *table, int write,
62                 void *buffer, size_t *lenp, loff_t *ppos)
63 {
64         struct ctl_table ipc_table;
65         memcpy(&ipc_table, table, sizeof(ipc_table));
66         ipc_table.data = get_ipc(table);
67
68         return proc_doulongvec_minmax(&ipc_table, write, buffer,
69                                         lenp, ppos);
70 }
71
72 static int proc_ipc_auto_msgmni(struct ctl_table *table, int write,
73                 void *buffer, size_t *lenp, loff_t *ppos)
74 {
75         struct ctl_table ipc_table;
76         int dummy = 0;
77
78         memcpy(&ipc_table, table, sizeof(ipc_table));
79         ipc_table.data = &dummy;
80
81         if (write)
82                 pr_info_once("writing to auto_msgmni has no effect");
83
84         return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
85 }
86
87 static int proc_ipc_sem_dointvec(struct ctl_table *table, int write,
88         void *buffer, size_t *lenp, loff_t *ppos)
89 {
90         int ret, semmni;
91         struct ipc_namespace *ns = current->nsproxy->ipc_ns;
92
93         semmni = ns->sem_ctls[3];
94         ret = proc_ipc_dointvec(table, write, buffer, lenp, ppos);
95
96         if (!ret)
97                 ret = sem_check_semmni(current->nsproxy->ipc_ns);
98
99         /*
100          * Reset the semmni value if an error happens.
101          */
102         if (ret)
103                 ns->sem_ctls[3] = semmni;
104         return ret;
105 }
106
107 #else
108 #define proc_ipc_doulongvec_minmax NULL
109 #define proc_ipc_dointvec          NULL
110 #define proc_ipc_dointvec_minmax   NULL
111 #define proc_ipc_dointvec_minmax_orphans   NULL
112 #define proc_ipc_auto_msgmni       NULL
113 #define proc_ipc_sem_dointvec      NULL
114 #endif
115
116 int ipc_mni = IPCMNI;
117 int ipc_mni_shift = IPCMNI_SHIFT;
118 int ipc_min_cycle = RADIX_TREE_MAP_SIZE;
119
120 static struct ctl_table ipc_kern_table[] = {
121         {
122                 .procname       = "shmmax",
123                 .data           = &init_ipc_ns.shm_ctlmax,
124                 .maxlen         = sizeof(init_ipc_ns.shm_ctlmax),
125                 .mode           = 0644,
126                 .proc_handler   = proc_ipc_doulongvec_minmax,
127         },
128         {
129                 .procname       = "shmall",
130                 .data           = &init_ipc_ns.shm_ctlall,
131                 .maxlen         = sizeof(init_ipc_ns.shm_ctlall),
132                 .mode           = 0644,
133                 .proc_handler   = proc_ipc_doulongvec_minmax,
134         },
135         {
136                 .procname       = "shmmni",
137                 .data           = &init_ipc_ns.shm_ctlmni,
138                 .maxlen         = sizeof(init_ipc_ns.shm_ctlmni),
139                 .mode           = 0644,
140                 .proc_handler   = proc_ipc_dointvec_minmax,
141                 .extra1         = SYSCTL_ZERO,
142                 .extra2         = &ipc_mni,
143         },
144         {
145                 .procname       = "shm_rmid_forced",
146                 .data           = &init_ipc_ns.shm_rmid_forced,
147                 .maxlen         = sizeof(init_ipc_ns.shm_rmid_forced),
148                 .mode           = 0644,
149                 .proc_handler   = proc_ipc_dointvec_minmax_orphans,
150                 .extra1         = SYSCTL_ZERO,
151                 .extra2         = SYSCTL_ONE,
152         },
153         {
154                 .procname       = "msgmax",
155                 .data           = &init_ipc_ns.msg_ctlmax,
156                 .maxlen         = sizeof(init_ipc_ns.msg_ctlmax),
157                 .mode           = 0644,
158                 .proc_handler   = proc_ipc_dointvec_minmax,
159                 .extra1         = SYSCTL_ZERO,
160                 .extra2         = SYSCTL_INT_MAX,
161         },
162         {
163                 .procname       = "msgmni",
164                 .data           = &init_ipc_ns.msg_ctlmni,
165                 .maxlen         = sizeof(init_ipc_ns.msg_ctlmni),
166                 .mode           = 0644,
167                 .proc_handler   = proc_ipc_dointvec_minmax,
168                 .extra1         = SYSCTL_ZERO,
169                 .extra2         = &ipc_mni,
170         },
171         {
172                 .procname       = "auto_msgmni",
173                 .data           = NULL,
174                 .maxlen         = sizeof(int),
175                 .mode           = 0644,
176                 .proc_handler   = proc_ipc_auto_msgmni,
177                 .extra1         = SYSCTL_ZERO,
178                 .extra2         = SYSCTL_ONE,
179         },
180         {
181                 .procname       =  "msgmnb",
182                 .data           = &init_ipc_ns.msg_ctlmnb,
183                 .maxlen         = sizeof(init_ipc_ns.msg_ctlmnb),
184                 .mode           = 0644,
185                 .proc_handler   = proc_ipc_dointvec_minmax,
186                 .extra1         = SYSCTL_ZERO,
187                 .extra2         = SYSCTL_INT_MAX,
188         },
189         {
190                 .procname       = "sem",
191                 .data           = &init_ipc_ns.sem_ctls,
192                 .maxlen         = 4*sizeof(int),
193                 .mode           = 0644,
194                 .proc_handler   = proc_ipc_sem_dointvec,
195         },
196 #ifdef CONFIG_CHECKPOINT_RESTORE
197         {
198                 .procname       = "sem_next_id",
199                 .data           = &init_ipc_ns.ids[IPC_SEM_IDS].next_id,
200                 .maxlen         = sizeof(init_ipc_ns.ids[IPC_SEM_IDS].next_id),
201                 .mode           = 0644,
202                 .proc_handler   = proc_ipc_dointvec_minmax,
203                 .extra1         = SYSCTL_ZERO,
204                 .extra2         = SYSCTL_INT_MAX,
205         },
206         {
207                 .procname       = "msg_next_id",
208                 .data           = &init_ipc_ns.ids[IPC_MSG_IDS].next_id,
209                 .maxlen         = sizeof(init_ipc_ns.ids[IPC_MSG_IDS].next_id),
210                 .mode           = 0644,
211                 .proc_handler   = proc_ipc_dointvec_minmax,
212                 .extra1         = SYSCTL_ZERO,
213                 .extra2         = SYSCTL_INT_MAX,
214         },
215         {
216                 .procname       = "shm_next_id",
217                 .data           = &init_ipc_ns.ids[IPC_SHM_IDS].next_id,
218                 .maxlen         = sizeof(init_ipc_ns.ids[IPC_SHM_IDS].next_id),
219                 .mode           = 0644,
220                 .proc_handler   = proc_ipc_dointvec_minmax,
221                 .extra1         = SYSCTL_ZERO,
222                 .extra2         = SYSCTL_INT_MAX,
223         },
224 #endif
225         {}
226 };
227
228 static struct ctl_table ipc_root_table[] = {
229         {
230                 .procname       = "kernel",
231                 .mode           = 0555,
232                 .child          = ipc_kern_table,
233         },
234         {}
235 };
236
237 static int __init ipc_sysctl_init(void)
238 {
239         register_sysctl_table(ipc_root_table);
240         return 0;
241 }
242
243 device_initcall(ipc_sysctl_init);
244
245 static int __init ipc_mni_extend(char *str)
246 {
247         ipc_mni = IPCMNI_EXTEND;
248         ipc_mni_shift = IPCMNI_EXTEND_SHIFT;
249         ipc_min_cycle = IPCMNI_EXTEND_MIN_CYCLE;
250         pr_info("IPCMNI extended to %d.\n", ipc_mni);
251         return 0;
252 }
253 early_param("ipcmni_extend", ipc_mni_extend);