Commit | Line | Data |
---|---|---|
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> | |
ae5e1b22 | 13 | #include <linux/ipc_namespace.h> |
6546bc42 ND |
14 | #include <linux/msg.h> |
15 | #include "util.h" | |
a5494dcd | 16 | |
a5c5928b | 17 | static void *get_ipc(struct ctl_table *table) |
a5494dcd EB |
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 | } | |
a5494dcd | 24 | |
11dea190 | 25 | #ifdef CONFIG_PROC_SYSCTL |
a5c5928b | 26 | static int proc_ipc_dointvec(struct ctl_table *table, int write, |
a5494dcd EB |
27 | void __user *buffer, size_t *lenp, loff_t *ppos) |
28 | { | |
29 | struct ctl_table ipc_table; | |
b34a6b1d | 30 | |
a5494dcd EB |
31 | memcpy(&ipc_table, table, sizeof(ipc_table)); |
32 | ipc_table.data = get_ipc(table); | |
33 | ||
8d65af78 | 34 | return proc_dointvec(&ipc_table, write, buffer, lenp, ppos); |
a5494dcd EB |
35 | } |
36 | ||
a5c5928b | 37 | static int proc_ipc_dointvec_minmax(struct ctl_table *table, int write, |
b34a6b1d VK |
38 | void __user *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 | ||
a5c5928b | 48 | static int proc_ipc_dointvec_minmax_orphans(struct ctl_table *table, int write, |
b34a6b1d VK |
49 | void __user *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 | ||
a5c5928b | 61 | static int proc_ipc_doulongvec_minmax(struct ctl_table *table, int write, |
8d65af78 | 62 | void __user *buffer, size_t *lenp, loff_t *ppos) |
a5494dcd EB |
63 | { |
64 | struct ctl_table ipc_table; | |
65 | memcpy(&ipc_table, table, sizeof(ipc_table)); | |
66 | ipc_table.data = get_ipc(table); | |
67 | ||
8d65af78 | 68 | return proc_doulongvec_minmax(&ipc_table, write, buffer, |
a5494dcd EB |
69 | lenp, ppos); |
70 | } | |
71 | ||
0050ee05 | 72 | static int proc_ipc_auto_msgmni(struct ctl_table *table, int write, |
8d65af78 | 73 | void __user *buffer, size_t *lenp, loff_t *ppos) |
9eefe520 ND |
74 | { |
75 | struct ctl_table ipc_table; | |
0050ee05 | 76 | int dummy = 0; |
9eefe520 ND |
77 | |
78 | memcpy(&ipc_table, table, sizeof(ipc_table)); | |
0050ee05 MS |
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); | |
9eefe520 ND |
85 | } |
86 | ||
8c81ddd2 WL |
87 | 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 | 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 | ||
a5494dcd EB |
107 | #else |
108 | #define proc_ipc_doulongvec_minmax NULL | |
109 | #define proc_ipc_dointvec NULL | |
b34a6b1d VK |
110 | #define proc_ipc_dointvec_minmax NULL |
111 | #define proc_ipc_dointvec_minmax_orphans NULL | |
0050ee05 | 112 | #define proc_ipc_auto_msgmni NULL |
8c81ddd2 | 113 | #define proc_ipc_sem_dointvec NULL |
a5494dcd EB |
114 | #endif |
115 | ||
9eefe520 ND |
116 | static int zero; |
117 | static int one = 1; | |
03f59566 | 118 | static int int_max = INT_MAX; |
5ac893b8 WL |
119 | int ipc_mni = IPCMNI; |
120 | int ipc_mni_shift = IPCMNI_SHIFT; | |
99db46ea | 121 | int ipc_min_cycle = RADIX_TREE_MAP_SIZE; |
9eefe520 | 122 | |
a5494dcd EB |
123 | static struct ctl_table ipc_kern_table[] = { |
124 | { | |
a5494dcd EB |
125 | .procname = "shmmax", |
126 | .data = &init_ipc_ns.shm_ctlmax, | |
239521f3 | 127 | .maxlen = sizeof(init_ipc_ns.shm_ctlmax), |
a5494dcd EB |
128 | .mode = 0644, |
129 | .proc_handler = proc_ipc_doulongvec_minmax, | |
a5494dcd EB |
130 | }, |
131 | { | |
a5494dcd EB |
132 | .procname = "shmall", |
133 | .data = &init_ipc_ns.shm_ctlall, | |
239521f3 | 134 | .maxlen = sizeof(init_ipc_ns.shm_ctlall), |
a5494dcd EB |
135 | .mode = 0644, |
136 | .proc_handler = proc_ipc_doulongvec_minmax, | |
a5494dcd EB |
137 | }, |
138 | { | |
a5494dcd EB |
139 | .procname = "shmmni", |
140 | .data = &init_ipc_ns.shm_ctlmni, | |
239521f3 | 141 | .maxlen = sizeof(init_ipc_ns.shm_ctlmni), |
a5494dcd | 142 | .mode = 0644, |
6730e658 WL |
143 | .proc_handler = proc_ipc_dointvec_minmax, |
144 | .extra1 = &zero, | |
145 | .extra2 = &ipc_mni, | |
a5494dcd | 146 | }, |
b34a6b1d VK |
147 | { |
148 | .procname = "shm_rmid_forced", | |
149 | .data = &init_ipc_ns.shm_rmid_forced, | |
150 | .maxlen = sizeof(init_ipc_ns.shm_rmid_forced), | |
151 | .mode = 0644, | |
152 | .proc_handler = proc_ipc_dointvec_minmax_orphans, | |
153 | .extra1 = &zero, | |
154 | .extra2 = &one, | |
155 | }, | |
a5494dcd | 156 | { |
a5494dcd EB |
157 | .procname = "msgmax", |
158 | .data = &init_ipc_ns.msg_ctlmax, | |
239521f3 | 159 | .maxlen = sizeof(init_ipc_ns.msg_ctlmax), |
a5494dcd | 160 | .mode = 0644, |
9bf76ca3 MK |
161 | .proc_handler = proc_ipc_dointvec_minmax, |
162 | .extra1 = &zero, | |
163 | .extra2 = &int_max, | |
a5494dcd EB |
164 | }, |
165 | { | |
a5494dcd EB |
166 | .procname = "msgmni", |
167 | .data = &init_ipc_ns.msg_ctlmni, | |
239521f3 | 168 | .maxlen = sizeof(init_ipc_ns.msg_ctlmni), |
a5494dcd | 169 | .mode = 0644, |
0050ee05 | 170 | .proc_handler = proc_ipc_dointvec_minmax, |
9bf76ca3 | 171 | .extra1 = &zero, |
6730e658 | 172 | .extra2 = &ipc_mni, |
a5494dcd | 173 | }, |
0050ee05 MS |
174 | { |
175 | .procname = "auto_msgmni", | |
176 | .data = NULL, | |
177 | .maxlen = sizeof(int), | |
178 | .mode = 0644, | |
179 | .proc_handler = proc_ipc_auto_msgmni, | |
180 | .extra1 = &zero, | |
181 | .extra2 = &one, | |
182 | }, | |
a5494dcd | 183 | { |
a5494dcd EB |
184 | .procname = "msgmnb", |
185 | .data = &init_ipc_ns.msg_ctlmnb, | |
239521f3 | 186 | .maxlen = sizeof(init_ipc_ns.msg_ctlmnb), |
a5494dcd | 187 | .mode = 0644, |
9bf76ca3 MK |
188 | .proc_handler = proc_ipc_dointvec_minmax, |
189 | .extra1 = &zero, | |
190 | .extra2 = &int_max, | |
a5494dcd EB |
191 | }, |
192 | { | |
a5494dcd EB |
193 | .procname = "sem", |
194 | .data = &init_ipc_ns.sem_ctls, | |
239521f3 | 195 | .maxlen = 4*sizeof(int), |
a5494dcd | 196 | .mode = 0644, |
8c81ddd2 | 197 | .proc_handler = proc_ipc_sem_dointvec, |
a5494dcd | 198 | }, |
03f59566 SK |
199 | #ifdef CONFIG_CHECKPOINT_RESTORE |
200 | { | |
201 | .procname = "sem_next_id", | |
202 | .data = &init_ipc_ns.ids[IPC_SEM_IDS].next_id, | |
203 | .maxlen = sizeof(init_ipc_ns.ids[IPC_SEM_IDS].next_id), | |
204 | .mode = 0644, | |
205 | .proc_handler = proc_ipc_dointvec_minmax, | |
206 | .extra1 = &zero, | |
207 | .extra2 = &int_max, | |
208 | }, | |
209 | { | |
210 | .procname = "msg_next_id", | |
211 | .data = &init_ipc_ns.ids[IPC_MSG_IDS].next_id, | |
212 | .maxlen = sizeof(init_ipc_ns.ids[IPC_MSG_IDS].next_id), | |
213 | .mode = 0644, | |
214 | .proc_handler = proc_ipc_dointvec_minmax, | |
215 | .extra1 = &zero, | |
216 | .extra2 = &int_max, | |
217 | }, | |
218 | { | |
219 | .procname = "shm_next_id", | |
220 | .data = &init_ipc_ns.ids[IPC_SHM_IDS].next_id, | |
221 | .maxlen = sizeof(init_ipc_ns.ids[IPC_SHM_IDS].next_id), | |
222 | .mode = 0644, | |
223 | .proc_handler = proc_ipc_dointvec_minmax, | |
224 | .extra1 = &zero, | |
225 | .extra2 = &int_max, | |
226 | }, | |
227 | #endif | |
a5494dcd EB |
228 | {} |
229 | }; | |
230 | ||
231 | static struct ctl_table ipc_root_table[] = { | |
232 | { | |
a5494dcd EB |
233 | .procname = "kernel", |
234 | .mode = 0555, | |
235 | .child = ipc_kern_table, | |
236 | }, | |
237 | {} | |
238 | }; | |
239 | ||
240 | static int __init ipc_sysctl_init(void) | |
241 | { | |
0b4d4147 | 242 | register_sysctl_table(ipc_root_table); |
a5494dcd EB |
243 | return 0; |
244 | } | |
245 | ||
6d08a256 | 246 | device_initcall(ipc_sysctl_init); |
5ac893b8 WL |
247 | |
248 | static int __init ipc_mni_extend(char *str) | |
249 | { | |
250 | ipc_mni = IPCMNI_EXTEND; | |
251 | ipc_mni_shift = IPCMNI_EXTEND_SHIFT; | |
99db46ea | 252 | ipc_min_cycle = IPCMNI_EXTEND_MIN_CYCLE; |
5ac893b8 WL |
253 | pr_info("IPCMNI extended to %d.\n", ipc_mni); |
254 | return 0; | |
255 | } | |
256 | early_param("ipcmni_extend", ipc_mni_extend); |