mirror of
https://github.com/tbsdtv/linux_media.git
synced 2025-07-23 12:43:29 +02:00
net: cleanly handle kernel vs user buffers for ->msg_control
The msg_control field in struct msghdr can either contain a user pointer when used with the recvmsg system call, or a kernel pointer when used with sendmsg. To complicate things further kernel_recvmsg can stuff a kernel pointer in and then use set_fs to make the uaccess helpers accept it. Replace it with a union of a kernel pointer msg_control field, and a user pointer msg_control_user one, and allow kernel_recvmsg operate on a proper kernel pointer using a bitfield to override the normal choice of a user pointer for recvmsg. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
2618d530dd
commit
1f466e1f15
22
net/socket.c
22
net/socket.c
@@ -924,14 +924,9 @@ EXPORT_SYMBOL(sock_recvmsg);
|
||||
int kernel_recvmsg(struct socket *sock, struct msghdr *msg,
|
||||
struct kvec *vec, size_t num, size_t size, int flags)
|
||||
{
|
||||
mm_segment_t oldfs = get_fs();
|
||||
int result;
|
||||
|
||||
msg->msg_control_is_user = false;
|
||||
iov_iter_kvec(&msg->msg_iter, READ, vec, num, size);
|
||||
set_fs(KERNEL_DS);
|
||||
result = sock_recvmsg(sock, msg, flags);
|
||||
set_fs(oldfs);
|
||||
return result;
|
||||
return sock_recvmsg(sock, msg, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(kernel_recvmsg);
|
||||
|
||||
@@ -2239,7 +2234,8 @@ int __copy_msghdr_from_user(struct msghdr *kmsg,
|
||||
if (copy_from_user(&msg, umsg, sizeof(*umsg)))
|
||||
return -EFAULT;
|
||||
|
||||
kmsg->msg_control = (void __force *)msg.msg_control;
|
||||
kmsg->msg_control_is_user = true;
|
||||
kmsg->msg_control_user = msg.msg_control;
|
||||
kmsg->msg_controllen = msg.msg_controllen;
|
||||
kmsg->msg_flags = msg.msg_flags;
|
||||
|
||||
@@ -2331,16 +2327,10 @@ static int ____sys_sendmsg(struct socket *sock, struct msghdr *msg_sys,
|
||||
goto out;
|
||||
}
|
||||
err = -EFAULT;
|
||||
/*
|
||||
* Careful! Before this, msg_sys->msg_control contains a user pointer.
|
||||
* Afterwards, it will be a kernel pointer. Thus the compiler-assisted
|
||||
* checking falls down on this.
|
||||
*/
|
||||
if (copy_from_user(ctl_buf,
|
||||
(void __user __force *)msg_sys->msg_control,
|
||||
ctl_len))
|
||||
if (copy_from_user(ctl_buf, msg_sys->msg_control_user, ctl_len))
|
||||
goto out_freectl;
|
||||
msg_sys->msg_control = ctl_buf;
|
||||
msg_sys->msg_control_is_user = false;
|
||||
}
|
||||
msg_sys->msg_flags = flags;
|
||||
|
||||
|
Reference in New Issue
Block a user