aboutsummaryrefslogtreecommitdiffstats
path: root/ipc/msg.c
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/msg.c')
-rw-r--r--ipc/msg.c202
1 files changed, 96 insertions, 106 deletions
diff --git a/ipc/msg.c b/ipc/msg.c
index 5b25e0755656..322e7bf8b8d1 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -361,23 +361,17 @@ copy_msqid_from_user(struct msqid64_ds *out, void __user *buf, int version)
361 * NOTE: no locks must be held, the rwsem is taken inside this function. 361 * NOTE: no locks must be held, the rwsem is taken inside this function.
362 */ 362 */
363static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd, 363static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
364 struct msqid_ds __user *buf, int version) 364 struct msqid64_ds *msqid64)
365{ 365{
366 struct kern_ipc_perm *ipcp; 366 struct kern_ipc_perm *ipcp;
367 struct msqid64_ds uninitialized_var(msqid64);
368 struct msg_queue *msq; 367 struct msg_queue *msq;
369 int err; 368 int err;
370 369
371 if (cmd == IPC_SET) {
372 if (copy_msqid_from_user(&msqid64, buf, version))
373 return -EFAULT;
374 }
375
376 down_write(&msg_ids(ns).rwsem); 370 down_write(&msg_ids(ns).rwsem);
377 rcu_read_lock(); 371 rcu_read_lock();
378 372
379 ipcp = ipcctl_pre_down_nolock(ns, &msg_ids(ns), msqid, cmd, 373 ipcp = ipcctl_pre_down_nolock(ns, &msg_ids(ns), msqid, cmd,
380 &msqid64.msg_perm, msqid64.msg_qbytes); 374 &msqid64->msg_perm, msqid64->msg_qbytes);
381 if (IS_ERR(ipcp)) { 375 if (IS_ERR(ipcp)) {
382 err = PTR_ERR(ipcp); 376 err = PTR_ERR(ipcp);
383 goto out_unlock1; 377 goto out_unlock1;
@@ -399,18 +393,18 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
399 { 393 {
400 DEFINE_WAKE_Q(wake_q); 394 DEFINE_WAKE_Q(wake_q);
401 395
402 if (msqid64.msg_qbytes > ns->msg_ctlmnb && 396 if (msqid64->msg_qbytes > ns->msg_ctlmnb &&
403 !capable(CAP_SYS_RESOURCE)) { 397 !capable(CAP_SYS_RESOURCE)) {
404 err = -EPERM; 398 err = -EPERM;
405 goto out_unlock1; 399 goto out_unlock1;
406 } 400 }
407 401
408 ipc_lock_object(&msq->q_perm); 402 ipc_lock_object(&msq->q_perm);
409 err = ipc_update_perm(&msqid64.msg_perm, ipcp); 403 err = ipc_update_perm(&msqid64->msg_perm, ipcp);
410 if (err) 404 if (err)
411 goto out_unlock0; 405 goto out_unlock0;
412 406
413 msq->q_qbytes = msqid64.msg_qbytes; 407 msq->q_qbytes = msqid64->msg_qbytes;
414 408
415 msq->q_ctime = get_seconds(); 409 msq->q_ctime = get_seconds();
416 /* 410 /*
@@ -442,111 +436,89 @@ out_up:
442 return err; 436 return err;
443} 437}
444 438
445static int msgctl_nolock(struct ipc_namespace *ns, int msqid, 439static int msgctl_info(struct ipc_namespace *ns, int msqid,
446 int cmd, int version, void __user *buf) 440 int cmd, struct msginfo *msginfo)
447{ 441{
448 int err; 442 int err;
449 struct msg_queue *msq; 443 int max_id;
450
451 switch (cmd) {
452 case IPC_INFO:
453 case MSG_INFO:
454 {
455 struct msginfo msginfo;
456 int max_id;
457
458 if (!buf)
459 return -EFAULT;
460 444
461 /* 445 /*
462 * We must not return kernel stack data. 446 * We must not return kernel stack data.
463 * due to padding, it's not enough 447 * due to padding, it's not enough
464 * to set all member fields. 448 * to set all member fields.
465 */ 449 */
466 err = security_msg_queue_msgctl(NULL, cmd); 450 err = security_msg_queue_msgctl(NULL, cmd);
467 if (err) 451 if (err)
468 return err; 452 return err;
469 453
470 memset(&msginfo, 0, sizeof(msginfo)); 454 memset(msginfo, 0, sizeof(*msginfo));
471 msginfo.msgmni = ns->msg_ctlmni; 455 msginfo->msgmni = ns->msg_ctlmni;
472 msginfo.msgmax = ns->msg_ctlmax; 456 msginfo->msgmax = ns->msg_ctlmax;
473 msginfo.msgmnb = ns->msg_ctlmnb; 457 msginfo->msgmnb = ns->msg_ctlmnb;
474 msginfo.msgssz = MSGSSZ; 458 msginfo->msgssz = MSGSSZ;
475 msginfo.msgseg = MSGSEG; 459 msginfo->msgseg = MSGSEG;
476 down_read(&msg_ids(ns).rwsem); 460 down_read(&msg_ids(ns).rwsem);
477 if (cmd == MSG_INFO) { 461 if (cmd == MSG_INFO) {
478 msginfo.msgpool = msg_ids(ns).in_use; 462 msginfo->msgpool = msg_ids(ns).in_use;
479 msginfo.msgmap = atomic_read(&ns->msg_hdrs); 463 msginfo->msgmap = atomic_read(&ns->msg_hdrs);
480 msginfo.msgtql = atomic_read(&ns->msg_bytes); 464 msginfo->msgtql = atomic_read(&ns->msg_bytes);
481 } else { 465 } else {
482 msginfo.msgmap = MSGMAP; 466 msginfo->msgmap = MSGMAP;
483 msginfo.msgpool = MSGPOOL; 467 msginfo->msgpool = MSGPOOL;
484 msginfo.msgtql = MSGTQL; 468 msginfo->msgtql = MSGTQL;
485 }
486 max_id = ipc_get_maxid(&msg_ids(ns));
487 up_read(&msg_ids(ns).rwsem);
488 if (copy_to_user(buf, &msginfo, sizeof(struct msginfo)))
489 return -EFAULT;
490 return (max_id < 0) ? 0 : max_id;
491 } 469 }
470 max_id = ipc_get_maxid(&msg_ids(ns));
471 up_read(&msg_ids(ns).rwsem);
472 return (max_id < 0) ? 0 : max_id;
473}
492 474
493 case MSG_STAT: 475static int msgctl_stat(struct ipc_namespace *ns, int msqid,
494 case IPC_STAT: 476 int cmd, struct msqid64_ds *p)
495 { 477{
496 struct msqid64_ds tbuf; 478 int err;
497 int success_return; 479 struct msg_queue *msq;
498 480 int success_return;
499 if (!buf)
500 return -EFAULT;
501
502 memset(&tbuf, 0, sizeof(tbuf));
503 481
504 rcu_read_lock(); 482 memset(p, 0, sizeof(*p));
505 if (cmd == MSG_STAT) {
506 msq = msq_obtain_object(ns, msqid);
507 if (IS_ERR(msq)) {
508 err = PTR_ERR(msq);
509 goto out_unlock;
510 }
511 success_return = msq->q_perm.id;
512 } else {
513 msq = msq_obtain_object_check(ns, msqid);
514 if (IS_ERR(msq)) {
515 err = PTR_ERR(msq);
516 goto out_unlock;
517 }
518 success_return = 0;
519 }
520 483
521 err = -EACCES; 484 rcu_read_lock();
522 if (ipcperms(ns, &msq->q_perm, S_IRUGO)) 485 if (cmd == MSG_STAT) {
486 msq = msq_obtain_object(ns, msqid);
487 if (IS_ERR(msq)) {
488 err = PTR_ERR(msq);
523 goto out_unlock; 489 goto out_unlock;
524 490 }
525 err = security_msg_queue_msgctl(msq, cmd); 491 success_return = msq->q_perm.id;
526 if (err) 492 } else {
493 msq = msq_obtain_object_check(ns, msqid);
494 if (IS_ERR(msq)) {
495 err = PTR_ERR(msq);
527 goto out_unlock; 496 goto out_unlock;
497 }
498 success_return = 0;
499 }
528 500
529 kernel_to_ipc64_perm(&msq->q_perm, &tbuf.msg_perm); 501 err = -EACCES;
530 tbuf.msg_stime = msq->q_stime; 502 if (ipcperms(ns, &msq->q_perm, S_IRUGO))
531 tbuf.msg_rtime = msq->q_rtime; 503 goto out_unlock;
532 tbuf.msg_ctime = msq->q_ctime;
533 tbuf.msg_cbytes = msq->q_cbytes;
534 tbuf.msg_qnum = msq->q_qnum;
535 tbuf.msg_qbytes = msq->q_qbytes;
536 tbuf.msg_lspid = msq->q_lspid;
537 tbuf.msg_lrpid = msq->q_lrpid;
538 rcu_read_unlock();
539 504
540 if (copy_msqid_to_user(buf, &tbuf, version)) 505 err = security_msg_queue_msgctl(msq, cmd);
541 return -EFAULT; 506 if (err)
542 return success_return; 507 goto out_unlock;
543 } 508
509 kernel_to_ipc64_perm(&msq->q_perm, &p->msg_perm);
510 p->msg_stime = msq->q_stime;
511 p->msg_rtime = msq->q_rtime;
512 p->msg_ctime = msq->q_ctime;
513 p->msg_cbytes = msq->q_cbytes;
514 p->msg_qnum = msq->q_qnum;
515 p->msg_qbytes = msq->q_qbytes;
516 p->msg_lspid = msq->q_lspid;
517 p->msg_lrpid = msq->q_lrpid;
518 rcu_read_unlock();
544 519
545 default: 520 return success_return;
546 return -EINVAL;
547 }
548 521
549 return err;
550out_unlock: 522out_unlock:
551 rcu_read_unlock(); 523 rcu_read_unlock();
552 return err; 524 return err;
@@ -556,6 +528,8 @@ SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf)
556{ 528{
557 int version; 529 int version;
558 struct ipc_namespace *ns; 530 struct ipc_namespace *ns;
531 struct msqid64_ds msqid64;
532 int err;
559 533
560 if (msqid < 0 || cmd < 0) 534 if (msqid < 0 || cmd < 0)
561 return -EINVAL; 535 return -EINVAL;
@@ -565,13 +539,29 @@ SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf)
565 539
566 switch (cmd) { 540 switch (cmd) {
567 case IPC_INFO: 541 case IPC_INFO:
568 case MSG_INFO: 542 case MSG_INFO: {
543 struct msginfo msginfo;
544 err = msgctl_info(ns, msqid, cmd, &msginfo);
545 if (err < 0)
546 return err;
547 if (copy_to_user(buf, &msginfo, sizeof(struct msginfo)))
548 err = -EFAULT;
549 return err;
550 }
569 case MSG_STAT: /* msqid is an index rather than a msg queue id */ 551 case MSG_STAT: /* msqid is an index rather than a msg queue id */
570 case IPC_STAT: 552 case IPC_STAT:
571 return msgctl_nolock(ns, msqid, cmd, version, buf); 553 err = msgctl_stat(ns, msqid, cmd, &msqid64);
554 if (err < 0)
555 return err;
556 if (copy_msqid_to_user(buf, &msqid64, version))
557 err = -EFAULT;
558 return err;
572 case IPC_SET: 559 case IPC_SET:
560 if (copy_msqid_from_user(&msqid64, buf, version))
561 return -EFAULT;
562 /* fallthru */
573 case IPC_RMID: 563 case IPC_RMID:
574 return msgctl_down(ns, msqid, cmd, buf, version); 564 return msgctl_down(ns, msqid, cmd, &msqid64);
575 default: 565 default:
576 return -EINVAL; 566 return -EINVAL;
577 } 567 }