diff options
author | suzuki <suzuki@linux.vnet.ibm.com> | 2006-12-06 23:37:48 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-07 11:39:38 -0500 |
commit | 651971cb7242e8f6d7ebd153e69bd271cb731223 (patch) | |
tree | 38c8bd3c461cb09a538664ddc78e5452fdf28f29 | |
parent | 19e5d9c0d2194b4b47189cbec2921cbf72b0bd1c (diff) |
[PATCH] Fix the size limit of compat space msgsize
Currently we allocate 64k space on the user stack and use it the msgbuf for
sys_{msgrcv,msgsnd} for compat and the results are later copied in user [
by copy_in_user]. This patch introduces helper routines for
sys_{msgrcv,msgsnd} as below:
do_msgsnd() : Accepts the mtype and user space ptr to the buffer along with
the msqid and msgflg.
do_msgrcv() : Accepts a kernel space ptr to mtype and a userspace ptr to
the buffer. The mtype has to be copied back the user space msgbuf by the
caller.
These changes avoid the need to allocate the msgsize on the userspace (
thus removing the size limt ) and the overhead of an extra copy_in_user().
Signed-off-by: Suzuki K P <suzuki@in.ibm.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: "David S. Miller" <davem@davemloft.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | include/linux/msg.h | 6 | ||||
-rw-r--r-- | ipc/compat.c | 23 | ||||
-rw-r--r-- | ipc/msg.c | 44 |
3 files changed, 46 insertions, 27 deletions
diff --git a/include/linux/msg.h b/include/linux/msg.h index acc7c174ff00..f1b60740d641 100644 --- a/include/linux/msg.h +++ b/include/linux/msg.h | |||
@@ -92,6 +92,12 @@ struct msg_queue { | |||
92 | struct list_head q_senders; | 92 | struct list_head q_senders; |
93 | }; | 93 | }; |
94 | 94 | ||
95 | /* Helper routines for sys_msgsnd and sys_msgrcv */ | ||
96 | extern long do_msgsnd(int msqid, long mtype, void __user *mtext, | ||
97 | size_t msgsz, int msgflg); | ||
98 | extern long do_msgrcv(int msqid, long *pmtype, void __user *mtext, | ||
99 | size_t msgsz, long msgtyp, int msgflg); | ||
100 | |||
95 | #endif /* __KERNEL__ */ | 101 | #endif /* __KERNEL__ */ |
96 | 102 | ||
97 | #endif /* _LINUX_MSG_H */ | 103 | #endif /* _LINUX_MSG_H */ |
diff --git a/ipc/compat.c b/ipc/compat.c index 4d20cfd38f0a..fa18141539fb 100644 --- a/ipc/compat.c +++ b/ipc/compat.c | |||
@@ -115,7 +115,6 @@ struct compat_shm_info { | |||
115 | 115 | ||
116 | extern int sem_ctls[]; | 116 | extern int sem_ctls[]; |
117 | #define sc_semopm (sem_ctls[2]) | 117 | #define sc_semopm (sem_ctls[2]) |
118 | #define MAXBUF (64*1024) | ||
119 | 118 | ||
120 | static inline int compat_ipc_parse_version(int *cmd) | 119 | static inline int compat_ipc_parse_version(int *cmd) |
121 | { | 120 | { |
@@ -307,35 +306,30 @@ long compat_sys_semctl(int first, int second, int third, void __user *uptr) | |||
307 | 306 | ||
308 | long compat_sys_msgsnd(int first, int second, int third, void __user *uptr) | 307 | long compat_sys_msgsnd(int first, int second, int third, void __user *uptr) |
309 | { | 308 | { |
310 | struct msgbuf __user *p; | ||
311 | struct compat_msgbuf __user *up = uptr; | 309 | struct compat_msgbuf __user *up = uptr; |
312 | long type; | 310 | long type; |
313 | 311 | ||
314 | if (first < 0) | 312 | if (first < 0) |
315 | return -EINVAL; | 313 | return -EINVAL; |
316 | if (second < 0 || (second >= MAXBUF - sizeof(struct msgbuf))) | 314 | if (second < 0) |
317 | return -EINVAL; | 315 | return -EINVAL; |
318 | 316 | ||
319 | p = compat_alloc_user_space(second + sizeof(struct msgbuf)); | 317 | if (get_user(type, &up->mtype)) |
320 | if (get_user(type, &up->mtype) || | ||
321 | put_user(type, &p->mtype) || | ||
322 | copy_in_user(p->mtext, up->mtext, second)) | ||
323 | return -EFAULT; | 318 | return -EFAULT; |
324 | 319 | ||
325 | return sys_msgsnd(first, p, second, third); | 320 | return do_msgsnd(first, type, up->mtext, second, third); |
326 | } | 321 | } |
327 | 322 | ||
328 | long compat_sys_msgrcv(int first, int second, int msgtyp, int third, | 323 | long compat_sys_msgrcv(int first, int second, int msgtyp, int third, |
329 | int version, void __user *uptr) | 324 | int version, void __user *uptr) |
330 | { | 325 | { |
331 | struct msgbuf __user *p; | ||
332 | struct compat_msgbuf __user *up; | 326 | struct compat_msgbuf __user *up; |
333 | long type; | 327 | long type; |
334 | int err; | 328 | int err; |
335 | 329 | ||
336 | if (first < 0) | 330 | if (first < 0) |
337 | return -EINVAL; | 331 | return -EINVAL; |
338 | if (second < 0 || (second >= MAXBUF - sizeof(struct msgbuf))) | 332 | if (second < 0) |
339 | return -EINVAL; | 333 | return -EINVAL; |
340 | 334 | ||
341 | if (!version) { | 335 | if (!version) { |
@@ -349,14 +343,11 @@ long compat_sys_msgrcv(int first, int second, int msgtyp, int third, | |||
349 | uptr = compat_ptr(ipck.msgp); | 343 | uptr = compat_ptr(ipck.msgp); |
350 | msgtyp = ipck.msgtyp; | 344 | msgtyp = ipck.msgtyp; |
351 | } | 345 | } |
352 | p = compat_alloc_user_space(second + sizeof(struct msgbuf)); | 346 | up = uptr; |
353 | err = sys_msgrcv(first, p, second, msgtyp, third); | 347 | err = do_msgrcv(first, &type, up->mtext, second, msgtyp, third); |
354 | if (err < 0) | 348 | if (err < 0) |
355 | goto out; | 349 | goto out; |
356 | up = uptr; | 350 | if (put_user(type, &up->mtype)) |
357 | if (get_user(type, &p->mtype) || | ||
358 | put_user(type, &up->mtype) || | ||
359 | copy_in_user(up->mtext, p->mtext, err)) | ||
360 | err = -EFAULT; | 351 | err = -EFAULT; |
361 | out: | 352 | out: |
362 | return err; | 353 | return err; |
@@ -626,12 +626,11 @@ static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg) | |||
626 | return 0; | 626 | return 0; |
627 | } | 627 | } |
628 | 628 | ||
629 | asmlinkage long | 629 | long do_msgsnd(int msqid, long mtype, void __user *mtext, |
630 | sys_msgsnd(int msqid, struct msgbuf __user *msgp, size_t msgsz, int msgflg) | 630 | size_t msgsz, int msgflg) |
631 | { | 631 | { |
632 | struct msg_queue *msq; | 632 | struct msg_queue *msq; |
633 | struct msg_msg *msg; | 633 | struct msg_msg *msg; |
634 | long mtype; | ||
635 | int err; | 634 | int err; |
636 | struct ipc_namespace *ns; | 635 | struct ipc_namespace *ns; |
637 | 636 | ||
@@ -639,12 +638,10 @@ sys_msgsnd(int msqid, struct msgbuf __user *msgp, size_t msgsz, int msgflg) | |||
639 | 638 | ||
640 | if (msgsz > ns->msg_ctlmax || (long) msgsz < 0 || msqid < 0) | 639 | if (msgsz > ns->msg_ctlmax || (long) msgsz < 0 || msqid < 0) |
641 | return -EINVAL; | 640 | return -EINVAL; |
642 | if (get_user(mtype, &msgp->mtype)) | ||
643 | return -EFAULT; | ||
644 | if (mtype < 1) | 641 | if (mtype < 1) |
645 | return -EINVAL; | 642 | return -EINVAL; |
646 | 643 | ||
647 | msg = load_msg(msgp->mtext, msgsz); | 644 | msg = load_msg(mtext, msgsz); |
648 | if (IS_ERR(msg)) | 645 | if (IS_ERR(msg)) |
649 | return PTR_ERR(msg); | 646 | return PTR_ERR(msg); |
650 | 647 | ||
@@ -723,6 +720,16 @@ out_free: | |||
723 | return err; | 720 | return err; |
724 | } | 721 | } |
725 | 722 | ||
723 | asmlinkage long | ||
724 | sys_msgsnd(int msqid, struct msgbuf __user *msgp, size_t msgsz, int msgflg) | ||
725 | { | ||
726 | long mtype; | ||
727 | |||
728 | if (get_user(mtype, &msgp->mtype)) | ||
729 | return -EFAULT; | ||
730 | return do_msgsnd(msqid, mtype, msgp->mtext, msgsz, msgflg); | ||
731 | } | ||
732 | |||
726 | static inline int convert_mode(long *msgtyp, int msgflg) | 733 | static inline int convert_mode(long *msgtyp, int msgflg) |
727 | { | 734 | { |
728 | /* | 735 | /* |
@@ -742,8 +749,8 @@ static inline int convert_mode(long *msgtyp, int msgflg) | |||
742 | return SEARCH_EQUAL; | 749 | return SEARCH_EQUAL; |
743 | } | 750 | } |
744 | 751 | ||
745 | asmlinkage long sys_msgrcv(int msqid, struct msgbuf __user *msgp, size_t msgsz, | 752 | long do_msgrcv(int msqid, long *pmtype, void __user *mtext, |
746 | long msgtyp, int msgflg) | 753 | size_t msgsz, long msgtyp, int msgflg) |
747 | { | 754 | { |
748 | struct msg_queue *msq; | 755 | struct msg_queue *msq; |
749 | struct msg_msg *msg; | 756 | struct msg_msg *msg; |
@@ -889,15 +896,30 @@ out_unlock: | |||
889 | return PTR_ERR(msg); | 896 | return PTR_ERR(msg); |
890 | 897 | ||
891 | msgsz = (msgsz > msg->m_ts) ? msg->m_ts : msgsz; | 898 | msgsz = (msgsz > msg->m_ts) ? msg->m_ts : msgsz; |
892 | if (put_user (msg->m_type, &msgp->mtype) || | 899 | *pmtype = msg->m_type; |
893 | store_msg(msgp->mtext, msg, msgsz)) { | 900 | if (store_msg(mtext, msg, msgsz)) |
894 | msgsz = -EFAULT; | 901 | msgsz = -EFAULT; |
895 | } | 902 | |
896 | free_msg(msg); | 903 | free_msg(msg); |
897 | 904 | ||
898 | return msgsz; | 905 | return msgsz; |
899 | } | 906 | } |
900 | 907 | ||
908 | asmlinkage long sys_msgrcv(int msqid, struct msgbuf __user *msgp, size_t msgsz, | ||
909 | long msgtyp, int msgflg) | ||
910 | { | ||
911 | long err, mtype; | ||
912 | |||
913 | err = do_msgrcv(msqid, &mtype, msgp->mtext, msgsz, msgtyp, msgflg); | ||
914 | if (err < 0) | ||
915 | goto out; | ||
916 | |||
917 | if (put_user(mtype, &msgp->mtype)) | ||
918 | err = -EFAULT; | ||
919 | out: | ||
920 | return err; | ||
921 | } | ||
922 | |||
901 | #ifdef CONFIG_PROC_FS | 923 | #ifdef CONFIG_PROC_FS |
902 | static int sysvipc_msg_proc_show(struct seq_file *s, void *it) | 924 | static int sysvipc_msg_proc_show(struct seq_file *s, void *it) |
903 | { | 925 | { |