aboutsummaryrefslogtreecommitdiffstats
path: root/ipc/mqueue.c
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/mqueue.c')
-rw-r--r--ipc/mqueue.c123
1 files changed, 74 insertions, 49 deletions
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index c79bd57353e7..722b0130aa94 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -32,6 +32,7 @@
32#include <linux/nsproxy.h> 32#include <linux/nsproxy.h>
33#include <linux/pid.h> 33#include <linux/pid.h>
34#include <linux/ipc_namespace.h> 34#include <linux/ipc_namespace.h>
35#include <linux/slab.h>
35 36
36#include <net/sock.h> 37#include <net/sock.h>
37#include "util.h" 38#include "util.h"
@@ -134,7 +135,6 @@ static struct inode *mqueue_get_inode(struct super_block *sb,
134 init_waitqueue_head(&info->wait_q); 135 init_waitqueue_head(&info->wait_q);
135 INIT_LIST_HEAD(&info->e_wait_q[0].list); 136 INIT_LIST_HEAD(&info->e_wait_q[0].list);
136 INIT_LIST_HEAD(&info->e_wait_q[1].list); 137 INIT_LIST_HEAD(&info->e_wait_q[1].list);
137 info->messages = NULL;
138 info->notify_owner = NULL; 138 info->notify_owner = NULL;
139 info->qsize = 0; 139 info->qsize = 0;
140 info->user = NULL; /* set when all is ok */ 140 info->user = NULL; /* set when all is ok */
@@ -146,26 +146,24 @@ static struct inode *mqueue_get_inode(struct super_block *sb,
146 info->attr.mq_msgsize = attr->mq_msgsize; 146 info->attr.mq_msgsize = attr->mq_msgsize;
147 } 147 }
148 mq_msg_tblsz = info->attr.mq_maxmsg * sizeof(struct msg_msg *); 148 mq_msg_tblsz = info->attr.mq_maxmsg * sizeof(struct msg_msg *);
149 info->messages = kmalloc(mq_msg_tblsz, GFP_KERNEL);
150 if (!info->messages)
151 goto out_inode;
152
149 mq_bytes = (mq_msg_tblsz + 153 mq_bytes = (mq_msg_tblsz +
150 (info->attr.mq_maxmsg * info->attr.mq_msgsize)); 154 (info->attr.mq_maxmsg * info->attr.mq_msgsize));
151 155
152 spin_lock(&mq_lock); 156 spin_lock(&mq_lock);
153 if (u->mq_bytes + mq_bytes < u->mq_bytes || 157 if (u->mq_bytes + mq_bytes < u->mq_bytes ||
154 u->mq_bytes + mq_bytes > 158 u->mq_bytes + mq_bytes >
155 p->signal->rlim[RLIMIT_MSGQUEUE].rlim_cur) { 159 task_rlimit(p, RLIMIT_MSGQUEUE)) {
156 spin_unlock(&mq_lock); 160 spin_unlock(&mq_lock);
161 kfree(info->messages);
157 goto out_inode; 162 goto out_inode;
158 } 163 }
159 u->mq_bytes += mq_bytes; 164 u->mq_bytes += mq_bytes;
160 spin_unlock(&mq_lock); 165 spin_unlock(&mq_lock);
161 166
162 info->messages = kmalloc(mq_msg_tblsz, GFP_KERNEL);
163 if (!info->messages) {
164 spin_lock(&mq_lock);
165 u->mq_bytes -= mq_bytes;
166 spin_unlock(&mq_lock);
167 goto out_inode;
168 }
169 /* all is ok */ 167 /* all is ok */
170 info->user = get_uid(u); 168 info->user = get_uid(u);
171 } else if (S_ISDIR(mode)) { 169 } else if (S_ISDIR(mode)) {
@@ -187,7 +185,7 @@ static int mqueue_fill_super(struct super_block *sb, void *data, int silent)
187{ 185{
188 struct inode *inode; 186 struct inode *inode;
189 struct ipc_namespace *ns = data; 187 struct ipc_namespace *ns = data;
190 int error = 0; 188 int error;
191 189
192 sb->s_blocksize = PAGE_CACHE_SIZE; 190 sb->s_blocksize = PAGE_CACHE_SIZE;
193 sb->s_blocksize_bits = PAGE_CACHE_SHIFT; 191 sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
@@ -205,7 +203,9 @@ static int mqueue_fill_super(struct super_block *sb, void *data, int silent)
205 if (!sb->s_root) { 203 if (!sb->s_root) {
206 iput(inode); 204 iput(inode);
207 error = -ENOMEM; 205 error = -ENOMEM;
206 goto out;
208 } 207 }
208 error = 0;
209 209
210out: 210out:
211 return error; 211 return error;
@@ -264,8 +264,9 @@ static void mqueue_delete_inode(struct inode *inode)
264 264
265 clear_inode(inode); 265 clear_inode(inode);
266 266
267 mq_bytes = (info->attr.mq_maxmsg * sizeof(struct msg_msg *) + 267 /* Total amount of bytes accounted for the mqueue */
268 (info->attr.mq_maxmsg * info->attr.mq_msgsize)); 268 mq_bytes = info->attr.mq_maxmsg * (sizeof(struct msg_msg *)
269 + info->attr.mq_msgsize);
269 user = info->user; 270 user = info->user;
270 if (user) { 271 if (user) {
271 spin_lock(&mq_lock); 272 spin_lock(&mq_lock);
@@ -604,8 +605,8 @@ static int mq_attr_ok(struct ipc_namespace *ipc_ns, struct mq_attr *attr)
604 /* check for overflow */ 605 /* check for overflow */
605 if (attr->mq_msgsize > ULONG_MAX/attr->mq_maxmsg) 606 if (attr->mq_msgsize > ULONG_MAX/attr->mq_maxmsg)
606 return 0; 607 return 0;
607 if ((unsigned long)(attr->mq_maxmsg * attr->mq_msgsize) + 608 if ((unsigned long)(attr->mq_maxmsg * (attr->mq_msgsize
608 (attr->mq_maxmsg * sizeof (struct msg_msg *)) < 609 + sizeof (struct msg_msg *))) <
609 (unsigned long)(attr->mq_maxmsg * attr->mq_msgsize)) 610 (unsigned long)(attr->mq_maxmsg * attr->mq_msgsize))
610 return 0; 611 return 0;
611 return 1; 612 return 1;
@@ -623,9 +624,10 @@ static struct file *do_create(struct ipc_namespace *ipc_ns, struct dentry *dir,
623 int ret; 624 int ret;
624 625
625 if (attr) { 626 if (attr) {
626 ret = -EINVAL; 627 if (!mq_attr_ok(ipc_ns, attr)) {
627 if (!mq_attr_ok(ipc_ns, attr)) 628 ret = -EINVAL;
628 goto out; 629 goto out;
630 }
629 /* store for use during create */ 631 /* store for use during create */
630 dentry->d_fsdata = attr; 632 dentry->d_fsdata = attr;
631 } 633 }
@@ -659,24 +661,28 @@ out:
659static struct file *do_open(struct ipc_namespace *ipc_ns, 661static struct file *do_open(struct ipc_namespace *ipc_ns,
660 struct dentry *dentry, int oflag) 662 struct dentry *dentry, int oflag)
661{ 663{
664 int ret;
662 const struct cred *cred = current_cred(); 665 const struct cred *cred = current_cred();
663 666
664 static const int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE, 667 static const int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE,
665 MAY_READ | MAY_WRITE }; 668 MAY_READ | MAY_WRITE };
666 669
667 if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) { 670 if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) {
668 dput(dentry); 671 ret = -EINVAL;
669 mntput(ipc_ns->mq_mnt); 672 goto err;
670 return ERR_PTR(-EINVAL);
671 } 673 }
672 674
673 if (inode_permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE])) { 675 if (inode_permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE])) {
674 dput(dentry); 676 ret = -EACCES;
675 mntput(ipc_ns->mq_mnt); 677 goto err;
676 return ERR_PTR(-EACCES);
677 } 678 }
678 679
679 return dentry_open(dentry, ipc_ns->mq_mnt, oflag, cred); 680 return dentry_open(dentry, ipc_ns->mq_mnt, oflag, cred);
681
682err:
683 dput(dentry);
684 mntput(ipc_ns->mq_mnt);
685 return ERR_PTR(ret);
680} 686}
681 687
682SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, mode_t, mode, 688SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, mode_t, mode,
@@ -705,16 +711,17 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, mode_t, mode,
705 dentry = lookup_one_len(name, ipc_ns->mq_mnt->mnt_root, strlen(name)); 711 dentry = lookup_one_len(name, ipc_ns->mq_mnt->mnt_root, strlen(name));
706 if (IS_ERR(dentry)) { 712 if (IS_ERR(dentry)) {
707 error = PTR_ERR(dentry); 713 error = PTR_ERR(dentry);
708 goto out_err; 714 goto out_putfd;
709 } 715 }
710 mntget(ipc_ns->mq_mnt); 716 mntget(ipc_ns->mq_mnt);
711 717
712 if (oflag & O_CREAT) { 718 if (oflag & O_CREAT) {
713 if (dentry->d_inode) { /* entry already exists */ 719 if (dentry->d_inode) { /* entry already exists */
714 audit_inode(name, dentry); 720 audit_inode(name, dentry);
715 error = -EEXIST; 721 if (oflag & O_EXCL) {
716 if (oflag & O_EXCL) 722 error = -EEXIST;
717 goto out; 723 goto out;
724 }
718 filp = do_open(ipc_ns, dentry, oflag); 725 filp = do_open(ipc_ns, dentry, oflag);
719 } else { 726 } else {
720 filp = do_create(ipc_ns, ipc_ns->mq_mnt->mnt_root, 727 filp = do_create(ipc_ns, ipc_ns->mq_mnt->mnt_root,
@@ -722,9 +729,10 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, mode_t, mode,
722 u_attr ? &attr : NULL); 729 u_attr ? &attr : NULL);
723 } 730 }
724 } else { 731 } else {
725 error = -ENOENT; 732 if (!dentry->d_inode) {
726 if (!dentry->d_inode) 733 error = -ENOENT;
727 goto out; 734 goto out;
735 }
728 audit_inode(name, dentry); 736 audit_inode(name, dentry);
729 filp = do_open(ipc_ns, dentry, oflag); 737 filp = do_open(ipc_ns, dentry, oflag);
730 } 738 }
@@ -742,7 +750,6 @@ out:
742 mntput(ipc_ns->mq_mnt); 750 mntput(ipc_ns->mq_mnt);
743out_putfd: 751out_putfd:
744 put_unused_fd(fd); 752 put_unused_fd(fd);
745out_err:
746 fd = error; 753 fd = error;
747out_upsem: 754out_upsem:
748 mutex_unlock(&ipc_ns->mq_mnt->mnt_root->d_inode->i_mutex); 755 mutex_unlock(&ipc_ns->mq_mnt->mnt_root->d_inode->i_mutex);
@@ -872,19 +879,24 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,
872 audit_mq_sendrecv(mqdes, msg_len, msg_prio, p); 879 audit_mq_sendrecv(mqdes, msg_len, msg_prio, p);
873 timeout = prepare_timeout(p); 880 timeout = prepare_timeout(p);
874 881
875 ret = -EBADF;
876 filp = fget(mqdes); 882 filp = fget(mqdes);
877 if (unlikely(!filp)) 883 if (unlikely(!filp)) {
884 ret = -EBADF;
878 goto out; 885 goto out;
886 }
879 887
880 inode = filp->f_path.dentry->d_inode; 888 inode = filp->f_path.dentry->d_inode;
881 if (unlikely(filp->f_op != &mqueue_file_operations)) 889 if (unlikely(filp->f_op != &mqueue_file_operations)) {
890 ret = -EBADF;
882 goto out_fput; 891 goto out_fput;
892 }
883 info = MQUEUE_I(inode); 893 info = MQUEUE_I(inode);
884 audit_inode(NULL, filp->f_path.dentry); 894 audit_inode(NULL, filp->f_path.dentry);
885 895
886 if (unlikely(!(filp->f_mode & FMODE_WRITE))) 896 if (unlikely(!(filp->f_mode & FMODE_WRITE))) {
897 ret = -EBADF;
887 goto out_fput; 898 goto out_fput;
899 }
888 900
889 if (unlikely(msg_len > info->attr.mq_msgsize)) { 901 if (unlikely(msg_len > info->attr.mq_msgsize)) {
890 ret = -EMSGSIZE; 902 ret = -EMSGSIZE;
@@ -961,19 +973,24 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,
961 audit_mq_sendrecv(mqdes, msg_len, 0, p); 973 audit_mq_sendrecv(mqdes, msg_len, 0, p);
962 timeout = prepare_timeout(p); 974 timeout = prepare_timeout(p);
963 975
964 ret = -EBADF;
965 filp = fget(mqdes); 976 filp = fget(mqdes);
966 if (unlikely(!filp)) 977 if (unlikely(!filp)) {
978 ret = -EBADF;
967 goto out; 979 goto out;
980 }
968 981
969 inode = filp->f_path.dentry->d_inode; 982 inode = filp->f_path.dentry->d_inode;
970 if (unlikely(filp->f_op != &mqueue_file_operations)) 983 if (unlikely(filp->f_op != &mqueue_file_operations)) {
984 ret = -EBADF;
971 goto out_fput; 985 goto out_fput;
986 }
972 info = MQUEUE_I(inode); 987 info = MQUEUE_I(inode);
973 audit_inode(NULL, filp->f_path.dentry); 988 audit_inode(NULL, filp->f_path.dentry);
974 989
975 if (unlikely(!(filp->f_mode & FMODE_READ))) 990 if (unlikely(!(filp->f_mode & FMODE_READ))) {
991 ret = -EBADF;
976 goto out_fput; 992 goto out_fput;
993 }
977 994
978 /* checks if buffer is big enough */ 995 /* checks if buffer is big enough */
979 if (unlikely(msg_len < info->attr.mq_msgsize)) { 996 if (unlikely(msg_len < info->attr.mq_msgsize)) {
@@ -1063,13 +1080,14 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
1063 1080
1064 /* create the notify skb */ 1081 /* create the notify skb */
1065 nc = alloc_skb(NOTIFY_COOKIE_LEN, GFP_KERNEL); 1082 nc = alloc_skb(NOTIFY_COOKIE_LEN, GFP_KERNEL);
1066 ret = -ENOMEM; 1083 if (!nc) {
1067 if (!nc) 1084 ret = -ENOMEM;
1068 goto out; 1085 goto out;
1069 ret = -EFAULT; 1086 }
1070 if (copy_from_user(nc->data, 1087 if (copy_from_user(nc->data,
1071 notification.sigev_value.sival_ptr, 1088 notification.sigev_value.sival_ptr,
1072 NOTIFY_COOKIE_LEN)) { 1089 NOTIFY_COOKIE_LEN)) {
1090 ret = -EFAULT;
1073 goto out; 1091 goto out;
1074 } 1092 }
1075 1093
@@ -1078,9 +1096,10 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
1078 /* and attach it to the socket */ 1096 /* and attach it to the socket */
1079retry: 1097retry:
1080 filp = fget(notification.sigev_signo); 1098 filp = fget(notification.sigev_signo);
1081 ret = -EBADF; 1099 if (!filp) {
1082 if (!filp) 1100 ret = -EBADF;
1083 goto out; 1101 goto out;
1102 }
1084 sock = netlink_getsockbyfilp(filp); 1103 sock = netlink_getsockbyfilp(filp);
1085 fput(filp); 1104 fput(filp);
1086 if (IS_ERR(sock)) { 1105 if (IS_ERR(sock)) {
@@ -1092,7 +1111,7 @@ retry:
1092 timeo = MAX_SCHEDULE_TIMEOUT; 1111 timeo = MAX_SCHEDULE_TIMEOUT;
1093 ret = netlink_attachskb(sock, nc, &timeo, NULL); 1112 ret = netlink_attachskb(sock, nc, &timeo, NULL);
1094 if (ret == 1) 1113 if (ret == 1)
1095 goto retry; 1114 goto retry;
1096 if (ret) { 1115 if (ret) {
1097 sock = NULL; 1116 sock = NULL;
1098 nc = NULL; 1117 nc = NULL;
@@ -1101,14 +1120,17 @@ retry:
1101 } 1120 }
1102 } 1121 }
1103 1122
1104 ret = -EBADF;
1105 filp = fget(mqdes); 1123 filp = fget(mqdes);
1106 if (!filp) 1124 if (!filp) {
1125 ret = -EBADF;
1107 goto out; 1126 goto out;
1127 }
1108 1128
1109 inode = filp->f_path.dentry->d_inode; 1129 inode = filp->f_path.dentry->d_inode;
1110 if (unlikely(filp->f_op != &mqueue_file_operations)) 1130 if (unlikely(filp->f_op != &mqueue_file_operations)) {
1131 ret = -EBADF;
1111 goto out_fput; 1132 goto out_fput;
1133 }
1112 info = MQUEUE_I(inode); 1134 info = MQUEUE_I(inode);
1113 1135
1114 ret = 0; 1136 ret = 0;
@@ -1171,14 +1193,17 @@ SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
1171 return -EINVAL; 1193 return -EINVAL;
1172 } 1194 }
1173 1195
1174 ret = -EBADF;
1175 filp = fget(mqdes); 1196 filp = fget(mqdes);
1176 if (!filp) 1197 if (!filp) {
1198 ret = -EBADF;
1177 goto out; 1199 goto out;
1200 }
1178 1201
1179 inode = filp->f_path.dentry->d_inode; 1202 inode = filp->f_path.dentry->d_inode;
1180 if (unlikely(filp->f_op != &mqueue_file_operations)) 1203 if (unlikely(filp->f_op != &mqueue_file_operations)) {
1204 ret = -EBADF;
1181 goto out_fput; 1205 goto out_fput;
1206 }
1182 info = MQUEUE_I(inode); 1207 info = MQUEUE_I(inode);
1183 1208
1184 spin_lock(&info->lock); 1209 spin_lock(&info->lock);
@@ -1272,7 +1297,7 @@ static int __init init_mqueue_fs(void)
1272 if (mqueue_inode_cachep == NULL) 1297 if (mqueue_inode_cachep == NULL)
1273 return -ENOMEM; 1298 return -ENOMEM;
1274 1299
1275 /* ignore failues - they are not fatal */ 1300 /* ignore failures - they are not fatal */
1276 mq_sysctl_table = mq_register_sysctl_table(); 1301 mq_sysctl_table = mq_register_sysctl_table();
1277 1302
1278 error = register_filesystem(&mqueue_fs_type); 1303 error = register_filesystem(&mqueue_fs_type);