Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: prevent rewrite of msg_name in sock_sendmsg()

Callers of sock_sendmsg(), and similarly kernel_sendmsg(), in kernel
space may observe their value of msg_name change in cases where BPF
sendmsg hooks rewrite the send address. This has been confirmed to break
NFS mounts running in UDP mode and has the potential to break other
systems.

This patch:

1) Creates a new function called __sock_sendmsg() with same logic as the
old sock_sendmsg() function.
2) Replaces calls to sock_sendmsg() made by __sys_sendto() and
__sys_sendmsg() with __sock_sendmsg() to avoid an unnecessary copy,
as these system calls are already protected.
3) Modifies sock_sendmsg() so that it makes a copy of msg_name if
present before passing it down the stack to insulate callers from
changes to the send address.

Link: https://lore.kernel.org/netdev/20230912013332.2048422-1-jrife@google.com/
Fixes: 1cedee13d25a ("bpf: Hooks for sys_sendmsg")
Cc: stable@vger.kernel.org
Reviewed-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: Jordan Rife <jrife@google.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Jordan Rife and committed by
David S. Miller
86a7e0b6 26297b4c

+23 -6
+23 -6
net/socket.c
··· 737 737 return ret; 738 738 } 739 739 740 + static int __sock_sendmsg(struct socket *sock, struct msghdr *msg) 741 + { 742 + int err = security_socket_sendmsg(sock, msg, 743 + msg_data_left(msg)); 744 + 745 + return err ?: sock_sendmsg_nosec(sock, msg); 746 + } 747 + 740 748 /** 741 749 * sock_sendmsg - send a message through @sock 742 750 * @sock: socket ··· 755 747 */ 756 748 int sock_sendmsg(struct socket *sock, struct msghdr *msg) 757 749 { 758 - int err = security_socket_sendmsg(sock, msg, 759 - msg_data_left(msg)); 750 + struct sockaddr_storage *save_addr = (struct sockaddr_storage *)msg->msg_name; 751 + struct sockaddr_storage address; 752 + int ret; 760 753 761 - return err ?: sock_sendmsg_nosec(sock, msg); 754 + if (msg->msg_name) { 755 + memcpy(&address, msg->msg_name, msg->msg_namelen); 756 + msg->msg_name = &address; 757 + } 758 + 759 + ret = __sock_sendmsg(sock, msg); 760 + msg->msg_name = save_addr; 761 + 762 + return ret; 762 763 } 763 764 EXPORT_SYMBOL(sock_sendmsg); 764 765 ··· 1155 1138 if (sock->type == SOCK_SEQPACKET) 1156 1139 msg.msg_flags |= MSG_EOR; 1157 1140 1158 - res = sock_sendmsg(sock, &msg); 1141 + res = __sock_sendmsg(sock, &msg); 1159 1142 *from = msg.msg_iter; 1160 1143 return res; 1161 1144 } ··· 2191 2174 if (sock->file->f_flags & O_NONBLOCK) 2192 2175 flags |= MSG_DONTWAIT; 2193 2176 msg.msg_flags = flags; 2194 - err = sock_sendmsg(sock, &msg); 2177 + err = __sock_sendmsg(sock, &msg); 2195 2178 2196 2179 out_put: 2197 2180 fput_light(sock->file, fput_needed); ··· 2555 2538 err = sock_sendmsg_nosec(sock, msg_sys); 2556 2539 goto out_freectl; 2557 2540 } 2558 - err = sock_sendmsg(sock, msg_sys); 2541 + err = __sock_sendmsg(sock, msg_sys); 2559 2542 /* 2560 2543 * If this is sendmmsg() and sending to current destination address was 2561 2544 * successful, remember it.