diff options
Diffstat (limited to 'ipc/shm.c')
-rw-r--r-- | ipc/shm.c | 73 |
1 files changed, 27 insertions, 46 deletions
@@ -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 | ||
71 | static int newseg (struct ipc_namespace *ns, key_t key, | 71 | static int newseg(struct ipc_namespace *, struct ipc_params *); |
72 | int shmflg, size_t size); | ||
73 | static void shm_open(struct vm_area_struct *vma); | 72 | static void shm_open(struct vm_area_struct *vma); |
74 | static void shm_close(struct vm_area_struct *vma); | 73 | static void shm_close(struct vm_area_struct *vma); |
75 | static void shm_destroy (struct ipc_namespace *ns, struct shmid_kernel *shp); | 74 | static 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 | ||
344 | static int newseg (struct ipc_namespace *ns, key_t key, int shmflg, size_t size) | 343 | static 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 | ||
428 | static inline int shm_security(void *shp, int shmflg) | ||
429 | { | ||
430 | return security_shm_associate((struct shmid_kernel *) shp, shmflg); | ||
431 | } | ||
432 | |||
433 | static 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 | |||
426 | asmlinkage long sys_shmget (key_t key, size_t size, int shmflg) | 441 | asmlinkage 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 | ||
479 | static inline unsigned long copy_shmid_to_user(void __user *buf, struct shmid64_ds *in, int version) | 460 | static inline unsigned long copy_shmid_to_user(void __user *buf, struct shmid64_ds *in, int version) |