diff options
Diffstat (limited to 'ipc/msg.c')
| -rw-r--r-- | ipc/msg.c | 44 | 
1 files changed, 23 insertions, 21 deletions
diff --git a/ipc/msg.c b/ipc/msg.c index 2f272fa7659..cefc24f46e3 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -755,15 +755,30 @@ static inline int convert_mode(long *msgtyp, int msgflg)  	return SEARCH_EQUAL;  } -long do_msgrcv(int msqid, long *pmtype, void __user *mtext, -		size_t msgsz, long msgtyp, int msgflg) +static long do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz) +{ +	struct msgbuf __user *msgp = dest; +	size_t msgsz; + +	if (put_user(msg->m_type, &msgp->mtype)) +		return -EFAULT; + +	msgsz = (bufsz > msg->m_ts) ? msg->m_ts : bufsz; +	if (store_msg(msgp->mtext, msg, msgsz)) +		return -EFAULT; +	return msgsz; +} + +long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, +	       int msgflg, +	       long (*msg_handler)(void __user *, struct msg_msg *, size_t))  {  	struct msg_queue *msq;  	struct msg_msg *msg;  	int mode;  	struct ipc_namespace *ns; -	if (msqid < 0 || (long) msgsz < 0) +	if (msqid < 0 || (long) bufsz < 0)  		return -EINVAL;  	mode = convert_mode(&msgtyp, msgflg);  	ns = current->nsproxy->ipc_ns; @@ -804,7 +819,7 @@ long do_msgrcv(int msqid, long *pmtype, void __user *mtext,  			 * Found a suitable message.  			 * Unlink it from the queue.  			 */ -			if ((msgsz < msg->m_ts) && !(msgflg & MSG_NOERROR)) { +			if ((bufsz < msg->m_ts) && !(msgflg & MSG_NOERROR)) {  				msg = ERR_PTR(-E2BIG);  				goto out_unlock;  			} @@ -831,7 +846,7 @@ long do_msgrcv(int msqid, long *pmtype, void __user *mtext,  		if (msgflg & MSG_NOERROR)  			msr_d.r_maxsize = INT_MAX;  		else -			msr_d.r_maxsize = msgsz; +			msr_d.r_maxsize = bufsz;  		msr_d.r_msg = ERR_PTR(-EAGAIN);  		current->state = TASK_INTERRUPTIBLE;  		msg_unlock(msq); @@ -894,29 +909,16 @@ out_unlock:  	if (IS_ERR(msg))  		return PTR_ERR(msg); -	msgsz = (msgsz > msg->m_ts) ? msg->m_ts : msgsz; -	*pmtype = msg->m_type; -	if (store_msg(mtext, msg, msgsz)) -		msgsz = -EFAULT; - +	bufsz = msg_handler(buf, msg, bufsz);  	free_msg(msg); -	return msgsz; +	return bufsz;  }  SYSCALL_DEFINE5(msgrcv, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz,  		long, msgtyp, int, msgflg)  { -	long err, mtype; - -	err =  do_msgrcv(msqid, &mtype, msgp->mtext, msgsz, msgtyp, msgflg); -	if (err < 0) -		goto out; - -	if (put_user(mtype, &msgp->mtype)) -		err = -EFAULT; -out: -	return err; +	return do_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg, do_msg_fill);  }  #ifdef CONFIG_PROC_FS  |