Skip to content

Commit 15b87e2

Browse files
committed
Merge branch 'selftests-net-a-couple-of-typos-fixes-in-key-management-rst-tests'
Dmitry Safonov says: ==================== selftests/net: A couple of typos fixes in key-management/rst tests Two typo fixes, noticed by Mohammad's review. And a fix for an issue that got uncovered. v1: https://lore.kernel.org/r/[email protected] Signed-off-by: Dmitry Safonov <[email protected]> ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents 585b40e + 6caf3ad commit 15b87e2

File tree

3 files changed

+124
-72
lines changed

3 files changed

+124
-72
lines changed

tools/testing/selftests/net/tcp_ao/key-management.c

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -417,9 +417,9 @@ struct test_key {
417417
matches_vrf : 1,
418418
is_current : 1,
419419
is_rnext : 1,
420-
used_on_handshake : 1,
421-
used_after_accept : 1,
422-
used_on_client : 1;
420+
used_on_server_tx : 1,
421+
used_on_client_tx : 1,
422+
skip_counters_checks : 1;
423423
};
424424

425425
struct key_collection {
@@ -609,16 +609,14 @@ static int key_collection_socket(bool server, unsigned int port)
609609
addr = &this_ip_dest;
610610
sndid = key->client_keyid;
611611
rcvid = key->server_keyid;
612-
set_current = key->is_current;
613-
set_rnext = key->is_rnext;
612+
key->used_on_client_tx = set_current = key->is_current;
613+
key->used_on_server_tx = set_rnext = key->is_rnext;
614614
}
615615

