blob: 8ad93c29f511033dc4a6df1b2a26398ea78c9104
1 | /* |
2 | * Copyright (C) 2007 |
3 | * |
4 | * Author: Eric Biederman <ebiederm@xmision.com> |
5 | * |
6 | * This program is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU General Public License as |
8 | * published by the Free Software Foundation, version 2 of the |
9 | * License. |
10 | */ |
11 | |
12 | #include <linux/module.h> |
13 | #include <linux/ipc.h> |
14 | #include <linux/nsproxy.h> |
15 | #include <linux/sysctl.h> |
16 | #include <linux/uaccess.h> |
17 | #include <linux/ipc_namespace.h> |
18 | #include <linux/msg.h> |
19 | #include "util.h" |
20 | |
21 | static void *get_ipc(struct ctl_table *table) |
22 | { |
23 | char *which = table->data; |
24 | struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns; |
25 | which = (which - (char *)&init_ipc_ns) + (char *)ipc_ns; |
26 | return which; |
27 | } |
28 | |
29 | #ifdef CONFIG_PROC_SYSCTL |
30 | static int proc_ipc_dointvec(struct ctl_table *table, int write, |
31 | void __user *buffer, size_t *lenp, loff_t *ppos) |
32 | { |
33 | struct ctl_table ipc_table; |
34 | |
35 | memcpy(&ipc_table, table, sizeof(ipc_table)); |
36 | ipc_table.data = get_ipc(table); |
37 | |
38 | return proc_dointvec(&ipc_table, write, buffer, lenp, ppos); |
39 | } |
40 | |
41 | static int proc_ipc_dointvec_minmax(struct ctl_table *table, int write, |
42 | void __user *buffer, size_t *lenp, loff_t *ppos) |
43 | { |
44 | struct ctl_table ipc_table; |
45 | |
46 | memcpy(&ipc_table, table, sizeof(ipc_table)); |
47 | ipc_table.data = get_ipc(table); |
48 | |
49 | return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos); |
50 | } |
51 | |
52 | static int proc_ipc_dointvec_minmax_orphans(struct ctl_table *table, int write, |
53 | void __user *buffer, size_t *lenp, loff_t *ppos) |
54 | { |
55 | struct ipc_namespace *ns = current->nsproxy->ipc_ns; |
56 | int err = proc_ipc_dointvec_minmax(table, write, buffer, lenp, ppos); |
57 | |
58 | if (err < 0) |
59 | return err; |
60 | if (ns->shm_rmid_forced) |
61 | shm_destroy_orphaned(ns); |
62 | return err; |
63 | } |
64 | |
65 | static int proc_ipc_doulongvec_minmax(struct ctl_table *table, int write, |
66 | void __user *buffer, size_t *lenp, loff_t *ppos) |
67 | { |
68 | struct ctl_table ipc_table; |
69 | memcpy(&ipc_table, table, sizeof(ipc_table)); |
70 | ipc_table.data = get_ipc(table); |
71 | |
72 | return proc_doulongvec_minmax(&ipc_table, write, buffer, |
73 | lenp, ppos); |
74 | } |
75 | |
76 | static int proc_ipc_auto_msgmni(struct ctl_table *table, int write, |
77 | void __user *buffer, size_t *lenp, loff_t *ppos) |
78 | { |
79 | struct ctl_table ipc_table; |
80 | int dummy = 0; |
81 | |
82 | memcpy(&ipc_table, table, sizeof(ipc_table)); |
83 | ipc_table.data = &dummy; |
84 | |
85 | if (write) |
86 | pr_info_once("writing to auto_msgmni has no effect"); |
87 | |
88 | return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos); |
89 | } |
90 | |
91 | #else |
92 | #define proc_ipc_doulongvec_minmax NULL |
93 | #define proc_ipc_dointvec NULL |
94 | #define proc_ipc_dointvec_minmax NULL |
95 | #define proc_ipc_dointvec_minmax_orphans NULL |
96 | #define proc_ipc_auto_msgmni NULL |
97 | #endif |
98 | |
99 | static int zero; |
100 | static int one = 1; |
101 | static int int_max = INT_MAX; |
102 | |
103 | static struct ctl_table ipc_kern_table[] = { |
104 | { |
105 | .procname = "shmmax", |
106 | .data = &init_ipc_ns.shm_ctlmax, |
107 | .maxlen = sizeof(init_ipc_ns.shm_ctlmax), |
108 | .mode = 0644, |
109 | .proc_handler = proc_ipc_doulongvec_minmax, |
110 | }, |
111 | { |
112 | .procname = "shmall", |
113 | .data = &init_ipc_ns.shm_ctlall, |
114 | .maxlen = sizeof(init_ipc_ns.shm_ctlall), |
115 | .mode = 0644, |
116 | .proc_handler = proc_ipc_doulongvec_minmax, |
117 | }, |
118 | { |
119 | .procname = "shmmni", |
120 | .data = &init_ipc_ns.shm_ctlmni, |
121 | .maxlen = sizeof(init_ipc_ns.shm_ctlmni), |
122 | .mode = 0644, |
123 | .proc_handler = proc_ipc_dointvec, |
124 | }, |
125 | { |
126 | .procname = "shm_rmid_forced", |
127 | .data = &init_ipc_ns.shm_rmid_forced, |
128 | .maxlen = sizeof(init_ipc_ns.shm_rmid_forced), |
129 | .mode = 0644, |
130 | .proc_handler = proc_ipc_dointvec_minmax_orphans, |
131 | .extra1 = &zero, |
132 | .extra2 = &one, |
133 | }, |
134 | { |
135 | .procname = "msgmax", |
136 | .data = &init_ipc_ns.msg_ctlmax, |
137 | .maxlen = sizeof(init_ipc_ns.msg_ctlmax), |
138 | .mode = 0644, |
139 | .proc_handler = proc_ipc_dointvec_minmax, |
140 | .extra1 = &zero, |
141 | .extra2 = &int_max, |
142 | }, |
143 | { |
144 | .procname = "msgmni", |
145 | .data = &init_ipc_ns.msg_ctlmni, |
146 | .maxlen = sizeof(init_ipc_ns.msg_ctlmni), |
147 | .mode = 0644, |
148 | .proc_handler = proc_ipc_dointvec_minmax, |
149 | .extra1 = &zero, |
150 | .extra2 = &int_max, |
151 | }, |
152 | { |
153 | .procname = "auto_msgmni", |
154 | .data = NULL, |
155 | .maxlen = sizeof(int), |
156 | .mode = 0644, |
157 | .proc_handler = proc_ipc_auto_msgmni, |
158 | .extra1 = &zero, |
159 | .extra2 = &one, |
160 | }, |
161 | { |
162 | .procname = "msgmnb", |
163 | .data = &init_ipc_ns.msg_ctlmnb, |
164 | .maxlen = sizeof(init_ipc_ns.msg_ctlmnb), |
165 | .mode = 0644, |
166 | .proc_handler = proc_ipc_dointvec_minmax, |
167 | .extra1 = &zero, |
168 | .extra2 = &int_max, |
169 | }, |
170 | { |
171 | .procname = "sem", |
172 | .data = &init_ipc_ns.sem_ctls, |
173 | .maxlen = 4*sizeof(int), |
174 | .mode = 0644, |
175 | .proc_handler = proc_ipc_dointvec, |
176 | }, |
177 | #ifdef CONFIG_CHECKPOINT_RESTORE |
178 | { |
179 | .procname = "sem_next_id", |
180 | .data = &init_ipc_ns.ids[IPC_SEM_IDS].next_id, |
181 | .maxlen = sizeof(init_ipc_ns.ids[IPC_SEM_IDS].next_id), |
182 | .mode = 0644, |
183 | .proc_handler = proc_ipc_dointvec_minmax, |
184 | .extra1 = &zero, |
185 | .extra2 = &int_max, |
186 | }, |
187 | { |
188 | .procname = "msg_next_id", |
189 | .data = &init_ipc_ns.ids[IPC_MSG_IDS].next_id, |
190 | .maxlen = sizeof(init_ipc_ns.ids[IPC_MSG_IDS].next_id), |
191 | .mode = 0644, |
192 | .proc_handler = proc_ipc_dointvec_minmax, |
193 | .extra1 = &zero, |
194 | .extra2 = &int_max, |
195 | }, |
196 | { |
197 | .procname = "shm_next_id", |
198 | .data = &init_ipc_ns.ids[IPC_SHM_IDS].next_id, |
199 | .maxlen = sizeof(init_ipc_ns.ids[IPC_SHM_IDS].next_id), |
200 | .mode = 0644, |
201 | .proc_handler = proc_ipc_dointvec_minmax, |
202 | .extra1 = &zero, |
203 | .extra2 = &int_max, |
204 | }, |
205 | #endif |
206 | {} |
207 | }; |
208 | |
209 | static struct ctl_table ipc_root_table[] = { |
210 | { |
211 | .procname = "kernel", |
212 | .mode = 0555, |
213 | .child = ipc_kern_table, |
214 | }, |
215 | {} |
216 | }; |
217 | |
218 | static int __init ipc_sysctl_init(void) |
219 | { |
220 | register_sysctl_table(ipc_root_table); |
221 | return 0; |
222 | } |
223 | |
224 | device_initcall(ipc_sysctl_init); |
225 |