diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /ipc/mqueue.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'ipc/mqueue.c')
-rw-r--r-- | ipc/mqueue.c | 125 |
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 | ||
211 | out: | 210 | out: |
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: | |||
660 | static struct file *do_open(struct ipc_namespace *ipc_ns, | 661 | static 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 | |||
682 | err: | ||
683 | dput(dentry); | ||
684 | mntput(ipc_ns->mq_mnt); | ||
685 | return ERR_PTR(ret); | ||
681 | } | 686 | } |
682 | 687 | ||
683 | SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, mode_t, mode, | 688 | SYSCALL_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); |
745 | out_putfd: | 751 | out_putfd: |
746 | put_unused_fd(fd); | 752 | put_unused_fd(fd); |
747 | out_err: | ||
748 | fd = error; | 753 | fd = error; |
749 | out_upsem: | 754 | out_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 */ |
1081 | retry: | 1097 | retry: |
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); |