616616
if (test_add_key_cr(sk, key->password, key->len,
617617
*addr, vrf, sndid, rcvid, key->maclen,
618618
key->alg, set_current, set_rnext))
619619
test_key_error("setsockopt(TCP_AO_ADD_KEY)", key);
620-
if (set_current || set_rnext)
621-
key->used_on_handshake = 1;
622620
#ifdef DEBUG
623621
test_print("%s [%u/%u] key: { %s, %u:%u, %u, %u:%u:%u:%u (%u)}",
624622
server ? "server" : "client", i, collection.nr_keys,
@@ -640,22 +638,22 @@ static void verify_counters(const char *tst_name, bool is_listen_sk, bool server
640638
for (i = 0; i < collection.nr_keys; i++) {
641639
struct test_key *key = &collection.keys[i];
642640
uint8_t sndid, rcvid;
643-
bool was_used;
641+
bool rx_cnt_expected;
644642

643+
if (key->skip_counters_checks)
644+
continue;
645645
if (server) {
646646
sndid = key->server_keyid;
647647
rcvid = key->client_keyid;
648-
if (is_listen_sk)
649-
was_used = key->used_on_handshake;
650-
else
651-
was_used = key->used_after_accept;
648+
rx_cnt_expected = key->used_on_client_tx;
652649
} else {
653650
sndid = key->client_keyid;
654651
rcvid = key->server_keyid;
655-
was_used = key->used_on_client;
652+
rx_cnt_expected = key->used_on_server_tx;
656653
}
657654

658-
test_tcp_ao_key_counters_cmp(tst_name, a, b, was_used,
655+
test_tcp_ao_key_counters_cmp(tst_name, a, b,
656+
rx_cnt_expected ? TEST_CNT_KEY_GOOD : 0,
659657
sndid, rcvid);
660658
}
661659
test_tcp_ao_counters_free(a);
@@ -843,7 +841,7 @@ static void end_server(const char *tst_name, int sk,
843841
synchronize_threads(); /* 4: verified => closed */
844842
close(sk);
845843

846-
verify_counters(tst_name, true, false, begin, &end);
844+
verify_counters(tst_name, false, true, begin, &end);
847845
synchronize_threads(); /* 5: counters */
848846
}
849847

@@ -916,9 +914,8 @@ static int run_client(const char *tst_name, unsigned int port,
916914
current_index = nr_keys - 1;
917915
if (rnext_index < 0)
918916
rnext_index = nr_keys - 1;
919-
collection.keys[current_index].used_on_handshake = 1;
920-
collection.keys[rnext_index].used_after_accept = 1;
921-
collection.keys[rnext_index].used_on_client = 1;
917+
collection.keys[current_index].used_on_client_tx = 1;
918+
collection.keys[rnext_index].used_on_server_tx = 1;
922919

923920
synchronize_threads(); /* 3: accepted => send data */
924921
if (test_client_verify(sk, msg_sz, msg_nr, TEST_TIMEOUT_SEC)) {
@@ -1059,7 +1056,16 @@ static void check_current_back(const char *tst_name, unsigned int port,
10591056
test_error("Can't change the current key");
10601057
if (test_client_verify(sk, msg_len, nr_packets, TEST_TIMEOUT_SEC))
10611058
test_fail("verify failed");
1062-
collection.keys[rotate_to_index].used_after_accept = 1;
1059+
/* There is a race here: between setting the current_key with
1060+
* setsockopt(TCP_AO_INFO) and starting to send some data - there
1061+
* might have been a segment received with the desired
1062+
* RNext_key set. In turn that would mean that the first outgoing
1063+
* segment will have the desired current_key (flipped back).
1064+
* Which is what the user/test wants. As it's racy, skip checking
1065+
* the counters, yet check what are the resulting current/rnext
1066+
* keys on both sides.
1067+
*/
1068+
collection.keys[rotate_to_index].skip_counters_checks = 1;
10631069

10641070
end_client(tst_name, sk, nr_keys, current_index, rnext_index, &tmp);
10651071
}
@@ -1089,7 +1095,7 @@ static void roll_over_keys(const char *tst_name, unsigned int port,
10891095
}
10901096
verify_current_rnext(tst_name, sk, -1,
10911097
collection.keys[i].server_keyid);
1092-
collection.keys[i].used_on_client = 1;
1098+
collection.keys[i].used_on_server_tx = 1;
10931099
synchronize_threads(); /* verify current/rnext */
10941100
}
10951101
end_client(tst_name, sk, nr_keys, current_index, rnext_index, &tmp);

tools/testing/selftests/net/tcp_ao/lib/sock.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,9 @@ int test_wait_fd(int sk, time_t sec, bool write)
6262
return -ETIMEDOUT;
6363
}
6464

65-
if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &ret, &slen) || ret)
65+
if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &ret, &slen))
66+
return -errno;
67+
if (ret)
6668
return -ret;
6769
return 0;
6870
}
@@ -584,9 +586,11 @@ int test_client_verify(int sk, const size_t msg_len, const size_t nr,
584586
{
585587
size_t buf_sz = msg_len * nr;
586588
char *buf = alloca(buf_sz);
589+
ssize_t ret;
587590

588591
randomize_buffer(buf, buf_sz);
589-
if (test_client_loop(sk, buf, buf_sz, msg_len, timeout_sec) != buf_sz)
590-
return -1;
591-
return 0;
592+
ret = test_client_loop(sk, buf, buf_sz, msg_len, timeout_sec);
593+
if (ret < 0)
594+
return (int)ret;
595+
return ret != buf_sz ? -1 : 0;
592596
}

tools/testing/selftests/net/tcp_ao/rst.c

Lines changed: 90 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,33 @@
11
// SPDX-License-Identifier: GPL-2.0
2-
/* Author: Dmitry Safonov <[email protected]> */
2+
/*
3+
* The test checks that both active and passive reset have correct TCP-AO
4+
* signature. An "active" reset (abort) here is procured from closing
5+
* listen() socket with non-accepted connections in the queue:
6+
* inet_csk_listen_stop() => inet_child_forget() =>
7+
* => tcp_disconnect() => tcp_send_active_reset()
8+
*
9+
* The passive reset is quite hard to get on established TCP connections.
10+
* It could be procured from non-established states, but the synchronization
11+
* part from userspace in order to reliably get RST seems uneasy.
12+
* So, instead it's procured by corrupting SEQ number on TIMED-WAIT state.
13+
*
14+
* It's important to test both passive and active RST as they go through
15+
* different code-paths:
16+
* - tcp_send_active_reset() makes no-data skb, sends it with tcp_transmit_skb()
17+
* - tcp_v*_send_reset() create their reply skbs and send them with
18+
* ip_send_unicast_reply()
19+
*
20+
* In both cases TCP-AO signatures have to be correct, which is verified by
21+
* (1) checking that the TCP-AO connection was reset and (2) TCP-AO counters.
22+
*
23+
* Author: Dmitry Safonov <[email protected]>
24+
*/
325
#include <inttypes.h>
426
#include "../../../../include/linux/kernel.h"
527
#include "aolib.h"
628

729
const size_t quota = 1000;
30+
const size_t packet_sz = 100;
831
/*
932
* Backlog == 0 means 1 connection in queue, see:
1033
* commit 64a146513f8f ("[NET]: Revert incorrect accept queue...")
@@ -59,26 +82,6 @@ static void close_forced(int sk)
5982
close(sk);
6083
}
6184

62-
static int test_wait_for_exception(int sk, time_t sec)
63-
{
64-
struct timeval tv = { .tv_sec = sec };
65-
struct timeval *ptv = NULL;
66-
fd_set efds;
67-
int ret;
68-
69-
FD_ZERO(&efds);
70-
FD_SET(sk, &efds);
71-
72-
if (sec)
73-
ptv = &tv;
74-
75-
errno = 0;
76-
ret = select(sk + 1, NULL, NULL, &efds, ptv);
77-
if (ret < 0)
78-
return -errno;
79-
return ret ? sk : 0;
80-
}
81-
8285
static void test_server_active_rst(unsigned int port)
8386
{
8487
struct tcp_ao_counters cnt1, cnt2;
@@ -155,17 +158,16 @@ static void test_server_passive_rst(unsigned int port)
155158
test_fail("server returned %zd", bytes);
156159
}
157160

158-
synchronize_threads(); /* 3: chekpoint/restore the connection */
161+
synchronize_threads(); /* 3: checkpoint the client */
162+
synchronize_threads(); /* 4: close the server, creating twsk */
159163
if (test_get_tcp_ao_counters(sk, &ao2))
160164
test_error("test_get_tcp_ao_counters()");
161-
162-
synchronize_threads(); /* 4: terminate server + send more on client */
163-
bytes = test_server_run(sk, quota, TEST_RETRANSMIT_SEC);
164165
close(sk);
166+
167+
synchronize_threads(); /* 5: restore the socket, send more data */
165168
test_tcp_ao_counters_cmp("passive RST server", &ao1, &ao2, TEST_CNT_GOOD);
166169

167-
synchronize_threads(); /* 5: verified => closed */
168-
close(sk);
170+
synchronize_threads(); /* 6: server exits */
169171
}
170172

