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