From: suzuki 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} which would accept the pointer to msgbuf along with the msgp->mtext. This avoids the need to allocate the msgsize on the userspace (thus removing the size limit) and the overhead of an extra copy_in_user(). Signed-off-by: Suzuki K P Cc: Arnd Bergmann Cc: "David S. Miller" Signed-off-by: Andrew Morton --- include/linux/msg.h | 6 ++++++ ipc/compat.c | 21 +++++++++------------ ipc/msg.c | 24 ++++++++++++++++++------ 3 files changed, 33 insertions(+), 18 deletions(-) diff -puN include/linux/msg.h~fix-compat-space-msg-size-limit-for-msgsnd-msgrcv include/linux/msg.h --- a/include/linux/msg.h~fix-compat-space-msg-size-limit-for-msgsnd-msgrcv +++ a/include/linux/msg.h @@ -92,6 +92,12 @@ struct msg_queue { struct list_head q_senders; }; +/* Helper routines for sys_msgsnd and sys_msgrcv */ +extern long do_msgsnd(int msqid, struct msgbuf __user *msgp, void __user *mtext, + size_t msgsz, int msgflg); +extern long do_msgrcv(int msqid, struct msgbuf __user *msgp, void __user *mtext, + size_t msgsz, long msgtyp, int msgflg); + #endif /* __KERNEL__ */ #endif /* _LINUX_MSG_H */ diff -puN ipc/compat.c~fix-compat-space-msg-size-limit-for-msgsnd-msgrcv ipc/compat.c --- a/ipc/compat.c~fix-compat-space-msg-size-limit-for-msgsnd-msgrcv +++ a/ipc/compat.c @@ -115,7 +115,6 @@ struct compat_shm_info { extern int sem_ctls[]; #define sc_semopm (sem_ctls[2]) -#define MAXBUF (64*1024) static inline int compat_ipc_parse_version(int *cmd) { @@ -313,16 +312,15 @@ long compat_sys_msgsnd(int first, int se if (first < 0) return -EINVAL; - if (second < 0 || (second >= MAXBUF - sizeof(struct msgbuf))) + if (second < 0) return -EINVAL; - p = compat_alloc_user_space(second + sizeof(struct msgbuf)); + p = compat_alloc_user_space(sizeof(struct msgbuf)); if (get_user(type, &up->mtype) || - put_user(type, &p->mtype) || - copy_in_user(p->mtext, up->mtext, second)) + put_user(type, &p->mtype)) return -EFAULT; - return sys_msgsnd(first, p, second, third); + return do_msgsnd(first, p, up->mtext, second, third); } long compat_sys_msgrcv(int first, int second, int msgtyp, int third, @@ -335,7 +333,7 @@ long compat_sys_msgrcv(int first, int se if (first < 0) return -EINVAL; - if (second < 0 || (second >= MAXBUF - sizeof(struct msgbuf))) + if (second < 0) return -EINVAL; if (!version) { @@ -349,14 +347,13 @@ long compat_sys_msgrcv(int first, int se uptr = compat_ptr(ipck.msgp); msgtyp = ipck.msgtyp; } - p = compat_alloc_user_space(second + sizeof(struct msgbuf)); - err = sys_msgrcv(first, p, second, msgtyp, third); + up = uptr; + p = compat_alloc_user_space(sizeof(struct msgbuf)); + err = do_msgrcv(first, p, up->mtext, second, msgtyp, third); if (err < 0) goto out; - up = uptr; if (get_user(type, &p->mtype) || - put_user(type, &up->mtype) || - copy_in_user(up->mtext, p->mtext, err)) + put_user(type, &up->mtype)) err = -EFAULT; out: return err; diff -puN ipc/msg.c~fix-compat-space-msg-size-limit-for-msgsnd-msgrcv ipc/msg.c --- a/ipc/msg.c~fix-compat-space-msg-size-limit-for-msgsnd-msgrcv +++ a/ipc/msg.c @@ -626,8 +626,8 @@ static inline int pipelined_send(struct return 0; } -asmlinkage long -sys_msgsnd(int msqid, struct msgbuf __user *msgp, size_t msgsz, int msgflg) +long do_msgsnd(int msqid, struct msgbuf __user *msgp, void __user *mtext, + size_t msgsz, int msgflg) { struct msg_queue *msq; struct msg_msg *msg; @@ -644,7 +644,7 @@ sys_msgsnd(int msqid, struct msgbuf __us if (mtype < 1) return -EINVAL; - msg = load_msg(msgp->mtext, msgsz); + msg = load_msg(mtext, msgsz); if (IS_ERR(msg)) return PTR_ERR(msg); @@ -723,6 +723,12 @@ out_free: return err; } +asmlinkage long +sys_msgsnd(int msqid, struct msgbuf __user *msgp, size_t msgsz, int msgflg) +{ + return do_msgsnd(msqid, msgp, msgp->mtext, msgsz, msgflg); +} + static inline int convert_mode(long *msgtyp, int msgflg) { /* @@ -742,8 +748,8 @@ static inline int convert_mode(long *msg return SEARCH_EQUAL; } -asmlinkage long sys_msgrcv(int msqid, struct msgbuf __user *msgp, size_t msgsz, - long msgtyp, int msgflg) +long do_msgrcv(int msqid, struct msgbuf __user *msgp, void __user *mtext, + size_t msgsz, long msgtyp, int msgflg) { struct msg_queue *msq; struct msg_msg *msg; @@ -890,7 +896,7 @@ out_unlock: msgsz = (msgsz > msg->m_ts) ? msg->m_ts : msgsz; if (put_user (msg->m_type, &msgp->mtype) || - store_msg(msgp->mtext, msg, msgsz)) { + store_msg(mtext, msg, msgsz)) { msgsz = -EFAULT; } free_msg(msg); @@ -898,6 +904,12 @@ out_unlock: return msgsz; } +asmlinkage long sys_msgrcv(int msqid, struct msgbuf __user *msgp, size_t msgsz, + long msgtyp, int msgflg) +{ + return do_msgrcv(msqid, msgp, msgp->mtext, msgsz, msgtyp, msgflg); +} + #ifdef CONFIG_PROC_FS static int sysvipc_msg_proc_show(struct seq_file *s, void *it) { _