171173
static void *server_fn(void *arg)
@@ -284,7 +286,7 @@ static void test_client_active_rst(unsigned int port)
284286
test_error("test_wait_fds(): %d", err);
285287

286288
synchronize_threads(); /* 3: close listen socket */
287-
if (test_client_verify(sk[0], 100, quota / 100, TEST_TIMEOUT_SEC))
289+
if (test_client_verify(sk[0], packet_sz, quota / packet_sz, TEST_TIMEOUT_SEC))
288290
test_fail("Failed to send data on connected socket");
289291
else
290292
test_ok("Verified established tcp connection");
@@ -323,7 +325,6 @@ static void test_client_passive_rst(unsigned int port)
323325
struct tcp_sock_state img;
324326
sockaddr_af saddr;
325327
int sk, err;
326-
socklen_t slen = sizeof(err);
327328

328329
sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
329330
if (sk < 0)
@@ -337,18 +338,51 @@ static void test_client_passive_rst(unsigned int port)
337338
test_error("failed to connect()");
338339

339340
synchronize_threads(); /* 2: accepted => send data */
340-
if (test_client_verify(sk, 100, quota / 100, TEST_TIMEOUT_SEC))
341+
if (test_client_verify(sk, packet_sz, quota / packet_sz, TEST_TIMEOUT_SEC))
341342
test_fail("Failed to send data on connected socket");
342343
else
343344
test_ok("Verified established tcp connection");
344345

345-
synchronize_threads(); /* 3: chekpoint/restore the connection */
346+
synchronize_threads(); /* 3: checkpoint the client */
346347
test_enable_repair(sk);
347348
test_sock_checkpoint(sk, &img, &saddr);
348349
test_ao_checkpoint(sk, &ao_img);
349-
test_kill_sk(sk);
350+
test_disable_repair(sk);
350351

