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