Branch data Line data Source code
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 : 0 : char *which = table->data;
20 : 0 : struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
21 : 0 : which = (which - (char *)&init_ipc_ns) + (char *)ipc_ns;
22 : : return which;
23 : : }
24 : :
25 : : #ifdef CONFIG_PROC_SYSCTL
26 : 0 : static int proc_ipc_dointvec(struct ctl_table *table, int write,
27 : : void __user *buffer, size_t *lenp, loff_t *ppos)
28 : : {
29 : : struct ctl_table ipc_table;
30 : :
31 : 0 : memcpy(&ipc_table, table, sizeof(ipc_table));
32 : 0 : ipc_table.data = get_ipc(table);
33 : :
34 : 0 : return proc_dointvec(&ipc_table, write, buffer, lenp, ppos);
35 : : }
36 : :
37 : 0 : static int proc_ipc_dointvec_minmax(struct ctl_table *table, int write,
38 : : void __user *buffer, size_t *lenp, loff_t *ppos)
39 : : {
40 : : struct ctl_table ipc_table;
41 : :
42 : 0 : memcpy(&ipc_table, table, sizeof(ipc_table));
43 : 0 : ipc_table.data = get_ipc(table);
44 : :
45 : 0 : return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
46 : : }
47 : :
48 : 0 : static int proc_ipc_dointvec_minmax_orphans(struct ctl_table *table, int write,
49 : : void __user *buffer, size_t *lenp, loff_t *ppos)
50 : : {
51 : 0 : struct ipc_namespace *ns = current->nsproxy->ipc_ns;
52 : 0 : int err = proc_ipc_dointvec_minmax(table, write, buffer, lenp, ppos);
53 : :
54 : 0 : if (err < 0)
55 : : return err;
56 : 0 : if (ns->shm_rmid_forced)
57 : 0 : shm_destroy_orphaned(ns);
58 : : return err;
59 : : }
60 : :
61 : 0 : static int proc_ipc_doulongvec_minmax(struct ctl_table *table, int write,
62 : : void __user *buffer, size_t *lenp, loff_t *ppos)
63 : : {
64 : : struct ctl_table ipc_table;
65 : 0 : memcpy(&ipc_table, table, sizeof(ipc_table));
66 : 0 : ipc_table.data = get_ipc(table);
67 : :
68 : 0 : return proc_doulongvec_minmax(&ipc_table, write, buffer,
69 : : lenp, ppos);
70 : : }
71 : :
72 : 0 : static int proc_ipc_auto_msgmni(struct ctl_table *table, int write,
73 : : void __user *buffer, size_t *lenp, loff_t *ppos)
74 : : {
75 : : struct ctl_table ipc_table;
76 : 0 : int dummy = 0;
77 : :
78 : 0 : memcpy(&ipc_table, table, sizeof(ipc_table));
79 : 0 : ipc_table.data = &dummy;
80 : :
81 : 0 : if (write)
82 : 0 : pr_info_once("writing to auto_msgmni has no effect");
83 : :
84 : 0 : return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
85 : : }
86 : :
87 : 0 : static int proc_ipc_sem_dointvec(struct ctl_table *table, int write,
88 : : void __user *buffer, size_t *lenp, loff_t *ppos)
89 : : {
90 : : int ret, semmni;
91 : 0 : struct ipc_namespace *ns = current->nsproxy->ipc_ns;
92 : :
93 : 0 : semmni = ns->sem_ctls[3];
94 : 0 : ret = proc_ipc_dointvec(table, write, buffer, lenp, ppos);
95 : :
96 : 0 : if (!ret)
97 : 0 : ret = sem_check_semmni(current->nsproxy->ipc_ns);
98 : :
99 : : /*
100 : : * Reset the semmni value if an error happens.
101 : : */
102 : 0 : if (ret)
103 : 0 : ns->sem_ctls[3] = semmni;
104 : 0 : 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 : 3 : static int __init ipc_sysctl_init(void)
238 : : {
239 : 3 : register_sysctl_table(ipc_root_table);
240 : 3 : return 0;
241 : : }
242 : :
243 : : device_initcall(ipc_sysctl_init);
244 : :
245 : 0 : static int __init ipc_mni_extend(char *str)
246 : : {
247 : 0 : ipc_mni = IPCMNI_EXTEND;
248 : 0 : ipc_mni_shift = IPCMNI_EXTEND_SHIFT;
249 : 0 : ipc_min_cycle = IPCMNI_EXTEND_MIN_CYCLE;
250 : 0 : pr_info("IPCMNI extended to %d.\n", ipc_mni);
251 : 0 : return 0;
252 : : }
253 : : early_param("ipcmni_extend", ipc_mni_extend);
|