351-
img.out.seq += quota;
352+
synchronize_threads(); /* 4: close the server, creating twsk */
353+
354+
/*
355+
* The "corruption" in SEQ has to be small enough to fit into TCP
356+
* window, see tcp_timewait_state_process() for out-of-window
357+
* segments.
358+
*/
359+
img.out.seq += 5; /* 5 is more noticeable in tcpdump than 1 */
360+
361+
/*
362+
* FIXME: This is kind-of ugly and dirty, but it works.
363+
*
364+
* At this moment, the server has close'ed(sk).
365+
* The passive RST that is being targeted here is new data after
366+
* half-duplex close, see tcp_timewait_state_process() => TCP_TW_RST
367+
*
368+
* What is needed here is:
369+
* (1) wait for FIN from the server
370+
* (2) make sure that the ACK from the client went out
371+
* (3) make sure that the ACK was received and processed by the server
372+
*
373+
* Otherwise, the data that will be sent from "repaired" socket
374+
* post SEQ corruption may get to the server before it's in
375+
* TCP_FIN_WAIT2.
376+
*
377+
* (1) is easy with select()/poll()
378+
* (2) is possible by polling tcpi_state from TCP_INFO
379+
* (3) is quite complex: as server's socket was already closed,
380+
* probably the way to do it would be tcp-diag.
381+
*/
382+
sleep(TEST_RETRANSMIT_SEC);
383+
384+
synchronize_threads(); /* 5: restore the socket, send more data */
385+
test_kill_sk(sk);
352386

353387
sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
354388
if (sk < 0)
@@ -366,25 +400,33 @@ static void test_client_passive_rst(unsigned int port)
366400
test_disable_repair(sk);
367401
test_sock_state_free(&img);
368402

369-
synchronize_threads(); /* 4: terminate server + send more on client */
370-
if (test_client_verify(sk, 100, quota / 100, 2 * TEST_TIMEOUT_SEC))
371-
test_ok("client connection broken post-seq-adjust");
372-
else
373-
test_fail("client connection still works post-seq-adjust");
374-
375-
test_wait_for_exception(sk, TEST_TIMEOUT_SEC);
376-
377-
if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &err, &slen))
378-
test_error("getsockopt()");
379-
if (err != ECONNRESET && err != EPIPE)
380-
test_fail("client connection was not reset: %d", err);
403+
/*
404+
* This is how "passive reset" is acquired in this test from TCP_TW_RST:
405+
*
406+
* IP 10.0.254.1.7011 > 10.0.1.1.59772: Flags [P.], seq 901:1001, ack 1001, win 249,
407+
* options [tcp-ao keyid 100 rnextkeyid 100 mac 0x10217d6c36a22379086ef3b1], length 100
408+
* IP 10.0.254.1.7011 > 10.0.1.1.59772: Flags [F.], seq 1001, ack 1001, win 249,
409+
* options [tcp-ao keyid 100 rnextkeyid 100 mac 0x104ffc99b98c10a5298cc268], length 0
410+
* IP 10.0.1.1.59772 > 10.0.254.1.7011: Flags [.], ack 1002, win 251,
411+
* options [tcp-ao keyid 100 rnextkeyid 100 mac 0xe496dd4f7f5a8a66873c6f93,nop,nop,sack 1 {1001:1002}], length 0
412+
* IP 10.0.1.1.59772 > 10.0.254.1.7011: Flags [P.], seq 1006:1106, ack 1001, win 251,
413+
* options [tcp-ao keyid 100 rnextkeyid 100 mac 0x1b5f3330fb23fbcd0c77d0ca], length 100
414+
* IP 10.0.254.1.7011 > 10.0.1.1.59772: Flags [R], seq 3215596252, win 0,
415+
* options [tcp-ao keyid 100 rnextkeyid 100 mac 0x0bcfbbf497bce844312304b2], length 0
416+
*/
417+
err = test_client_verify(sk, packet_sz, quota / packet_sz, 2 * TEST_TIMEOUT_SEC);
418+
/* Make sure that the connection was reset, not timeouted */
419+
if (err && err == -ECONNRESET)
420+
test_ok("client sock was passively reset post-seq-adjust");
421+
else if (err)
422+
test_fail("client sock was not reset post-seq-adjust: %d", err);
381423
else
382-
test_ok("client connection was reset");
424+
test_fail("client sock is yet connected post-seq-adjust");
383425

384426
if (test_get_tcp_ao_counters(sk, &ao2))
385427
test_error("test_get_tcp_ao_counters()");
386428

387-
synchronize_threads(); /* 5: verified => closed */
429+
synchronize_threads(); /* 6: server exits */
388430
close(sk);
389431
test_tcp_ao_counters_cmp("client passive RST", &ao1, &ao2, TEST_CNT_GOOD);
390432
}
@@ -410,6 +452,6 @@ static void *client_fn(void *arg)
410452

411453
int main(int argc, char *argv[])
412454
{
413-
test_init(15, server_fn, client_fn);
455+
test_init(14, server_fn, client_fn);
414456
return 0;
415457
}

0 commit comments

Comments
 (0)