net: Ensure ->msg_control_user is used for user buffers
Since commit 1f466e1f15
("net: cleanly handle kernel vs user
buffers for ->msg_control"), pointers to user buffers should be
stored in struct msghdr::msg_control_user, instead of the
msg_control field. Most users of msg_control have already been
converted (where user buffers are involved), but not all of them.
This patch attempts to address the remaining cases. An exception is
made for null checks, as it should be safe to use msg_control
unconditionally for that purpose.
Cc: Christoph Hellwig <hch@lst.de>
Cc: Eric Dumazet <edumazet@google.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
eaaa4e9239
commit
c39ef21304
12
net/compat.c
12
net/compat.c
@ -113,7 +113,7 @@ int get_compat_msghdr(struct msghdr *kmsg,
|
|||||||
|
|
||||||
#define CMSG_COMPAT_FIRSTHDR(msg) \
|
#define CMSG_COMPAT_FIRSTHDR(msg) \
|
||||||
(((msg)->msg_controllen) >= sizeof(struct compat_cmsghdr) ? \
|
(((msg)->msg_controllen) >= sizeof(struct compat_cmsghdr) ? \
|
||||||
(struct compat_cmsghdr __user *)((msg)->msg_control) : \
|
(struct compat_cmsghdr __user *)((msg)->msg_control_user) : \
|
||||||
(struct compat_cmsghdr __user *)NULL)
|
(struct compat_cmsghdr __user *)NULL)
|
||||||
|
|
||||||
#define CMSG_COMPAT_OK(ucmlen, ucmsg, mhdr) \
|
#define CMSG_COMPAT_OK(ucmlen, ucmsg, mhdr) \
|
||||||
@ -126,7 +126,7 @@ static inline struct compat_cmsghdr __user *cmsg_compat_nxthdr(struct msghdr *ms
|
|||||||
struct compat_cmsghdr __user *cmsg, int cmsg_len)
|
struct compat_cmsghdr __user *cmsg, int cmsg_len)
|
||||||
{
|
{
|
||||||
char __user *ptr = (char __user *)cmsg + CMSG_COMPAT_ALIGN(cmsg_len);
|
char __user *ptr = (char __user *)cmsg + CMSG_COMPAT_ALIGN(cmsg_len);
|
||||||
if ((unsigned long)(ptr + 1 - (char __user *)msg->msg_control) >
|
if ((unsigned long)(ptr + 1 - (char __user *)msg->msg_control_user) >
|
||||||
msg->msg_controllen)
|
msg->msg_controllen)
|
||||||
return NULL;
|
return NULL;
|
||||||
return (struct compat_cmsghdr __user *)ptr;
|
return (struct compat_cmsghdr __user *)ptr;
|
||||||
@ -225,7 +225,7 @@ Efault:
|
|||||||
|
|
||||||
int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *data)
|
int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *data)
|
||||||
{
|
{
|
||||||
struct compat_cmsghdr __user *cm = (struct compat_cmsghdr __user *) kmsg->msg_control;
|
struct compat_cmsghdr __user *cm = (struct compat_cmsghdr __user *) kmsg->msg_control_user;
|
||||||
struct compat_cmsghdr cmhdr;
|
struct compat_cmsghdr cmhdr;
|
||||||
struct old_timeval32 ctv;
|
struct old_timeval32 ctv;
|
||||||
struct old_timespec32 cts[3];
|
struct old_timespec32 cts[3];
|
||||||
@ -274,7 +274,7 @@ int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *dat
|
|||||||
cmlen = CMSG_COMPAT_SPACE(len);
|
cmlen = CMSG_COMPAT_SPACE(len);
|
||||||
if (kmsg->msg_controllen < cmlen)
|
if (kmsg->msg_controllen < cmlen)
|
||||||
cmlen = kmsg->msg_controllen;
|
cmlen = kmsg->msg_controllen;
|
||||||
kmsg->msg_control += cmlen;
|
kmsg->msg_control_user += cmlen;
|
||||||
kmsg->msg_controllen -= cmlen;
|
kmsg->msg_controllen -= cmlen;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -289,7 +289,7 @@ static int scm_max_fds_compat(struct msghdr *msg)
|
|||||||
void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm)
|
void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm)
|
||||||
{
|
{
|
||||||
struct compat_cmsghdr __user *cm =
|
struct compat_cmsghdr __user *cm =
|
||||||
(struct compat_cmsghdr __user *)msg->msg_control;
|
(struct compat_cmsghdr __user *)msg->msg_control_user;
|
||||||
unsigned int o_flags = (msg->msg_flags & MSG_CMSG_CLOEXEC) ? O_CLOEXEC : 0;
|
unsigned int o_flags = (msg->msg_flags & MSG_CMSG_CLOEXEC) ? O_CLOEXEC : 0;
|
||||||
int fdmax = min_t(int, scm_max_fds_compat(msg), scm->fp->count);
|
int fdmax = min_t(int, scm_max_fds_compat(msg), scm->fp->count);
|
||||||
int __user *cmsg_data = CMSG_COMPAT_DATA(cm);
|
int __user *cmsg_data = CMSG_COMPAT_DATA(cm);
|
||||||
@ -313,7 +313,7 @@ void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm)
|
|||||||
cmlen = CMSG_COMPAT_SPACE(i * sizeof(int));
|
cmlen = CMSG_COMPAT_SPACE(i * sizeof(int));
|
||||||
if (msg->msg_controllen < cmlen)
|
if (msg->msg_controllen < cmlen)
|
||||||
cmlen = msg->msg_controllen;
|
cmlen = msg->msg_controllen;
|
||||||
msg->msg_control += cmlen;
|
msg->msg_control_user += cmlen;
|
||||||
msg->msg_controllen -= cmlen;
|
msg->msg_controllen -= cmlen;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -250,7 +250,10 @@ int put_cmsg(struct msghdr * msg, int level, int type, int len, void *data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
cmlen = min(CMSG_SPACE(len), msg->msg_controllen);
|
cmlen = min(CMSG_SPACE(len), msg->msg_controllen);
|
||||||
msg->msg_control += cmlen;
|
if (msg->msg_control_is_user)
|
||||||
|
msg->msg_control_user += cmlen;
|
||||||
|
else
|
||||||
|
msg->msg_control += cmlen;
|
||||||
msg->msg_controllen -= cmlen;
|
msg->msg_controllen -= cmlen;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -299,7 +302,7 @@ static int scm_max_fds(struct msghdr *msg)
|
|||||||
void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
|
void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
|
||||||
{
|
{
|
||||||
struct cmsghdr __user *cm =
|
struct cmsghdr __user *cm =
|
||||||
(__force struct cmsghdr __user *)msg->msg_control;
|
(__force struct cmsghdr __user *)msg->msg_control_user;
|
||||||
unsigned int o_flags = (msg->msg_flags & MSG_CMSG_CLOEXEC) ? O_CLOEXEC : 0;
|
unsigned int o_flags = (msg->msg_flags & MSG_CMSG_CLOEXEC) ? O_CLOEXEC : 0;
|
||||||
int fdmax = min_t(int, scm_max_fds(msg), scm->fp->count);
|
int fdmax = min_t(int, scm_max_fds(msg), scm->fp->count);
|
||||||
int __user *cmsg_data = CMSG_USER_DATA(cm);
|
int __user *cmsg_data = CMSG_USER_DATA(cm);
|
||||||
@ -332,7 +335,7 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
|
|||||||
cmlen = CMSG_SPACE(i * sizeof(int));
|
cmlen = CMSG_SPACE(i * sizeof(int));
|
||||||
if (msg->msg_controllen < cmlen)
|
if (msg->msg_controllen < cmlen)
|
||||||
cmlen = msg->msg_controllen;
|
cmlen = msg->msg_controllen;
|
||||||
msg->msg_control += cmlen;
|
msg->msg_control_user += cmlen;
|
||||||
msg->msg_controllen -= cmlen;
|
msg->msg_controllen -= cmlen;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2165,7 +2165,7 @@ static void tcp_zc_finalize_rx_tstamp(struct sock *sk,
|
|||||||
struct msghdr cmsg_dummy;
|
struct msghdr cmsg_dummy;
|
||||||
|
|
||||||
msg_control_addr = (unsigned long)zc->msg_control;
|
msg_control_addr = (unsigned long)zc->msg_control;
|
||||||
cmsg_dummy.msg_control = (void *)msg_control_addr;
|
cmsg_dummy.msg_control_user = (void __user *)msg_control_addr;
|
||||||
cmsg_dummy.msg_controllen =
|
cmsg_dummy.msg_controllen =
|
||||||
(__kernel_size_t)zc->msg_controllen;
|
(__kernel_size_t)zc->msg_controllen;
|
||||||
cmsg_dummy.msg_flags = in_compat_syscall()
|
cmsg_dummy.msg_flags = in_compat_syscall()
|
||||||
@ -2176,7 +2176,7 @@ static void tcp_zc_finalize_rx_tstamp(struct sock *sk,
|
|||||||
zc->msg_controllen == cmsg_dummy.msg_controllen) {
|
zc->msg_controllen == cmsg_dummy.msg_controllen) {
|
||||||
tcp_recv_timestamp(&cmsg_dummy, sk, tss);
|
tcp_recv_timestamp(&cmsg_dummy, sk, tss);
|
||||||
zc->msg_control = (__u64)
|
zc->msg_control = (__u64)
|
||||||
((uintptr_t)cmsg_dummy.msg_control);
|
((uintptr_t)cmsg_dummy.msg_control_user);
|
||||||
zc->msg_controllen =
|
zc->msg_controllen =
|
||||||
(__u64)cmsg_dummy.msg_controllen;
|
(__u64)cmsg_dummy.msg_controllen;
|
||||||
zc->msg_flags = (__u32)cmsg_dummy.msg_flags;
|
zc->msg_flags = (__u32)cmsg_dummy.msg_flags;
|
||||||
|
Loading…
Reference in New Issue
Block a user