summaryrefslogtreecommitdiff
path: root/ipc
diff options
context:
space:
mode:
Diffstat (limited to 'ipc')
-rw-r--r--ipc/mqueue.c71
1 files changed, 21 insertions, 50 deletions
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index fee67559acbe..a2483524b633 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -270,13 +270,30 @@ static struct inode *mqueue_get_inode(struct super_block *sb,
* that means the min(mq_maxmsg, max_priorities) * struct
* posix_msg_tree_node.
*/
+
+ ret = -EINVAL;
+ if (info->attr.mq_maxmsg <= 0 || info->attr.mq_msgsize <= 0)
+ goto out_inode;
+ if (capable(CAP_SYS_RESOURCE)) {
+ if (info->attr.mq_maxmsg > HARD_MSGMAX ||
+ info->attr.mq_msgsize > HARD_MSGSIZEMAX)
+ goto out_inode;
+ } else {
+ if (info->attr.mq_maxmsg > ipc_ns->mq_msg_max ||
+ info->attr.mq_msgsize > ipc_ns->mq_msgsize_max)
+ goto out_inode;
+ }
+ ret = -EOVERFLOW;
+ /* check for overflow */
+ if (info->attr.mq_msgsize > ULONG_MAX/info->attr.mq_maxmsg)
+ goto out_inode;
mq_treesize = info->attr.mq_maxmsg * sizeof(struct msg_msg) +
min_t(unsigned int, info->attr.mq_maxmsg, MQ_PRIO_MAX) *
sizeof(struct posix_msg_tree_node);
-
- mq_bytes = mq_treesize + (info->attr.mq_maxmsg *
- info->attr.mq_msgsize);
-
+ mq_bytes = info->attr.mq_maxmsg * info->attr.mq_msgsize;
+ if (mq_bytes + mq_treesize < mq_bytes)
+ goto out_inode;
+ mq_bytes += mq_treesize;
spin_lock(&mq_lock);
if (u->mq_bytes + mq_bytes < u->mq_bytes ||
u->mq_bytes + mq_bytes > rlimit(RLIMIT_MSGQUEUE)) {
@@ -696,34 +713,6 @@ static void remove_notification(struct mqueue_inode_info *info)
info->notify_user_ns = NULL;
}
-static int mq_attr_ok(struct ipc_namespace *ipc_ns, struct mq_attr *attr)
-{
- int mq_treesize;
- unsigned long total_size;
-
- if (attr->mq_maxmsg <= 0 || attr->mq_msgsize <= 0)
- return -EINVAL;
- if (capable(CAP_SYS_RESOURCE)) {
- if (attr->mq_maxmsg > HARD_MSGMAX ||
- attr->mq_msgsize > HARD_MSGSIZEMAX)
- return -EINVAL;
- } else {
- if (attr->mq_maxmsg > ipc_ns->mq_msg_max ||
- attr->mq_msgsize > ipc_ns->mq_msgsize_max)
- return -EINVAL;
- }
- /* check for overflow */
- if (attr->mq_msgsize > ULONG_MAX/attr->mq_maxmsg)
- return -EOVERFLOW;
- mq_treesize = attr->mq_maxmsg * sizeof(struct msg_msg) +
- min_t(unsigned int, attr->mq_maxmsg, MQ_PRIO_MAX) *
- sizeof(struct posix_msg_tree_node);
- total_size = attr->mq_maxmsg * attr->mq_msgsize;
- if (total_size + mq_treesize < total_size)
- return -EOVERFLOW;
- return 0;
-}
-
/*
* Invoked when creating a new queue via sys_mq_open
*/
@@ -731,24 +720,6 @@ static int do_create(struct ipc_namespace *ipc_ns, struct inode *dir,
struct path *path, int oflag, umode_t mode,
struct mq_attr *attr)
{
- int ret;
-
- if (attr) {
- ret = mq_attr_ok(ipc_ns, attr);
- if (ret)
- return ret;
- } else {
- struct mq_attr def_attr;
-
- def_attr.mq_maxmsg = min(ipc_ns->mq_msg_max,
- ipc_ns->mq_msg_default);
- def_attr.mq_msgsize = min(ipc_ns->mq_msgsize_max,
- ipc_ns->mq_msgsize_default);
- ret = mq_attr_ok(ipc_ns, &def_attr);
- if (ret)
- return ret;
- }
-
return vfs_mkobj(path->dentry, mode & ~current_umask(),
mqueue_create_attr, attr);
}