diff options
author | David Howells <dhowells@redhat.com> | 2018-10-05 14:05:35 +0100 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2018-10-05 14:21:59 +0100 |
commit | 2cfa2271604bb26e75b828d38f357ed084464795 (patch) | |
tree | a86cf7c8b12a35b9a1ffd6e28ccc64bf855256aa /net/rxrpc/local_object.c | |
parent | 5e33a23ba4b56c109b732d57a0a76558a37d9ec5 (diff) | |
download | lwn-2cfa2271604bb26e75b828d38f357ed084464795.tar.gz lwn-2cfa2271604bb26e75b828d38f357ed084464795.zip |
rxrpc: Fix the data_ready handler
Fix the rxrpc_data_ready() function to pick up all packets and to not miss
any. There are two problems:
(1) The sk_data_ready pointer on the UDP socket is set *after* it is
bound. This means that it's open for business before we're ready to
dequeue packets and there's a tiny window exists in which a packet can
sneak onto the receive queue, but we never know about it.
Fix this by setting the pointers on the socket prior to binding it.
(2) skb_recv_udp() will return an error (such as ENETUNREACH) if there was
an error on the transmission side, even though we set the
sk_error_report hook. Because rxrpc_data_ready() returns immediately
in such a case, it never actually removes its packet from the receive
queue.
Fix this by abstracting out the UDP dequeuing and checksumming into a
separate function that keeps hammering on skb_recv_udp() until it
returns -EAGAIN, passing the packets extracted to the remainder of the
function.
and two potential problems:
(3) It might be possible in some circumstances or in the future for
packets to be being added to the UDP receive queue whilst rxrpc is
running consuming them, so the data_ready() handler might get called
less often than once per packet.
Allow for this by fully draining the queue on each call as (2).
(4) If a packet fails the checksum check, the code currently returns after
discarding the packet without checking for more.
Allow for this by fully draining the queue on each call as (2).
Fixes: 17926a79320a ("[AF_RXRPC]: Provide secure RxRPC sockets for use by userspace and kernel both")
Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: Paolo Abeni <pabeni@redhat.com>
Diffstat (limited to 'net/rxrpc/local_object.c')
-rw-r--r-- | net/rxrpc/local_object.c | 11 |
1 files changed, 6 insertions, 5 deletions
diff --git a/net/rxrpc/local_object.c b/net/rxrpc/local_object.c index 94d234e9c685..30862f44c9f1 100644 --- a/net/rxrpc/local_object.c +++ b/net/rxrpc/local_object.c @@ -122,6 +122,12 @@ static int rxrpc_open_socket(struct rxrpc_local *local, struct net *net) return ret; } + /* set the socket up */ + sock = local->socket->sk; + sock->sk_user_data = local; + sock->sk_data_ready = rxrpc_data_ready; + sock->sk_error_report = rxrpc_error_report; + /* if a local address was supplied then bind it */ if (local->srx.transport_len > sizeof(sa_family_t)) { _debug("bind"); @@ -191,11 +197,6 @@ static int rxrpc_open_socket(struct rxrpc_local *local, struct net *net) BUG(); } - /* set the socket up */ - sock = local->socket->sk; - sock->sk_user_data = local; - sock->sk_data_ready = rxrpc_data_ready; - sock->sk_error_report = rxrpc_error_report; _leave(" = 0"); return 0; |