diff mbox series

[net,v2,2/3] net: prevent rewrite of msg_name in sock_sendmsg()

Message ID 20230918025021.4078252-2-jrife@google.com (mailing list archive)
State Superseded
Delegated to: Netdev Maintainers
Headers show
Series [net,v2,1/3] net: replace calls to sock->ops->connect() with kernel_connect() | expand

Checks

Context Check Description
netdev/series_format warning Series does not have a cover letter
netdev/tree_selection success Clearly marked for net
netdev/fixes_present fail Series targets non-next tree, but doesn't contain any Fixes tags
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 1343 this patch: 1343
netdev/cc_maintainers success CCed 5 of 5 maintainers
netdev/build_clang success Errors and warnings before: 1364 this patch: 1364
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 1366 this patch: 1366
netdev/checkpatch warning WARNING: line length of 86 exceeds 80 columns
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Jordan Rife Sept. 18, 2023, 2:50 a.m. UTC
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/

Signed-off-by: Jordan Rife <jrife@google.com>
---
v1->v2: Split up original patch into patch series. Perform address copy
	in sock_sendmsg() instead of sock->ops->sendmsg().

 net/socket.c | 32 ++++++++++++++++++++++++++------
 1 file changed, 26 insertions(+), 6 deletions(-)

Comments

Willem de Bruijn Sept. 18, 2023, 1:08 p.m. UTC | #1
On Sun, Sep 17, 2023 at 10:50 PM Jordan Rife <jrife@google.com> wrote:
>
> 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.

You used this short-hand to avoid having to update all callers to
sock_sendmsg to __kernel_sendmsg?

Unless the changes are massively worse than the other two patches, I
do think using the kernel_.. prefix is preferable, as it documents
that in-kernel users should use the kernel_.. sockets API rather than
directly call the sock_.. ones.

It's not clear that sock_sendmsg really is part of the kernel socket API.
Jordan Rife Sept. 18, 2023, 5:52 p.m. UTC | #2
> You used this short-hand to avoid having to update all callers to sock_sendmsg to __kernel_sendmsg?

Sorry about that, I misunderstood the intent. I'm fine with
introducing a new function, doing the address copy there, and
replacing all calls to sock_sendmsg with this wrapper. One thought on
the naming though,

To me the "__" prefix seems out of place for a function meant as a
public interface. Some possible alternatives:

