aboutsummaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
Diffstat (limited to 'ipc')
-rw-r--r--ipc/msg.c61
-rw-r--r--ipc/sem.c76
-rw-r--r--ipc/shm.c73
-rw-r--r--ipc/util.c101
-rw-r--r--ipc/util.h43
5 files changed, 215 insertions, 139 deletions
diff --git a/ipc/msg.c b/ipc/msg.c
index 08591a0278ce..c2ee26f01055 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -81,7 +81,7 @@ static struct ipc_ids init_msg_ids;
81 ipc_buildid(&msg_ids(ns), id, seq) 81 ipc_buildid(&msg_ids(ns), id, seq)
82 82
83static void freeque(struct ipc_namespace *, struct msg_queue *); 83static void freeque(struct ipc_namespace *, struct msg_queue *);
84static int newque (struct ipc_namespace *ns, key_t key, int msgflg); 84static int newque(struct ipc_namespace *, struct ipc_params *);
85#ifdef CONFIG_PROC_FS 85#ifdef CONFIG_PROC_FS
86static int sysvipc_msg_proc_show(struct seq_file *s, void *it); 86static int sysvipc_msg_proc_show(struct seq_file *s, void *it);
87#endif 87#endif
@@ -144,10 +144,12 @@ static inline void msg_rmid(struct ipc_namespace *ns, struct msg_queue *s)
144 ipc_rmid(&msg_ids(ns), &s->q_perm); 144 ipc_rmid(&msg_ids(ns), &s->q_perm);
145} 145}
146 146
147static int newque (struct ipc_namespace *ns, key_t key, int msgflg) 147static int newque(struct ipc_namespace *ns, struct ipc_params *params)
148{ 148{
149 struct msg_queue *msq; 149 struct msg_queue *msq;
150 int id, retval; 150 int id, retval;
151 key_t key = params->key;
152 int msgflg = params->flg;
151 153
152 msq = ipc_rcu_alloc(sizeof(*msq)); 154 msq = ipc_rcu_alloc(sizeof(*msq));
153 if (!msq) 155 if (!msq)
@@ -264,56 +266,27 @@ static void freeque(struct ipc_namespace *ns, struct msg_queue *msq)
264 ipc_rcu_putref(msq); 266 ipc_rcu_putref(msq);
265} 267}
266 268
269static inline int msg_security(void *msq, int msgflg)
270{
271 return security_msg_queue_associate((struct msg_queue *) msq, msgflg);
272}
273
267asmlinkage long sys_msgget(key_t key, int msgflg) 274asmlinkage long sys_msgget(key_t key, int msgflg)
268{ 275{
269 struct msg_queue *msq;
270 int ret;
271 struct ipc_namespace *ns; 276 struct ipc_namespace *ns;
277 struct ipc_ops msg_ops;
278 struct ipc_params msg_params;
272 279
273 ns = current->nsproxy->ipc_ns; 280 ns = current->nsproxy->ipc_ns;
274 281
275 ret = idr_pre_get(&msg_ids(ns).ipcs_idr, GFP_KERNEL); 282 msg_ops.getnew = newque;
283 msg_ops.associate = msg_security;
284 msg_ops.more_checks = NULL;
276 285
277 if (key == IPC_PRIVATE) { 286 msg_params.key = key;
278 if (!ret) 287 msg_params.flg = msgflg;
279 ret = -ENOMEM;
280 else {
281 mutex_lock(&msg_ids(ns).mutex);
282 ret = newque(ns, key, msgflg);
283 mutex_unlock(&msg_ids(ns).mutex);
284 }
285 } else {
286 mutex_lock(&msg_ids(ns).mutex);
287 msq = (struct msg_queue *) ipc_findkey(&msg_ids(ns), key);
288 if (msq == NULL) {
289 /* key not used */
290 if (!(msgflg & IPC_CREAT))
291 ret = -ENOENT;
292 else if (!ret)
293 ret = -ENOMEM;
294 else
295 ret = newque(ns, key, msgflg);
296 } else {
297 /* msq has been locked by ipc_findkey() */
298
299 if (msgflg & IPC_CREAT && msgflg & IPC_EXCL)
300 ret = -EEXIST;
301 else {
302 if (ipcperms(&msq->q_perm, msgflg))
303 ret = -EACCES;
304 else {
305 ret = security_msg_queue_associate(
306 msq, msgflg);
307 if (!ret)
308 ret = msq->q_perm.id;
309 }
310 }
311 msg_unlock(msq);
312 }
313 mutex_unlock(&msg_ids(ns).mutex);
314 }
315 288
316 return ret; 289 return ipcget(ns, &msg_ids(ns), &msg_ops, &msg_params);
317} 290}
318 291
319static inline unsigned long 292static inline unsigned long
diff --git a/ipc/sem.c b/ipc/sem.c
index f92a2565d12b..6af226af0b90 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -97,7 +97,7 @@
97 97
98static struct ipc_ids init_sem_ids; 98static struct ipc_ids init_sem_ids;
99 99
100static int newary(struct ipc_namespace *, key_t, int, int); 100static int newary(struct ipc_namespace *, struct ipc_params *);
101static void freeary(struct ipc_namespace *, struct sem_array *); 101static void freeary(struct ipc_namespace *, struct sem_array *);
102#ifdef CONFIG_PROC_FS 102#ifdef CONFIG_PROC_FS
103static int sysvipc_sem_proc_show(struct seq_file *s, void *it); 103static int sysvipc_sem_proc_show(struct seq_file *s, void *it);
@@ -214,12 +214,15 @@ static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s)
214 */ 214 */
215#define IN_WAKEUP 1 215#define IN_WAKEUP 1
216 216
217static int newary (struct ipc_namespace *ns, key_t key, int nsems, int semflg) 217static int newary(struct ipc_namespace *ns, struct ipc_params *params)
218{ 218{
219 int id; 219 int id;
220 int retval; 220 int retval;
221 struct sem_array *sma; 221 struct sem_array *sma;
222 int size; 222 int size;
223 key_t key = params->key;
224 int nsems = params->u.nsems;
225 int semflg = params->flg;
223 226
224 if (!nsems) 227 if (!nsems)
225 return -EINVAL; 228 return -EINVAL;
@@ -263,61 +266,40 @@ static int newary (struct ipc_namespace *ns, key_t key, int nsems, int semflg)
263 return sma->sem_perm.id; 266 return sma->sem_perm.id;
264} 267}
265 268
266asmlinkage long sys_semget (key_t key, int nsems, int semflg) 269
270static inline int sem_security(void *sma, int semflg)
271{
272 return security_sem_associate((struct sem_array *) sma, semflg);
273}
274
275static inline int sem_more_checks(void *sma, struct ipc_params *params)
276{
277 if (params->u.nsems > ((struct sem_array *)sma)->sem_nsems)
278 return -EINVAL;
279
280 return 0;
281}
282
283asmlinkage long sys_semget(key_t key, int nsems, int semflg)
267{ 284{
268 int err;
269 struct sem_array *sma;
270 struct ipc_namespace *ns; 285 struct ipc_namespace *ns;
286 struct ipc_ops sem_ops;
287 struct ipc_params sem_params;
271 288
272 ns = current->nsproxy->ipc_ns; 289 ns = current->nsproxy->ipc_ns;
273 290
274 if (nsems < 0 || nsems > ns->sc_semmsl) 291 if (nsems < 0 || nsems > ns->sc_semmsl)
275 return -EINVAL; 292 return -EINVAL;
276 293
277 err = idr_pre_get(&sem_ids(ns).ipcs_idr, GFP_KERNEL); 294 sem_ops.getnew = newary;
295 sem_ops.associate = sem_security;
296 sem_ops.more_checks = sem_more_checks;
278 297
279 if (key == IPC_PRIVATE) { 298 sem_params.key = key;
280 if (!err) 299 sem_params.flg = semflg;
281 err = -ENOMEM; 300 sem_params.u.nsems = nsems;
282 else {
283 mutex_lock(&sem_ids(ns).mutex);
284 err = newary(ns, key, nsems, semflg);
285 mutex_unlock(&sem_ids(ns).mutex);
286 }
287 } else {
288 mutex_lock(&sem_ids(ns).mutex);
289 sma = (struct sem_array *) ipc_findkey(&sem_ids(ns), key);
290 if (sma == NULL) {
291 /* key not used */
292 if (!(semflg & IPC_CREAT))
293 err = -ENOENT;
294 else if (!err)
295 err = -ENOMEM;
296 else
297 err = newary(ns, key, nsems, semflg);
298 } else {
299 /* sma has been locked by ipc_findkey() */
300
301 if (semflg & IPC_CREAT && semflg & IPC_EXCL)
302 err = -EEXIST;
303 else {
304 if (nsems > sma->sem_nsems)
305 err = -EINVAL;
306 else if (ipcperms(&sma->sem_perm, semflg))
307 err = -EACCES;
308 else {
309 err = security_sem_associate(sma,
310 semflg);
311 if (!err)
312 err = sma->sem_perm.id;
313 }
314 }
315 sem_unlock(sma);
316 }
317 mutex_unlock(&sem_ids(ns).mutex);
318 }
319 301
320 return err; 302 return ipcget(ns, &sem_ids(ns), &sem_ops, &sem_params);
321} 303}
322 304
323/* Manage the doubly linked list sma->sem_pending as a FIFO: 305/* Manage the doubly linked list sma->sem_pending as a FIFO:
diff --git a/ipc/shm.c b/ipc/shm.c
index dcc333239683..d20cc25c5bdf 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -68,8 +68,7 @@ static struct ipc_ids init_shm_ids;
68#define shm_buildid(ns, id, seq) \ 68#define shm_buildid(ns, id, seq) \
69 ipc_buildid(&shm_ids(ns), id, seq) 69 ipc_buildid(&shm_ids(ns), id, seq)
70 70
71static int newseg (struct ipc_namespace *ns, key_t key, 71static int newseg(struct ipc_namespace *, struct ipc_params *);
72 int shmflg, size_t size);
73static void shm_open(struct vm_area_struct *vma); 72static void shm_open(struct vm_area_struct *vma);
74static void shm_close(struct vm_area_struct *vma); 73static void shm_close(struct vm_area_struct *vma);
75static void shm_destroy (struct ipc_namespace *ns, struct shmid_kernel *shp); 74static void shm_destroy (struct ipc_namespace *ns, struct shmid_kernel *shp);
@@ -341,8 +340,11 @@ static struct vm_operations_struct shm_vm_ops = {
341#endif 340#endif
342}; 341};
343 342
344static int newseg (struct ipc_namespace *ns, key_t key, int shmflg, size_t size) 343static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
345{ 344{
345 key_t key = params->key;
346 int shmflg = params->flg;
347 size_t size = params->u.size;
346 int error; 348 int error;
347 struct shmid_kernel *shp; 349 struct shmid_kernel *shp;
348 int numpages = (size + PAGE_SIZE -1) >> PAGE_SHIFT; 350 int numpages = (size + PAGE_SIZE -1) >> PAGE_SHIFT;
@@ -423,57 +425,36 @@ no_file:
423 return error; 425 return error;
424} 426}
425 427
428static inline int shm_security(void *shp, int shmflg)
429{
430 return security_shm_associate((struct shmid_kernel *) shp, shmflg);
431}
432
433static inline int shm_more_checks(void *shp, struct ipc_params *params)
434{
435 if (((struct shmid_kernel *)shp)->shm_segsz < params->u.size)
436 return -EINVAL;
437
438 return 0;
439}
440
426asmlinkage long sys_shmget (key_t key, size_t size, int shmflg) 441asmlinkage long sys_shmget (key_t key, size_t size, int shmflg)
427{ 442{
428 struct shmid_kernel *shp;
429 int err;
430 struct ipc_namespace *ns; 443 struct ipc_namespace *ns;
444 struct ipc_ops shm_ops;
445 struct ipc_params shm_params;
431 446
432 ns = current->nsproxy->ipc_ns; 447 ns = current->nsproxy->ipc_ns;
433 448
434 err = idr_pre_get(&shm_ids(ns).ipcs_idr, GFP_KERNEL); 449 shm_ops.getnew = newseg;
450 shm_ops.associate = shm_security;
451 shm_ops.more_checks = shm_more_checks;
435 452
436 if (key == IPC_PRIVATE) { 453 shm_params.key = key;
437 if (!err) 454 shm_params.flg = shmflg;
438 err = -ENOMEM; 455 shm_params.u.size = size;
439 else {
440 mutex_lock(&shm_ids(ns).mutex);
441 err = newseg(ns, key, shmflg, size);
442 mutex_unlock(&shm_ids(ns).mutex);
443 }
444 } else {
445 mutex_lock(&shm_ids(ns).mutex);
446 shp = (struct shmid_kernel *) ipc_findkey(&shm_ids(ns), key);
447 if (shp == NULL) {
448 if (!(shmflg & IPC_CREAT))
449 err = -ENOENT;
450 else if (!err)
451 err = -ENOMEM;
452 else
453 err = newseg(ns, key, shmflg, size);
454 } else {
455 /* shp has been locked by ipc_findkey() */
456
457 if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL))
458 err = -EEXIST;
459 else {
460 if (shp->shm_segsz < size)
461 err = -EINVAL;
462 else if (ipcperms(&shp->shm_perm, shmflg))
463 err = -EACCES;
464 else {
465 err = security_shm_associate(shp,
466 shmflg);
467 if (!err)
468 err = shp->shm_perm.id;
469 }
470 }
471 shm_unlock(shp);
472 }
473 mutex_unlock(&shm_ids(ns).mutex);
474 }
475 456
476 return err; 457 return ipcget(ns, &shm_ids(ns), &shm_ops, &shm_params);
477} 458}
478 459
479static inline unsigned long copy_shmid_to_user(void __user *buf, struct shmid64_ds *in, int version) 460static inline unsigned long copy_shmid_to_user(void __user *buf, struct shmid64_ds *in, int version)
diff --git a/ipc/util.c b/ipc/util.c
index 2a205875d277..03b88798f71f 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -197,7 +197,7 @@ void __init ipc_init_proc_interface(const char *path, const char *header,
197 * If key is found ipc contains its ipc structure 197 * If key is found ipc contains its ipc structure
198 */ 198 */
199 199
200struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key) 200static struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key)
201{ 201{
202 struct kern_ipc_perm *ipc; 202 struct kern_ipc_perm *ipc;
203 int next_id; 203 int next_id;
@@ -301,6 +301,105 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
301} 301}
302 302
303/** 303/**
304 * ipcget_new - create a new ipc object
305 * @ns: namespace
306 * @ids: identifer set
307 * @ops: the actual creation routine to call
308 * @params: its parameters
309 *
310 * This routine is called sys_msgget, sys_semget() and sys_shmget() when
311 * the key is IPC_PRIVATE
312 */
313int ipcget_new(struct ipc_namespace *ns, struct ipc_ids *ids,
314 struct ipc_ops *ops, struct ipc_params *params)
315{
316 int err;
317
318 err = idr_pre_get(&ids->ipcs_idr, GFP_KERNEL);
319
320 if (!err)
321 return -ENOMEM;
322
323 mutex_lock(&ids->mutex);
324 err = ops->getnew(ns, params);
325 mutex_unlock(&ids->mutex);
326
327 return err;
328}
329
330/**
331 * ipc_check_perms - check security and permissions for an IPC
332 * @ipcp: ipc permission set
333 * @ids: identifer set
334 * @ops: the actual security routine to call
335 * @params: its parameters
336 */
337static int ipc_check_perms(struct kern_ipc_perm *ipcp, struct ipc_ops *ops,
338 struct ipc_params *params)
339{
340 int err;
341
342 if (ipcperms(ipcp, params->flg))
343 err = -EACCES;
344 else {
345 err = ops->associate(ipcp, params->flg);
346 if (!err)
347 err = ipcp->id;
348 }
349
350 return err;
351}
352
353/**
354 * ipcget_public - get an ipc object or create a new one
355 * @ns: namespace
356 * @ids: identifer set
357 * @ops: the actual creation routine to call
358 * @params: its parameters
359 *
360 * This routine is called sys_msgget, sys_semget() and sys_shmget() when
361 * the key is not IPC_PRIVATE
362 */
363int ipcget_public(struct ipc_namespace *ns, struct ipc_ids *ids,
364 struct ipc_ops *ops, struct ipc_params *params)
365{
366 struct kern_ipc_perm *ipcp;
367 int flg = params->flg;
368 int err;
369
370 err = idr_pre_get(&ids->ipcs_idr, GFP_KERNEL);
371
372 mutex_lock(&ids->mutex);
373 ipcp = ipc_findkey(ids, params->key);
374 if (ipcp == NULL) {
375 /* key not used */
376 if (!(flg & IPC_CREAT))
377 err = -ENOENT;
378 else if (!err)
379 err = -ENOMEM;
380 else
381 err = ops->getnew(ns, params);
382 } else {
383 /* ipc object has been locked by ipc_findkey() */
384
385 if (flg & IPC_CREAT && flg & IPC_EXCL)
386 err = -EEXIST;
387 else {
388 err = 0;
389 if (ops->more_checks)
390 err = ops->more_checks(ipcp, params);
391 if (!err)
392 err = ipc_check_perms(ipcp, ops, params);
393 }
394 ipc_unlock(ipcp);
395 }
396 mutex_unlock(&ids->mutex);
397
398 return err;
399}
400
401
402/**
304 * ipc_rmid - remove an IPC identifier 403 * ipc_rmid - remove an IPC identifier
305 * @ids: identifier set 404 * @ids: identifier set
306 * @id: ipc perm structure containing the identifier to remove 405 * @id: ipc perm structure containing the identifier to remove
diff --git a/ipc/util.h b/ipc/util.h
index c9063267d4f8..30b2a6d7cbed 100644
--- a/ipc/util.h
+++ b/ipc/util.h
@@ -35,6 +35,35 @@ struct ipc_ids {
35 struct idr ipcs_idr; 35 struct idr ipcs_idr;
36}; 36};
37 37
38/*
39 * Structure that holds the parameters needed by the ipc operations
40 * (see after)
41 */
42struct ipc_params {
43 key_t key;
44 int flg;
45 union {
46 size_t size; /* for shared memories */
47 int nsems; /* for semaphores */
48 } u; /* holds the getnew() specific param */
49};
50
51/*
52 * Structure that holds some ipc operations. This structure is used to unify
53 * the calls to sys_msgget(), sys_semget(), sys_shmget()
54 * . routine to call to create a new ipc object. Can be one of newque,
55 * newary, newseg
56 * . routine to call to call to check permissions for a new ipc object.
57 * Can be one of security_msg_associate, security_sem_associate,
58 * security_shm_associate
59 * . routine to call for an extra check if needed
60 */
61struct ipc_ops {
62 int (*getnew) (struct ipc_namespace *, struct ipc_params *);
63 int (*associate) (void *, int);
64 int (*more_checks) (void *, struct ipc_params *);
65};
66
38struct seq_file; 67struct seq_file;
39 68
40void ipc_init_ids(struct ipc_ids *); 69void ipc_init_ids(struct ipc_ids *);
@@ -50,7 +79,6 @@ void __init ipc_init_proc_interface(const char *path, const char *header,
50#define IPC_SHM_IDS 2 79#define IPC_SHM_IDS 2
51 80
52/* must be called with ids->mutex acquired.*/ 81/* must be called with ids->mutex acquired.*/
53struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key);
54int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int); 82int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int);
55int ipc_get_maxid(struct ipc_ids *); 83int ipc_get_maxid(struct ipc_ids *);
56 84
@@ -95,5 +123,18 @@ int ipc_parse_version (int *cmd);
95extern void free_msg(struct msg_msg *msg); 123extern void free_msg(struct msg_msg *msg);
96extern struct msg_msg *load_msg(const void __user *src, int len); 124extern struct msg_msg *load_msg(const void __user *src, int len);
97extern int store_msg(void __user *dest, struct msg_msg *msg, int len); 125extern int store_msg(void __user *dest, struct msg_msg *msg, int len);
126extern int ipcget_new(struct ipc_namespace *, struct ipc_ids *,
127 struct ipc_ops *, struct ipc_params *);
128extern int ipcget_public(struct ipc_namespace *, struct ipc_ids *,
129 struct ipc_ops *, struct ipc_params *);
130
131static inline int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids,
132 struct ipc_ops *ops, struct ipc_params *params)
133{
134 if (params->key == IPC_PRIVATE)
135 return ipcget_new(ns, ids, ops, params);
136 else
137 return ipcget_public(ns, ids, ops, params);
138}
98 139
99#endif 140#endif