aboutsummaryrefslogtreecommitdiffstats
path: root/ipc/shm.c
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/shm.c')
-rw-r--r--ipc/shm.c73
1 files changed, 27 insertions, 46 deletions
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)