aboutsummaryrefslogtreecommitdiffstats
path: root/ipc/msg.c
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/msg.c')
-rw-r--r--ipc/msg.c366
1 files changed, 255 insertions, 111 deletions
diff --git a/ipc/msg.c b/ipc/msg.c
index df82bc9a5531..06be5a9adfa4 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -133,7 +133,7 @@ static int newque(struct ipc_namespace *ns, struct ipc_params *params)
133 } 133 }
134 134
135 msq->q_stime = msq->q_rtime = 0; 135 msq->q_stime = msq->q_rtime = 0;
136 msq->q_ctime = get_seconds(); 136 msq->q_ctime = ktime_get_real_seconds();
137 msq->q_cbytes = msq->q_qnum = 0; 137 msq->q_cbytes = msq->q_qnum = 0;
138 msq->q_qbytes = ns->msg_ctlmnb; 138 msq->q_qbytes = ns->msg_ctlmnb;
139 msq->q_lspid = msq->q_lrpid = 0; 139 msq->q_lspid = msq->q_lrpid = 0;
@@ -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,20 +393,20 @@ 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 = ktime_get_real_seconds();
416 /* 410 /*
417 * Sleeping receivers might be excluded by 411 * Sleeping receivers might be excluded by
418 * stricter permissions. 412 * stricter permissions.
@@ -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
461 /*
462 * We must not return kernel stack data.
463 * due to padding, it's not enough
464 * to set all member fields.
465 */
466 err = security_msg_queue_msgctl(NULL, cmd);
467 if (err)
468 return err;
469 444
470 memset(&msginfo, 0, sizeof(msginfo)); 445 /*
471 msginfo.msgmni = ns->msg_ctlmni; 446 * We must not return kernel stack data.
472 msginfo.msgmax = ns->msg_ctlmax; 447 * due to padding, it's not enough
473 msginfo.msgmnb = ns->msg_ctlmnb; 448 * to set all member fields.
474 msginfo.msgssz = MSGSSZ; 449 */
475 msginfo.msgseg = MSGSEG; 450 err = security_msg_queue_msgctl(NULL, cmd);
476 down_read(&msg_ids(ns).rwsem); 451 if (err)
477 if (cmd == MSG_INFO) { 452 return err;
478 msginfo.msgpool = msg_ids(ns).in_use; 453
479 msginfo.msgmap = atomic_read(&ns->msg_hdrs); 454 memset(msginfo, 0, sizeof(*msginfo));
480 msginfo.msgtql = atomic_read(&ns->msg_bytes); 455 msginfo->msgmni = ns->msg_ctlmni;
481 } else { 456 msginfo->msgmax = ns->msg_ctlmax;
482 msginfo.msgmap = MSGMAP; 457 msginfo->msgmnb = ns->msg_ctlmnb;
483 msginfo.msgpool = MSGPOOL; 458 msginfo->msgssz = MSGSSZ;
484 msginfo.msgtql = MSGTQL; 459 msginfo->msgseg = MSGSEG;
485 } 460 down_read(&msg_ids(ns).rwsem);
486 max_id = ipc_get_maxid(&msg_ids(ns)); 461 if (cmd == MSG_INFO) {
487 up_read(&msg_ids(ns).rwsem); 462 msginfo->msgpool = msg_ids(ns).in_use;
488 if (copy_to_user(buf, &msginfo, sizeof(struct msginfo))) 463 msginfo->msgmap = atomic_read(&ns->msg_hdrs);
489 return -EFAULT; 464 msginfo->msgtql = atomic_read(&ns->msg_bytes);
490 return (max_id < 0) ? 0 : max_id; 465 } else {
466 msginfo->msgmap = MSGMAP;
467 msginfo->msgpool = MSGPOOL;
468 msginfo->msgtql = MSGTQL;
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,18 +539,147 @@ 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 }
578} 568}
579 569
570#ifdef CONFIG_COMPAT
571
572struct compat_msqid_ds {
573 struct compat_ipc_perm msg_perm;
574 compat_uptr_t msg_first;
575 compat_uptr_t msg_last;
576 compat_time_t msg_stime;
577 compat_time_t msg_rtime;
578 compat_time_t msg_ctime;
579 compat_ulong_t msg_lcbytes;
580 compat_ulong_t msg_lqbytes;
581 unsigned short msg_cbytes;
582 unsigned short msg_qnum;
583 unsigned short msg_qbytes;
584 compat_ipc_pid_t msg_lspid;
585 compat_ipc_pid_t msg_lrpid;
586};
587
588static int copy_compat_msqid_from_user(struct msqid64_ds *out, void __user *buf,
589 int version)
590{
591 memset(out, 0, sizeof(*out));
592 if (version == IPC_64) {
593 struct compat_msqid64_ds *p = buf;
594 if (get_compat_ipc64_perm(&out->msg_perm, &p->msg_perm))
595 return -EFAULT;
596 if (get_user(out->msg_qbytes, &p->msg_qbytes))
597 return -EFAULT;
598 } else {
599 struct compat_msqid_ds *p = buf;
600 if (get_compat_ipc_perm(&out->msg_perm, &p->msg_perm))
601 return -EFAULT;
602 if (get_user(out->msg_qbytes, &p->msg_qbytes))
603 return -EFAULT;
604 }
605 return 0;
606}
607
608static int copy_compat_msqid_to_user(void __user *buf, struct msqid64_ds *in,
609 int version)
610{
611 if (version == IPC_64) {
612 struct compat_msqid64_ds v;
613 memset(&v, 0, sizeof(v));
614 to_compat_ipc64_perm(&v.msg_perm, &in->msg_perm);
615 v.msg_stime = in->msg_stime;
616 v.msg_rtime = in->msg_rtime;
617 v.msg_ctime = in->msg_ctime;
618 v.msg_cbytes = in->msg_cbytes;
619 v.msg_qnum = in->msg_qnum;
620 v.msg_qbytes = in->msg_qbytes;
621 v.msg_lspid = in->msg_lspid;
622 v.msg_lrpid = in->msg_lrpid;
623 return copy_to_user(buf, &v, sizeof(v));
624 } else {
625 struct compat_msqid_ds v;
626 memset(&v, 0, sizeof(v));
627 to_compat_ipc_perm(&v.msg_perm, &in->msg_perm);
628 v.msg_stime = in->msg_stime;
629 v.msg_rtime = in->msg_rtime;
630 v.msg_ctime = in->msg_ctime;
631 v.msg_cbytes = in->msg_cbytes;
632 v.msg_qnum = in->msg_qnum;
633 v.msg_qbytes = in->msg_qbytes;
634 v.msg_lspid = in->msg_lspid;
635 v.msg_lrpid = in->msg_lrpid;
636 return copy_to_user(buf, &v, sizeof(v));
637 }
638}
639
640COMPAT_SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, void __user *, uptr)
641{
642 struct ipc_namespace *ns;
643 int err;
644 struct msqid64_ds msqid64;
645 int version = compat_ipc_parse_version(&cmd);
646
647 ns = current->nsproxy->ipc_ns;
648
649 if (msqid < 0 || cmd < 0)
650 return -EINVAL;
651
652 switch (cmd & (~IPC_64)) {
653 case IPC_INFO:
654 case MSG_INFO: {
655 struct msginfo msginfo;
656 err = msgctl_info(ns, msqid, cmd, &msginfo);
657 if (err < 0)
658 return err;
659 if (copy_to_user(uptr, &msginfo, sizeof(struct msginfo)))
660 err = -EFAULT;
661 return err;
662 }
663 case IPC_STAT:
664 case MSG_STAT:
665 err = msgctl_stat(ns, msqid, cmd, &msqid64);
666 if (err < 0)
667 return err;
668 if (copy_compat_msqid_to_user(uptr, &msqid64, version))
669 err = -EFAULT;
670 return err;
671 case IPC_SET:
672 if (copy_compat_msqid_from_user(&msqid64, uptr, version))
673 return -EFAULT;
674 /* fallthru */
675 case IPC_RMID:
676 return msgctl_down(ns, msqid, cmd, &msqid64);
677 default:
678 return -EINVAL;
679 }
680}
681#endif
682
580static int testmsg(struct msg_msg *msg, long type, int mode) 683static int testmsg(struct msg_msg *msg, long type, int mode)
581{ 684{
582 switch (mode) { 685 switch (mode) {
@@ -627,7 +730,7 @@ static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg,
627 return 0; 730 return 0;
628} 731}
629 732
630long do_msgsnd(int msqid, long mtype, void __user *mtext, 733static long do_msgsnd(int msqid, long mtype, void __user *mtext,
631 size_t msgsz, int msgflg) 734 size_t msgsz, int msgflg)
632{ 735{
633 struct msg_queue *msq; 736 struct msg_queue *msq;
@@ -750,6 +853,25 @@ SYSCALL_DEFINE4(msgsnd, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz,
750 return do_msgsnd(msqid, mtype, msgp->mtext, msgsz, msgflg); 853 return do_msgsnd(msqid, mtype, msgp->mtext, msgsz, msgflg);
751} 854}
752 855
856#ifdef CONFIG_COMPAT
857
858struct compat_msgbuf {
859 compat_long_t mtype;
860 char mtext[1];
861};
862
863COMPAT_SYSCALL_DEFINE4(msgsnd, int, msqid, compat_uptr_t, msgp,
864 compat_ssize_t, msgsz, int, msgflg)
865{
866 struct compat_msgbuf __user *up = compat_ptr(msgp);
867 compat_long_t mtype;
868
869 if (get_user(mtype, &up->mtype))
870 return -EFAULT;
871 return do_msgsnd(msqid, mtype, up->mtext, (ssize_t)msgsz, msgflg);
872}
873#endif
874
753static inline int convert_mode(long *msgtyp, int msgflg) 875static inline int convert_mode(long *msgtyp, int msgflg)
754{ 876{
755 if (msgflg & MSG_COPY) 877 if (msgflg & MSG_COPY)
@@ -846,7 +968,7 @@ static struct msg_msg *find_msg(struct msg_queue *msq, long *msgtyp, int mode)
846 return found ?: ERR_PTR(-EAGAIN); 968 return found ?: ERR_PTR(-EAGAIN);
847} 969}
848 970
849long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgflg, 971static long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgflg,
850 long (*msg_handler)(void __user *, struct msg_msg *, size_t)) 972 long (*msg_handler)(void __user *, struct msg_msg *, size_t))
851{ 973{
852 int mode; 974 int mode;
@@ -1010,6 +1132,28 @@ SYSCALL_DEFINE5(msgrcv, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz,
1010 return do_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg, do_msg_fill); 1132 return do_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg, do_msg_fill);
1011} 1133}
1012 1134
1135#ifdef CONFIG_COMPAT
1136static long compat_do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz)
1137{
1138 struct compat_msgbuf __user *msgp = dest;
1139 size_t msgsz;
1140
1141 if (put_user(msg->m_type, &msgp->mtype))
1142 return -EFAULT;
1143
1144 msgsz = (bufsz > msg->m_ts) ? msg->m_ts : bufsz;
1145 if (store_msg(msgp->mtext, msg, msgsz))
1146 return -EFAULT;
1147 return msgsz;
1148}
1149
1150COMPAT_SYSCALL_DEFINE5(msgrcv, int, msqid, compat_uptr_t, msgp,
1151 compat_ssize_t, msgsz, compat_long_t, msgtyp, int, msgflg)
1152{
1153 return do_msgrcv(msqid, compat_ptr(msgp), (ssize_t)msgsz, (long)msgtyp,
1154 msgflg, compat_do_msg_fill);
1155}
1156#endif
1013 1157
1014int msg_init_ns(struct ipc_namespace *ns) 1158int msg_init_ns(struct ipc_namespace *ns)
1015{ 1159{
@@ -1039,7 +1183,7 @@ static int sysvipc_msg_proc_show(struct seq_file *s, void *it)
1039 struct msg_queue *msq = container_of(ipcp, struct msg_queue, q_perm); 1183 struct msg_queue *msq = container_of(ipcp, struct msg_queue, q_perm);
1040 1184
1041 seq_printf(s, 1185 seq_printf(s,
1042 "%10d %10d %4o %10lu %10lu %5u %5u %5u %5u %5u %5u %10lu %10lu %10lu\n", 1186 "%10d %10d %4o %10lu %10lu %5u %5u %5u %5u %5u %5u %10llu %10llu %10llu\n",
1043 msq->q_perm.key, 1187 msq->q_perm.key,
1044 msq->q_perm.id, 1188 msq->q_perm.id,
1045 msq->q_perm.mode, 1189 msq->q_perm.mode,