13
13
#include <linux/capability.h>
14
14
#include <linux/ipc_namespace.h>
15
15
#include <linux/msg.h>
16
+ #include <linux/slab.h>
16
17
#include "util.h"
17
18
18
- static void * get_ipc (struct ctl_table * table )
19
- {
20
- char * which = table -> data ;
21
- struct ipc_namespace * ipc_ns = current -> nsproxy -> ipc_ns ;
22
- which = (which - (char * )& init_ipc_ns ) + (char * )ipc_ns ;
23
- return which ;
24
- }
25
-
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 ,
19
+ static int proc_ipc_dointvec_minmax_orphans (struct ctl_table * table , int write ,
38
20
void * buffer , size_t * lenp , loff_t * ppos )
39
21
{
22
+ struct ipc_namespace * ns = table -> extra1 ;
40
23
struct ctl_table ipc_table ;
24
+ int err ;
41
25
42
26
memcpy (& ipc_table , table , sizeof (ipc_table ));
43
- ipc_table .data = get_ipc (table );
44
27
45
- return proc_dointvec_minmax ( & ipc_table , write , buffer , lenp , ppos ) ;
46
- }
28
+ ipc_table . extra1 = SYSCTL_ZERO ;
29
+ ipc_table . extra2 = SYSCTL_ONE ;
47
30
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 );
31
+ err = proc_dointvec_minmax (& ipc_table , write , buffer , lenp , ppos );
53
32
54
33
if (err < 0 )
55
34
return err ;
@@ -58,17 +37,6 @@ static int proc_ipc_dointvec_minmax_orphans(struct ctl_table *table, int write,
58
37
return err ;
59
38
}
60
39
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
40
static int proc_ipc_auto_msgmni (struct ctl_table * table , int write ,
73
41
void * buffer , size_t * lenp , loff_t * ppos )
74
42
{
@@ -87,11 +55,17 @@ static int proc_ipc_auto_msgmni(struct ctl_table *table, int write,
87
55
static int proc_ipc_sem_dointvec (struct ctl_table * table , int write ,
88
56
void * buffer , size_t * lenp , loff_t * ppos )
89
57
{
58
+ struct ipc_namespace * ns = table -> extra1 ;
59
+ struct ctl_table ipc_table ;
90
60
int ret , semmni ;
91
- struct ipc_namespace * ns = current -> nsproxy -> ipc_ns ;
61
+
62
+ memcpy (& ipc_table , table , sizeof (ipc_table ));
63
+
64
+ ipc_table .extra1 = NULL ;
65
+ ipc_table .extra2 = NULL ;
92
66
93
67
semmni = ns -> sem_ctls [3 ];
94
- ret = proc_ipc_dointvec (table , write , buffer , lenp , ppos );
68
+ ret = proc_dointvec (table , write , buffer , lenp , ppos );
95
69
96
70
if (!ret )
97
71
ret = sem_check_semmni (current -> nsproxy -> ipc_ns );
@@ -108,40 +82,46 @@ static int proc_ipc_sem_dointvec(struct ctl_table *table, int write,
108
82
static int proc_ipc_dointvec_minmax_checkpoint_restore (struct ctl_table * table ,
109
83
int write , void * buffer , size_t * lenp , loff_t * ppos )
110
84
{
111
- struct user_namespace * user_ns = current -> nsproxy -> ipc_ns -> user_ns ;
85
+ struct ipc_namespace * ns = table -> extra1 ;
86
+ struct ctl_table ipc_table ;
112
87
113
- if (write && !checkpoint_restore_ns_capable (user_ns ))
88
+ if (write && !checkpoint_restore_ns_capable (ns -> user_ns ))
114
89
return - EPERM ;
115
90
116
- return proc_ipc_dointvec_minmax (table , write , buffer , lenp , ppos );
91
+ memcpy (& ipc_table , table , sizeof (ipc_table ));
92
+
93
+ ipc_table .extra1 = SYSCTL_ZERO ;
94
+ ipc_table .extra2 = SYSCTL_INT_MAX ;
95
+
96
+ return proc_dointvec_minmax (& ipc_table , write , buffer , lenp , ppos );
117
97
}
118
98
#endif
119
99
120
100
int ipc_mni = IPCMNI ;
121
101
int ipc_mni_shift = IPCMNI_SHIFT ;
122
102
int ipc_min_cycle = RADIX_TREE_MAP_SIZE ;
123
103
124
- static struct ctl_table ipc_kern_table [] = {
104
+ static struct ctl_table ipc_sysctls [] = {
125
105
{
126
106
.procname = "shmmax" ,
127
107
.data = & init_ipc_ns .shm_ctlmax ,
128
108
.maxlen = sizeof (init_ipc_ns .shm_ctlmax ),
129
109
.mode = 0644 ,
130
- .proc_handler = proc_ipc_doulongvec_minmax ,
110
+ .proc_handler = proc_doulongvec_minmax ,
131
111
},
132
112
{
133
113
.procname = "shmall" ,
134
114
.data = & init_ipc_ns .shm_ctlall ,
135
115
.maxlen = sizeof (init_ipc_ns .shm_ctlall ),
136
116
.mode = 0644 ,
137
- .proc_handler = proc_ipc_doulongvec_minmax ,
117
+ .proc_handler = proc_doulongvec_minmax ,
138
118
},
139
119
{
140
120
.procname = "shmmni" ,
141
121
.data = & init_ipc_ns .shm_ctlmni ,
142
122
.maxlen = sizeof (init_ipc_ns .shm_ctlmni ),
143
123
.mode = 0644 ,
144
- .proc_handler = proc_ipc_dointvec_minmax ,
124
+ .proc_handler = proc_dointvec_minmax ,
145
125
.extra1 = SYSCTL_ZERO ,
146
126
.extra2 = & ipc_mni ,
147
127
},
@@ -151,15 +131,13 @@ static struct ctl_table ipc_kern_table[] = {
151
131
.maxlen = sizeof (init_ipc_ns .shm_rmid_forced ),
152
132
.mode = 0644 ,
153
133
.proc_handler = proc_ipc_dointvec_minmax_orphans ,
154
- .extra1 = SYSCTL_ZERO ,
155
- .extra2 = SYSCTL_ONE ,
156
134
},
157
135
{
158
136
.procname = "msgmax" ,
159
137
.data = & init_ipc_ns .msg_ctlmax ,
160
138
.maxlen = sizeof (init_ipc_ns .msg_ctlmax ),
161
139
.mode = 0644 ,
162
- .proc_handler = proc_ipc_dointvec_minmax ,
140
+ .proc_handler = proc_dointvec_minmax ,
163
141
.extra1 = SYSCTL_ZERO ,
164
142
.extra2 = SYSCTL_INT_MAX ,
165
143
},
@@ -168,7 +146,7 @@ static struct ctl_table ipc_kern_table[] = {
168
146
.data = & init_ipc_ns .msg_ctlmni ,
169
147
.maxlen = sizeof (init_ipc_ns .msg_ctlmni ),
170
148
.mode = 0644 ,
171
- .proc_handler = proc_ipc_dointvec_minmax ,
149
+ .proc_handler = proc_dointvec_minmax ,
172
150
.extra1 = SYSCTL_ZERO ,
173
151
.extra2 = & ipc_mni ,
174
152
},
@@ -186,7 +164,7 @@ static struct ctl_table ipc_kern_table[] = {
186
164
.data = & init_ipc_ns .msg_ctlmnb ,
187
165
.maxlen = sizeof (init_ipc_ns .msg_ctlmnb ),
188
166
.mode = 0644 ,
189
- .proc_handler = proc_ipc_dointvec_minmax ,
167
+ .proc_handler = proc_dointvec_minmax ,
190
168
.extra1 = SYSCTL_ZERO ,
191
169
.extra2 = SYSCTL_INT_MAX ,
192
170
},
@@ -204,43 +182,120 @@ static struct ctl_table ipc_kern_table[] = {
204
182
.maxlen = sizeof (init_ipc_ns .ids [IPC_SEM_IDS ].next_id ),
205
183
.mode = 0666 ,
206
184
.proc_handler = proc_ipc_dointvec_minmax_checkpoint_restore ,
207
- .extra1 = SYSCTL_ZERO ,
208
- .extra2 = SYSCTL_INT_MAX ,
209
185
},
210
186
{
211
187
.procname = "msg_next_id" ,
212
188
.data = & init_ipc_ns .ids [IPC_MSG_IDS ].next_id ,
213
189
.maxlen = sizeof (init_ipc_ns .ids [IPC_MSG_IDS ].next_id ),
214
190
.mode = 0666 ,
215
191
.proc_handler = proc_ipc_dointvec_minmax_checkpoint_restore ,
216
- .extra1 = SYSCTL_ZERO ,
217
- .extra2 = SYSCTL_INT_MAX ,
218
192
},
219
193
{
220
194
.procname = "shm_next_id" ,
221
195
.data = & init_ipc_ns .ids [IPC_SHM_IDS ].next_id ,
222
196
.maxlen = sizeof (init_ipc_ns .ids [IPC_SHM_IDS ].next_id ),
223
197
.mode = 0666 ,
224
198
.proc_handler = proc_ipc_dointvec_minmax_checkpoint_restore ,
225
- .extra1 = SYSCTL_ZERO ,
226
- .extra2 = SYSCTL_INT_MAX ,
227
199
},
228
200
#endif
229
201
{}
230
202
};
231
203
232
- static struct ctl_table ipc_root_table [] = {
233
- {
234
- .procname = "kernel" ,
235
- .mode = 0555 ,
236
- .child = ipc_kern_table ,
237
- },
238
- {}
204
+ static struct ctl_table_set * set_lookup (struct ctl_table_root * root )
205
+ {
206
+ return & current -> nsproxy -> ipc_ns -> ipc_set ;
207
+ }
208
+
209
+ static int set_is_seen (struct ctl_table_set * set )
210
+ {
211
+ return & current -> nsproxy -> ipc_ns -> ipc_set == set ;
212
+ }
213
+
214
+ static struct ctl_table_root set_root = {
215
+ .lookup = set_lookup ,
239
216
};
240
217
218
+ bool setup_ipc_sysctls (struct ipc_namespace * ns )
219
+ {
220
+ struct ctl_table * tbl ;
221
+
222
+ setup_sysctl_set (& ns -> ipc_set , & set_root , set_is_seen );
223
+
224
+ tbl = kmemdup (ipc_sysctls , sizeof (ipc_sysctls ), GFP_KERNEL );
225
+ if (tbl ) {
226
+ int i ;
227
+
228
+ for (i = 0 ; i < ARRAY_SIZE (ipc_sysctls ); i ++ ) {
229
+ if (tbl [i ].data == & init_ipc_ns .shm_ctlmax ) {
230
+ tbl [i ].data = & ns -> shm_ctlmax ;
231
+
232
+ } else if (tbl [i ].data == & init_ipc_ns .shm_ctlall ) {
233
+ tbl [i ].data = & ns -> shm_ctlall ;
234
+
235
+ } else if (tbl [i ].data == & init_ipc_ns .shm_ctlmni ) {
236
+ tbl [i ].data = & ns -> shm_ctlmni ;
237
+
238
+ } else if (tbl [i ].data == & init_ipc_ns .shm_rmid_forced ) {
239
+ tbl [i ].data = & ns -> shm_rmid_forced ;
240
+ tbl [i ].extra1 = ns ;
241
+
242
+ } else if (tbl [i ].data == & init_ipc_ns .msg_ctlmax ) {
243
+ tbl [i ].data = & ns -> msg_ctlmax ;
244
+
245
+ } else if (tbl [i ].data == & init_ipc_ns .msg_ctlmni ) {
246
+ tbl [i ].data = & ns -> msg_ctlmni ;
247
+
248
+ } else if (tbl [i ].data == & init_ipc_ns .msg_ctlmnb ) {
249
+ tbl [i ].data = & ns -> msg_ctlmnb ;
250
+
251
+ } else if (tbl [i ].data == & init_ipc_ns .sem_ctls ) {
252
+ tbl [i ].data = & ns -> sem_ctls ;
253
+ tbl [i ].extra1 = ns ;
254
+ #ifdef CONFIG_CHECKPOINT_RESTORE
255
+ } else if (tbl [i ].data == & init_ipc_ns .ids [IPC_SEM_IDS ].next_id ) {
256
+ tbl [i ].data = & ns -> ids [IPC_SEM_IDS ].next_id ;
257
+ tbl [i ].extra1 = ns ;
258
+
259
+ } else if (tbl [i ].data == & init_ipc_ns .ids [IPC_MSG_IDS ].next_id ) {
260
+ tbl [i ].data = & ns -> ids [IPC_MSG_IDS ].next_id ;
261
+ tbl [i ].extra1 = ns ;
262
+
263
+ } else if (tbl [i ].data == & init_ipc_ns .ids [IPC_SHM_IDS ].next_id ) {
264
+ tbl [i ].data = & ns -> ids [IPC_SHM_IDS ].next_id ;
265
+ tbl [i ].extra1 = ns ;
266
+ #endif
267
+ } else {
268
+ tbl [i ].data = NULL ;
269
+ }
270
+ }
271
+
272
+ ns -> ipc_sysctls = __register_sysctl_table (& ns -> ipc_set , "kernel" , tbl );
273
+ }
274
+ if (!ns -> ipc_sysctls ) {
275
+ kfree (tbl );
276
+ retire_sysctl_set (& ns -> ipc_set );
277
+ return false;
278
+ }
279
+
280
+ return true;
281
+ }
282
+
283
+ void retire_ipc_sysctls (struct ipc_namespace * ns )
284
+ {
285
+ struct ctl_table * tbl ;
286
+
287
+ tbl = ns -> ipc_sysctls -> ctl_table_arg ;
288
+ unregister_sysctl_table (ns -> ipc_sysctls );
289
+ retire_sysctl_set (& ns -> ipc_set );
290
+ kfree (tbl );
291
+ }
292
+
241
293
static int __init ipc_sysctl_init (void )
242
294
{
243
- register_sysctl_table (ipc_root_table );
295
+ if (!setup_ipc_sysctls (& init_ipc_ns )) {
296
+ pr_warn ("ipc sysctl registration failed\n" );
297
+ return - ENOMEM ;
298
+ }
244
299
return 0 ;
245
300
}
246
301
0 commit comments