aboutsummaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
authorDoug Ledford <dledford@redhat.com>2012-05-31 19:26:36 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-05-31 20:49:31 -0400
commit113289cc086f80f28acd06f160a7c6423cdd4191 (patch)
tree4a50ff35f9cc0b320985a76b5f2e8313635b0f81 /ipc
parent2c12ea498f349207c28840c0ed9654321aab7720 (diff)
ipc/mqueue: strengthen checks on mqueue creation
We already check the mq attr struct if it's passed in, but now that the admin can set system wide defaults separate from maximums, it's actually possible to set the defaults to something that would overflow. So, if there is no attr struct passed in to the open call, check the default values. While we are at it, simplify mq_attr_ok() by making it return 0 or an error condition, so that way if we add more tests to it later, we have the option of what error should be returned instead of the calling location having to pick a possibly inaccurate error code. [akpm@linux-foundation.org: s/ENOMEM/EOVERFLOW/] Signed-off-by: Doug Ledford <dledford@redhat.com> Cc: Stephen Rothwell <sfr@canb.auug.org.au> Cc: Manfred Spraul <manfred@colorfullife.com> Acked-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> 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/mqueue.c27
1 files changed, 18 insertions, 9 deletions
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 076399ce363a..af1692556c52 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -680,26 +680,26 @@ static int mq_attr_ok(struct ipc_namespace *ipc_ns, struct mq_attr *attr)
680 unsigned long total_size; 680 unsigned long total_size;
681 681
682 if (attr->mq_maxmsg <= 0 || attr->mq_msgsize <= 0) 682 if (attr->mq_maxmsg <= 0 || attr->mq_msgsize <= 0)
683 return 0; 683 return -EINVAL;
684 if (capable(CAP_SYS_RESOURCE)) { 684 if (capable(CAP_SYS_RESOURCE)) {
685 if (attr->mq_maxmsg > HARD_MSGMAX || 685 if (attr->mq_maxmsg > HARD_MSGMAX ||
686 attr->mq_msgsize > HARD_MSGSIZEMAX) 686 attr->mq_msgsize > HARD_MSGSIZEMAX)
687 return 0; 687 return -EINVAL;
688 } else { 688 } else {
689 if (attr->mq_maxmsg > ipc_ns->mq_msg_max || 689 if (attr->mq_maxmsg > ipc_ns->mq_msg_max ||
690 attr->mq_msgsize > ipc_ns->mq_msgsize_max) 690 attr->mq_msgsize > ipc_ns->mq_msgsize_max)
691 return 0; 691 return -EINVAL;
692 } 692 }
693 /* check for overflow */ 693 /* check for overflow */
694 if (attr->mq_msgsize > ULONG_MAX/attr->mq_maxmsg) 694 if (attr->mq_msgsize > ULONG_MAX/attr->mq_maxmsg)
695 return 0; 695 return -EOVERFLOW;
696 mq_treesize = attr->mq_maxmsg * sizeof(struct msg_msg) + 696 mq_treesize = attr->mq_maxmsg * sizeof(struct msg_msg) +
697 min_t(unsigned int, attr->mq_maxmsg, MQ_PRIO_MAX) * 697 min_t(unsigned int, attr->mq_maxmsg, MQ_PRIO_MAX) *
698 sizeof(struct posix_msg_tree_node); 698 sizeof(struct posix_msg_tree_node);
699 total_size = attr->mq_maxmsg * attr->mq_msgsize; 699 total_size = attr->mq_maxmsg * attr->mq_msgsize;
700 if (total_size + mq_treesize < total_size) 700 if (total_size + mq_treesize < total_size)
701 return 0; 701 return -EOVERFLOW;
702 return 1; 702 return 0;
703} 703}
704 704
705/* 705/*
@@ -714,12 +714,21 @@ static struct file *do_create(struct ipc_namespace *ipc_ns, struct dentry *dir,
714 int ret; 714 int ret;
715 715
716 if (attr) { 716 if (attr) {
717 if (!mq_attr_ok(ipc_ns, attr)) { 717 ret = mq_attr_ok(ipc_ns, attr);
718 ret = -EINVAL; 718 if (ret)
719 goto out; 719 goto out;
720 }
721 /* store for use during create */ 720 /* store for use during create */
722 dentry->d_fsdata = attr; 721 dentry->d_fsdata = attr;
722 } else {
723 struct mq_attr def_attr;
724
725 def_attr.mq_maxmsg = min(ipc_ns->mq_msg_max,
726 ipc_ns->mq_msg_default);
727 def_attr.mq_msgsize = min(ipc_ns->mq_msgsize_max,
728 ipc_ns->mq_msgsize_default);
729 ret = mq_attr_ok(ipc_ns, &def_attr);
730 if (ret)
731 goto out;
723 } 732 }
724 733
725 mode &= ~current_umask(); 734 mode &= ~current_umask();