diff options
| author | Pierre Peiffer <pierre.peiffer@bull.net> | 2008-04-29 04:00:48 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-29 11:06:13 -0400 |
| commit | a0d092fc2df845a43cc4847836818f49331d0a5c (patch) | |
| tree | f47b94bfa2e18beadff39930c9386764e45bc4ec /ipc | |
| parent | 8d4cc8b5c5e5bac526618ee704f3cfdcad954e0c (diff) | |
IPC/message queues: introduce msgctl_down
Currently, sys_msgctl is not easy to read.
This patch tries to improve that by introducing the msgctl_down function to
handle all commands requiring the rwmutex to be taken in write mode (ie
IPC_SET and IPC_RMID for now). It is the equivalent function of semctl_down
for message queues.
This greatly changes the readability of sys_msgctl and also harmonizes the way
these commands are handled among all IPCs.
Signed-off-by: Pierre Peiffer <pierre.peiffer@bull.net>
Acked-by: Serge Hallyn <serue@us.ibm.com>
Cc: Nadia Derbey <Nadia.Derbey@bull.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'ipc')
| -rw-r--r-- | ipc/msg.c | 162 |
1 files changed, 89 insertions, 73 deletions
| @@ -436,10 +436,95 @@ copy_msqid_from_user(struct msq_setbuf *out, void __user *buf, int version) | |||
| 436 | } | 436 | } |
| 437 | } | 437 | } |
| 438 | 438 | ||
| 439 | asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf) | 439 | /* |
| 440 | * This function handles some msgctl commands which require the rw_mutex | ||
| 441 | * to be held in write mode. | ||
| 442 | * NOTE: no locks must be held, the rw_mutex is taken inside this function. | ||
| 443 | */ | ||
| 444 | static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd, | ||
| 445 | struct msqid_ds __user *buf, int version) | ||
| 440 | { | 446 | { |
| 441 | struct kern_ipc_perm *ipcp; | 447 | struct kern_ipc_perm *ipcp; |
| 442 | struct msq_setbuf uninitialized_var(setbuf); | 448 | struct msq_setbuf setbuf; |
| 449 | struct msg_queue *msq; | ||
| 450 | int err; | ||
| 451 | |||
| 452 | if (cmd == IPC_SET) { | ||
| 453 | if (copy_msqid_from_user(&setbuf, buf, version)) | ||
| 454 | return -EFAULT; | ||
| 455 | } | ||
| 456 | |||
| 457 | down_write(&msg_ids(ns).rw_mutex); | ||
| 458 | msq = msg_lock_check_down(ns, msqid); | ||
| 459 | if (IS_ERR(msq)) { | ||
| 460 | err = PTR_ERR(msq); | ||
| 461 | goto out_up; | ||
| 462 | } | ||
| 463 | |||
| 464 | ipcp = &msq->q_perm; | ||
| 465 | |||
| 466 | err = audit_ipc_obj(ipcp); | ||
| 467 | if (err) | ||
| 468 | goto out_unlock; | ||
| 469 | |||
| 470 | if (cmd == IPC_SET) { | ||
| 471 | err = audit_ipc_set_perm(setbuf.qbytes, setbuf.uid, setbuf.gid, | ||
| 472 | setbuf.mode); | ||
| 473 | if (err) | ||
| 474 | goto out_unlock; | ||
| 475 | } | ||
| 476 | |||
| 477 | if (current->euid != ipcp->cuid && | ||
| 478 | current->euid != ipcp->uid && | ||
| 479 | !capable(CAP_SYS_ADMIN)) { | ||
| 480 | /* We _could_ check for CAP_CHOWN above, but we don't */ | ||
| 481 | err = -EPERM; | ||
| 482 | goto out_unlock; | ||
| 483 | } | ||
| 484 | |||
| 485 | err = security_msg_queue_msgctl(msq, cmd); | ||
| 486 | if (err) | ||
| 487 | goto out_unlock; | ||
| 488 | |||
| 489 | switch (cmd) { | ||
| 490 | case IPC_RMID: | ||
| 491 | freeque(ns, ipcp); | ||
| 492 | goto out_up; | ||
| 493 | case IPC_SET: | ||
| 494 | if (setbuf.qbytes > ns->msg_ctlmnb && | ||
| 495 | !capable(CAP_SYS_RESOURCE)) { | ||
| 496 | err = -EPERM; | ||
| 497 | goto out_unlock; | ||
| 498 | } | ||
| 499 | |||
| 500 | msq->q_qbytes = setbuf.qbytes; | ||
| 501 | |||
| 502 | ipcp->uid = setbuf.uid; | ||
| 503 | ipcp->gid = setbuf.gid; | ||
| 504 | ipcp->mode = (ipcp->mode & ~S_IRWXUGO) | | ||
| 505 | (S_IRWXUGO & setbuf.mode); | ||
| 506 | msq->q_ctime = get_seconds(); | ||
| 507 | /* sleeping receivers might be excluded by | ||
| 508 | * stricter permissions. | ||
| 509 | */ | ||
| 510 | expunge_all(msq, -EAGAIN); | ||
| 511 | /* sleeping senders might be able to send | ||
| 512 | * due to a larger queue size. | ||
| 513 | */ | ||
| 514 | ss_wakeup(&msq->q_senders, 0); | ||
| 515 | break; | ||
| 516 | default: | ||
| 517 | err = -EINVAL; | ||
| 518 | } | ||
| 519 | out_unlock: | ||
| 520 | msg_unlock(msq); | ||
| 521 | out_up: | ||
| 522 | up_write(&msg_ids(ns).rw_mutex); | ||
| 523 | return err; | ||
| 524 | } | ||
| 525 | |||
| 526 | asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf) | ||
| 527 | { | ||
| 443 | struct msg_queue *msq; | 528 | struct msg_queue *msq; |
| 444 | int err, version; | 529 | int err, version; |
| 445 | struct ipc_namespace *ns; | 530 | struct ipc_namespace *ns; |
| @@ -535,82 +620,13 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf) | |||
| 535 | return success_return; | 620 | return success_return; |
| 536 | } | 621 | } |
| 537 | case IPC_SET: | 622 | case IPC_SET: |
| 538 | if (!buf) | ||
| 539 | return -EFAULT; | ||
| 540 | if (copy_msqid_from_user(&setbuf, buf, version)) | ||
| 541 | return -EFAULT; | ||
| 542 | break; | ||
| 543 | case IPC_RMID: | 623 | case IPC_RMID: |
| 544 | break; | 624 | err = msgctl_down(ns, msqid, cmd, buf, version); |
| 625 | return err; | ||
| 545 | default: | 626 | default: |
| 546 | return -EINVAL; | 627 | return -EINVAL; |
| 547 | } | 628 | } |
| 548 | 629 | ||
| 549 | down_write(&msg_ids(ns).rw_mutex); | ||
| 550 | msq = msg_lock_check_down(ns, msqid); | ||
| 551 | if (IS_ERR(msq)) { | ||
| 552 | err = PTR_ERR(msq); | ||
| 553 | goto out_up; | ||
| 554 | } | ||
| 555 | |||
| 556 | ipcp = &msq->q_perm; | ||
| 557 | |||
| 558 | err = audit_ipc_obj(ipcp); | ||
| 559 | if (err) | ||
| 560 | goto out_unlock_up; | ||
| 561 | if (cmd == IPC_SET) { | ||
| 562 | err = audit_ipc_set_perm(setbuf.qbytes, setbuf.uid, setbuf.gid, | ||
| 563 | setbuf.mode); | ||
| 564 | if (err) | ||
| 565 | goto out_unlock_up; | ||
| 566 | } | ||
| 567 | |||
| 568 | err = -EPERM; | ||
| 569 | if (current->euid != ipcp->cuid && | ||
| 570 | current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) | ||
| 571 | /* We _could_ check for CAP_CHOWN above, but we don't */ | ||
| 572 | goto out_unlock_up; | ||
| 573 | |||
| 574 | err = security_msg_queue_msgctl(msq, cmd); | ||
| 575 | if (err) | ||
| 576 | goto out_unlock_up; | ||
| 577 | |||
| 578 | switch (cmd) { | ||
| 579 | case IPC_SET: | ||
| 580 | { | ||
| 581 | err = -EPERM; | ||
| 582 | if (setbuf.qbytes > ns->msg_ctlmnb && !capable(CAP_SYS_RESOURCE)) | ||
| 583 | goto out_unlock_up; | ||
| 584 | |||
| 585 | msq->q_qbytes = setbuf.qbytes; | ||
| 586 | |||
| 587 | ipcp->uid = setbuf.uid; | ||
| 588 | ipcp->gid = setbuf.gid; | ||
| 589 | ipcp->mode = (ipcp->mode & ~S_IRWXUGO) | | ||
| 590 | (S_IRWXUGO & setbuf.mode); | ||
| 591 | msq->q_ctime = get_seconds(); | ||
| 592 | /* sleeping receivers might be excluded by | ||
| 593 | * stricter permissions. | ||
| 594 | */ | ||
| 595 | expunge_all(msq, -EAGAIN); | ||
| 596 | /* sleeping senders might be able to send | ||
| 597 | * due to a larger queue size. | ||
| 598 | */ | ||
| 599 | ss_wakeup(&msq->q_senders, 0); | ||
| 600 | msg_unlock(msq); | ||
| 601 | break; | ||
| 602 | } | ||
| 603 | case IPC_RMID: | ||
| 604 | freeque(ns, &msq->q_perm); | ||
| 605 | break; | ||
| 606 | } | ||
| 607 | err = 0; | ||
| 608 | out_up: | ||
| 609 | up_write(&msg_ids(ns).rw_mutex); | ||
| 610 | return err; | ||
| 611 | out_unlock_up: | ||
| 612 | msg_unlock(msq); | ||
| 613 | goto out_up; | ||
| 614 | out_unlock: | 630 | out_unlock: |
| 615 | msg_unlock(msq); | 631 | msg_unlock(msq); |
| 616 | return err; | 632 | return err; |
