aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsuzuki <suzuki@linux.vnet.ibm.com>2006-12-06 23:37:48 -0500
committerLinus Torvalds <torvalds@woody.osdl.org>2006-12-07 11:39:38 -0500
commit651971cb7242e8f6d7ebd153e69bd271cb731223 (patch)
tree38c8bd3c461cb09a538664ddc78e5452fdf28f29
parent19e5d9c0d2194b4b47189cbec2921cbf72b0bd1c (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.h6
-rw-r--r--ipc/compat.c23
-rw-r--r--ipc/msg.c44
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 */
96extern long do_msgsnd(int msqid, long mtype, void __user *mtext,
97 size_t msgsz, int msgflg);
98extern 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
116extern int sem_ctls[]; 116extern int sem_ctls[];
117#define sc_semopm (sem_ctls[2]) 117#define sc_semopm (sem_ctls[2])
118#define MAXBUF (64*1024)
119 118
120static inline int compat_ipc_parse_version(int *cmd) 119static 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
308long compat_sys_msgsnd(int first, int second, int third, void __user *uptr) 307long 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
328long compat_sys_msgrcv(int first, int second, int msgtyp, int third, 323long 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;
361out: 352out:
362 return err; 353 return err;
diff --git a/ipc/msg.c b/ipc/msg.c
index 1266b1d0c8e3..a388824740e7 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -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
629asmlinkage long 629long do_msgsnd(int msqid, long mtype, void __user *mtext,
630sys_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
723asmlinkage long
724sys_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
726static inline int convert_mode(long *msgtyp, int msgflg) 733static 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
745asmlinkage long sys_msgrcv(int msqid, struct msgbuf __user *msgp, size_t msgsz, 752long 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
908asmlinkage 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;
919out:
920 return err;
921}
922
901#ifdef CONFIG_PROC_FS 923#ifdef CONFIG_PROC_FS
902static int sysvipc_msg_proc_show(struct seq_file *s, void *it) 924static int sysvipc_msg_proc_show(struct seq_file *s, void *it)
903{ 925{