diff options
Diffstat (limited to 'net/core/scm.c')
| -rw-r--r-- | net/core/scm.c | 23 | 
1 files changed, 15 insertions, 8 deletions
diff --git a/net/core/scm.c b/net/core/scm.c index 8156d4fb8a39..ae3085d9aae8 100644 --- a/net/core/scm.c +++ b/net/core/scm.c @@ -228,14 +228,16 @@ int put_cmsg(struct msghdr * msg, int level, int type, int len, void *data)  	if (msg->msg_control_is_user) {  		struct cmsghdr __user *cm = msg->msg_control_user; -		struct cmsghdr cmhdr; - -		cmhdr.cmsg_level = level; -		cmhdr.cmsg_type = type; -		cmhdr.cmsg_len = cmlen; -		if (copy_to_user(cm, &cmhdr, sizeof cmhdr) || -		    copy_to_user(CMSG_USER_DATA(cm), data, cmlen - sizeof(*cm))) -			return -EFAULT; + +		if (!user_write_access_begin(cm, cmlen)) +			goto efault; + +		unsafe_put_user(cmlen, &cm->cmsg_len, efault_end); +		unsafe_put_user(level, &cm->cmsg_level, efault_end); +		unsafe_put_user(type, &cm->cmsg_type, efault_end); +		unsafe_copy_to_user(CMSG_USER_DATA(cm), data, +				    cmlen - sizeof(*cm), efault_end); +		user_write_access_end();  	} else {  		struct cmsghdr *cm = msg->msg_control; @@ -249,6 +251,11 @@ int put_cmsg(struct msghdr * msg, int level, int type, int len, void *data)  	msg->msg_control += cmlen;  	msg->msg_controllen -= cmlen;  	return 0; + +efault_end: +	user_write_access_end(); +efault: +	return -EFAULT;  }  EXPORT_SYMBOL(put_cmsg);  |