1) Rename the current kernel_sendmsg() function to
kernel_sendmsg_kvec() and name  our new function kernel_sendmsg(). To
me this makes some sense, considering the new function is the more
generic of the two, and the existing kernel_sendmsg() specifically
accepts "struct kvec".
2) Same as #1, but drop the old kernel_sendmsg() function instead of
renaming it. Adapt all calls to the old kernel_sendmsg() to fit the
new kernel_sendmsg() (this amounts to adding a
iov_iter_kvec(&msg->msg_iter, ITER_SOURCE, vec, num, size); call in
each spot before kernel_sendmsg() is called.

-Jordan


On Mon, Sep 18, 2023 at 6:09 AM Willem de Bruijn
<willemdebruijn.kernel@gmail.com> wrote:
>
> On Sun, Sep 17, 2023 at 10:50 PM Jordan Rife <jrife@google.com> wrote:
> >
> > 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.
>
> You used this short-hand to avoid having to update all callers to
> sock_sendmsg to __kernel_sendmsg?
>
> Unless the changes are massively worse than the other two patches, I
> do think using the kernel_.. prefix is preferable, as it documents
> that in-kernel users should use the kernel_.. sockets API rather than
> directly call the sock_.. ones.
>
> It's not clear that sock_sendmsg really is part of the kernel socket API.
Willem de Bruijn Sept. 18, 2023, 5:54 p.m. UTC | #3
On Mon, Sep 18, 2023 at 1:52 PM Jordan Rife <jrife@google.com> wrote:
>
> > You used this short-hand to avoid having to update all callers to sock_sendmsg to __kernel_sendmsg?
>
> Sorry about that, I misunderstood the intent. I'm fine with
> introducing a new function, doing the address copy there, and
> replacing all calls to sock_sendmsg with this wrapper. One thought on
> the naming though,
>
> To me the "__" prefix seems out of place for a function meant as a
> public interface. Some possible alternatives:
>
> 1) Rename the current kernel_sendmsg() function to
> kernel_sendmsg_kvec() and name  our new function kernel_sendmsg(). To
> me this makes some sense, considering the new function is the more
> generic of the two, and the existing kernel_sendmsg() specifically
> accepts "struct kvec".
> 2) Same as #1, but drop the old kernel_sendmsg() function instead of
> renaming it. Adapt all calls to the old kernel_sendmsg() to fit the
> new kernel_sendmsg() (this amounts to adding a
> iov_iter_kvec(&msg->msg_iter, ITER_SOURCE, vec, num, size); call in
> each spot before kernel_sendmsg() is called.

Thanks. Fair points.

Of the two proposals, I think the first is preferable, as it avoids
some non-trivial open coding in multiple callers.
Jordan Rife Sept. 18, 2023, 6:02 p.m. UTC | #4
Sounds like a plan.

On Mon, Sep 18, 2023 at 10:55 AM Willem de Bruijn
<willemdebruijn.kernel@gmail.com> wrote:
>
> On Mon, Sep 18, 2023 at 1:52 PM Jordan Rife <jrife@google.com> wrote:
> >
> > > You used this short-hand to avoid having to update all callers to sock_sendmsg to __kernel_sendmsg?
> >
> > Sorry about that, I misunderstood the intent. I'm fine with
> > introducing a new function, doing the address copy there, and
> > replacing all calls to sock_sendmsg with this wrapper. One thought on
> > the naming though,
> >
> > To me the "__" prefix seems out of place for a function meant as a
> > public interface. Some possible alternatives:
> >
> > 1) Rename the current kernel_sendmsg() function to
> > kernel_sendmsg_kvec() and name  our new function kernel_sendmsg(). To
> > me this makes some sense, considering the new function is the more
> > generic of the two, and the existing kernel_sendmsg() specifically
> > accepts "struct kvec".
> > 2) Same as #1, but drop the old kernel_sendmsg() function instead of
> > renaming it. Adapt all calls to the old kernel_sendmsg() to fit the
> > new kernel_sendmsg() (this amounts to adding a
> > iov_iter_kvec(&msg->msg_iter, ITER_SOURCE, vec, num, size); call in
> > each spot before kernel_sendmsg() is called.
>
> Thanks. Fair points.
>
> Of the two proposals, I think the first is preferable, as it avoids
> some non-trivial open coding in multiple callers.
Jordan Rife Sept. 18, 2023, 8:48 p.m. UTC | #5
Just a heads up, there are also kernel_recvmsg/sock_recvmsg functions
that mirror the kernel_sendmsg/sock_sendmsg. If we are are doing this

> 1) Rename the current kernel_sendmsg() function to
> kernel_sendmsg_kvec() and name  our new function kernel_sendmsg(). To
> me this makes some sense, considering the new function is the more
> generic of the two, and the existing kernel_sendmsg() specifically
> accepts "struct kvec".

it creates an asymmetry between *sendmsg and *recvmsg function names.
If we wanted these to be similar then it means a rename to these
functions (e.g. kern_recvmsg becomes kern_recvmsg_kvec, rename
sock_recvmsg to kern_recvmsg).

-Jordan

On Mon, Sep 18, 2023 at 11:02 AM Jordan Rife <jrife@google.com> wrote:
>
> Sounds like a plan.
>
> On Mon, Sep 18, 2023 at 10:55 AM Willem de Bruijn
> <willemdebruijn.kernel@gmail.com> wrote:
> >
> > On Mon, Sep 18, 2023 at 1:52 PM Jordan Rife <jrife@google.com> wrote:
> > >
> > > > You used this short-hand to avoid having to update all callers to sock_sendmsg to __kernel_sendmsg?
> > >
> > > Sorry about that, I misunderstood the intent. I'm fine with
> > > introducing a new function, doing the address copy there, and
> > > replacing all calls to sock_sendmsg with this wrapper. One thought on
> > > the naming though,
> > >
> > > To me the "__" prefix seems out of place for a function meant as a
> > > public interface. Some possible alternatives:
> > >
> > > 1) Rename the current kernel_sendmsg() function to
> > > kernel_sendmsg_kvec() and name  our new function kernel_sendmsg(). To
> > > me this makes some sense, considering the new function is the more
> > > generic of the two, and the existing kernel_sendmsg() specifically
> > > accepts "struct kvec".
> > > 2) Same as #1, but drop the old kernel_sendmsg() function instead of
> > > renaming it. Adapt all calls to the old kernel_sendmsg() to fit the
> > > new kernel_sendmsg() (this amounts to adding a
> > > iov_iter_kvec(&msg->msg_iter, ITER_SOURCE, vec, num, size); call in
> > > each spot before kernel_sendmsg() is called.
> >
> > Thanks. Fair points.
> >
> > Of the two proposals, I think the first is preferable, as it avoids
> > some non-trivial open coding in multiple callers.
Willem de Bruijn Sept. 18, 2023, 9:25 p.m. UTC | #6
On Mon, Sep 18, 2023 at 4:49 PM Jordan Rife <jrife@google.com> wrote:
>
> Just a heads up, there are also kernel_recvmsg/sock_recvmsg functions
> that mirror the kernel_sendmsg/sock_sendmsg. If we are are doing this
>
> > 1) Rename the current kernel_sendmsg() function to
> > kernel_sendmsg_kvec() and name  our new function kernel_sendmsg(). To
> > me this makes some sense, considering the new function is the more
> > generic of the two, and the existing kernel_sendmsg() specifically
> > accepts "struct kvec".
>
> it creates an asymmetry between *sendmsg and *recvmsg function names.
> If we wanted these to be similar then it means a rename to these
> functions (e.g. kern_recvmsg becomes kern_recvmsg_kvec, rename
> sock_recvmsg to kern_recvmsg).

