aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2018-10-05 09:05:35 -0400
committerDavid Howells <dhowells@redhat.com>2018-10-05 09:21:59 -0400
commit2cfa2271604bb26e75b828d38f357ed084464795 (patch)
treea86cf7c8b12a35b9a1ffd6e28ccc64bf855256aa
parent5e33a23ba4b56c109b732d57a0a76558a37d9ec5 (diff)
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>
-rw-r--r--net/rxrpc/input.c68
-rw-r--r--net/rxrpc/local_object.c11
2 files changed, 44 insertions, 35 deletions
diff --git a/net/rxrpc/input.c b/net/rxrpc/input.c
index c5af9955665b..c3114fa66c92 100644
--- a/net/rxrpc/input.c
+++ b/net/rxrpc/input.c
@@ -1121,7 +1121,7 @@ int rxrpc_extract_header(struct rxrpc_skb_priv *sp, struct sk_buff *skb)
1121 * shut down and the local endpoint from going away, thus sk_user_data will not 1121 * shut down and the local endpoint from going away, thus sk_user_data will not
1122 * be cleared until this function returns. 1122 * be cleared until this function returns.
1123 */ 1123 */
1124void rxrpc_data_ready(struct sock *udp_sk) 1124void rxrpc_input_packet(struct sock *udp_sk, struct sk_buff *skb)
1125{ 1125{
1126 struct rxrpc_connection *conn; 1126 struct rxrpc_connection *conn;
1127 struct rxrpc_channel *chan; 1127 struct rxrpc_channel *chan;
@@ -1130,39 +1130,11 @@ void rxrpc_data_ready(struct sock *udp_sk)
1130 struct rxrpc_local *local = udp_sk->sk_user_data; 1130 struct rxrpc_local *local = udp_sk->sk_user_data;
1131 struct rxrpc_peer *peer = NULL; 1131 struct rxrpc_peer *peer = NULL;
1132 struct rxrpc_sock *rx = NULL; 1132 struct rxrpc_sock *rx = NULL;
1133 struct sk_buff *skb;
1134 unsigned int channel; 1133 unsigned int channel;
1135 int ret, skew = 0; 1134 int skew = 0;
1136 1135
1137 _enter("%p", udp_sk); 1136 _enter("%p", udp_sk);
1138 1137
1139 ASSERT(!irqs_disabled());
1140
1141 skb = skb_recv_udp(udp_sk, 0, 1, &ret);
1142 if (!skb) {
1143 if (ret == -EAGAIN)
1144 return;
1145 _debug("UDP socket error %d", ret);
1146 return;
1147 }
1148
1149 if (skb->tstamp == 0)
1150 skb->tstamp = ktime_get_real();
1151
1152 rxrpc_new_skb(skb, rxrpc_skb_rx_received);
1153
1154 _net("recv skb %p", skb);
1155
1156 /* we'll probably need to checksum it (didn't call sock_recvmsg) */
1157 if (skb_checksum_complete(skb)) {
1158 rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
1159 __UDP_INC_STATS(sock_net(udp_sk), UDP_MIB_INERRORS, 0);
1160 _leave(" [CSUM failed]");
1161 return;
1162 }
1163
1164 __UDP_INC_STATS(sock_net(udp_sk), UDP_MIB_INDATAGRAMS, 0);
1165
1166 /* The UDP protocol already released all skb resources; 1138 /* The UDP protocol already released all skb resources;
1167 * we are free to add our own data there. 1139 * we are free to add our own data there.
1168 */ 1140 */
@@ -1181,6 +1153,8 @@ void rxrpc_data_ready(struct sock *udp_sk)
1181 } 1153 }
1182 } 1154 }
1183 1155
1156 if (skb->tstamp == 0)
1157 skb->tstamp = ktime_get_real();
1184 trace_rxrpc_rx_packet(sp); 1158 trace_rxrpc_rx_packet(sp);
1185 1159
1186 switch (sp->hdr.type) { 1160 switch (sp->hdr.type) {
@@ -1398,3 +1372,37 @@ reject_packet:
1398 rxrpc_reject_packet(local, skb); 1372 rxrpc_reject_packet(local, skb);
1399 _leave(" [badmsg]"); 1373 _leave(" [badmsg]");
1400} 1374}
1375
1376void rxrpc_data_ready(struct sock *udp_sk)
1377{
1378 struct sk_buff *skb;
1379 int ret;
1380
1381 for (;;) {
1382 skb = skb_recv_udp(udp_sk, 0, 1, &ret);
1383 if (!skb) {
1384 if (ret == -EAGAIN)
1385 return;
1386
1387 /* If there was a transmission failure, we get an error
1388 * here that we need to ignore.
1389 */
1390 _debug("UDP socket error %d", ret);
1391 continue;
1392 }
1393
1394 rxrpc_new_skb(skb, rxrpc_skb_rx_received);
1395
1396 /* we'll probably need to checksum it (didn't call sock_recvmsg) */
1397 if (skb_checksum_complete(skb)) {
1398 rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
1399 __UDP_INC_STATS(sock_net(udp_sk), UDP_MIB_INERRORS, 0);
1400 _debug("csum failed");
1401 continue;
1402 }
1403
1404 __UDP_INC_STATS(sock_net(udp_sk), UDP_MIB_INDATAGRAMS, 0);
1405
1406 rxrpc_input_packet(udp_sk, skb);
1407 }
1408}
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)
122 return ret; 122 return ret;
123 } 123 }
124 124
125 /* set the socket up */
126 sock = local->socket->sk;
127 sock->sk_user_data = local;
128 sock->sk_data_ready = rxrpc_data_ready;
129 sock->sk_error_report = rxrpc_error_report;
130
125 /* if a local address was supplied then bind it */ 131 /* if a local address was supplied then bind it */
126 if (local->srx.transport_len > sizeof(sa_family_t)) { 132 if (local->srx.transport_len > sizeof(sa_family_t)) {
127 _debug("bind"); 133 _debug("bind");
@@ -191,11 +197,6 @@ static int rxrpc_open_socket(struct rxrpc_local *local, struct net *net)
191 BUG(); 197 BUG();
192 } 198 }
193 199
194 /* set the socket up */
195 sock = local->socket->sk;
196 sock->sk_user_data = local;
197 sock->sk_data_ready = rxrpc_data_ready;
198 sock->sk_error_report = rxrpc_error_report;
199 _leave(" = 0"); 200 _leave(" = 0");
200 return 0; 201 return 0;
201 202