I see. That's definitely outside the realm of bug fix.

If we have to keep the two consistent, then I suppose your existing
fix is the best approach for net. And any renaming to clarify the API
is best left for net-next.
diff mbox series

Patch

diff --git a/net/socket.c b/net/socket.c
index b2e3700d035a6..b0189b773d130 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -737,6 +737,14 @@  static inline int sock_sendmsg_nosec(struct socket *sock, struct msghdr *msg)
 	return ret;
 }
 
+static int __sock_sendmsg(struct socket *sock, struct msghdr *msg)
+{
+	int err = security_socket_sendmsg(sock, msg,
+					  msg_data_left(msg));
+
+	return err ?: sock_sendmsg_nosec(sock, msg);
+}
+
 /**
  *	sock_sendmsg - send a message through @sock
  *	@sock: socket
@@ -747,10 +755,22 @@  static inline int sock_sendmsg_nosec(struct socket *sock, struct msghdr *msg)
  */
 int sock_sendmsg(struct socket *sock, struct msghdr *msg)
 {
-	int err = security_socket_sendmsg(sock, msg,
-					  msg_data_left(msg));
+	struct sockaddr_storage address;
+	struct sockaddr_storage *save_addr = (struct sockaddr_storage *)msg->msg_name;
+	int ret;
 
-	return err ?: sock_sendmsg_nosec(sock, msg);
+	if (msg->msg_name) {
+		if (msg->msg_namelen < 0 || msg->msg_namelen > sizeof(address))
+			return -EINVAL;
+
+		memcpy(&address, msg->msg_name, msg->msg_namelen);
+		msg->msg_name = &address;
+	}
+
+	ret = __sock_sendmsg(sock, msg);
+	msg->msg_name = save_addr;
+
+	return ret;
 }
 EXPORT_SYMBOL(sock_sendmsg);
 
@@ -1138,7 +1158,7 @@  static ssize_t sock_write_iter(struct kiocb *iocb, struct iov_iter *from)
 	if (sock->type == SOCK_SEQPACKET)
 		msg.msg_flags |= MSG_EOR;
 
-	res = sock_sendmsg(sock, &msg);
+	res = __sock_sendmsg(sock, &msg);
 	*from = msg.msg_iter;
 	return res;
 }
@@ -2174,7 +2194,7 @@  int __sys_sendto(int fd, void __user *buff, size_t len, unsigned int flags,
 	if (sock->file->f_flags & O_NONBLOCK)
 		flags |= MSG_DONTWAIT;
 	msg.msg_flags = flags;
-	err = sock_sendmsg(sock, &msg);
+	err = __sock_sendmsg(sock, &msg);
 
 out_put:
 	fput_light(sock->file, fput_needed);
@@ -2538,7 +2558,7 @@  static int ____sys_sendmsg(struct socket *sock, struct msghdr *msg_sys,
 		err = sock_sendmsg_nosec(sock, msg_sys);
 		goto out_freectl;
 	}
-	err = sock_sendmsg(sock, msg_sys);
+	err = __sock_sendmsg(sock, msg_sys);
 	/*
 	 * If this is sendmmsg() and sending to current destination address was
 	 * successful, remember it.