From 6dfc57f8a901f2cb40664a9f2060a91943a7982c Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Tue, 3 Oct 2023 17:19:16 +0200 Subject: Add testing of bitflips in packet headers A new type of noise is introduced in the noisy dgram bio filter. Reviewed-by: Matt Caswell Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/22267) --- test/helpers/noisydgrambio.c | 63 ++++++++++++++++++++++++++++++++++++++------ test/quicapitest.c | 28 ++++++++++---------- 2 files changed, 69 insertions(+), 22 deletions(-) (limited to 'test') diff --git a/test/helpers/noisydgrambio.c b/test/helpers/noisydgrambio.c index 33cf84c3c6..445ae3c4ad 100644 --- a/test/helpers/noisydgrambio.c +++ b/test/helpers/noisydgrambio.c @@ -75,7 +75,8 @@ static int noisy_dgram_sendmmsg(BIO *bio, BIO_MSG *msg, size_t stride, #define NOISE_TYPE_DROP 0 #define NOISE_TYPE_DUPLICATE 1 #define NOISE_TYPE_DELAY 2 -#define NUM_NOISE_TYPES 3 +#define NOISE_TYPE_BITFLIPS 3 +#define NUM_NOISE_TYPES 4 /* * When a duplicate occurs we reinject the new datagram after up to @@ -89,10 +90,13 @@ static int noisy_dgram_sendmmsg(BIO *bio, BIO_MSG *msg, size_t stride, */ #define MAX_DGRAM_REINJECT 4 -static void get_noise(uint64_t *reinject, int *should_drop) +static void get_noise(int long_header, uint64_t *reinject, int *should_drop, + uint16_t *flip, size_t *flip_offset) { uint32_t type; + *flip = 0; + if (test_random() % NOISE_RATE != 0) { *reinject = 0; *should_drop = 0; @@ -102,7 +106,7 @@ static void get_noise(uint64_t *reinject, int *should_drop) type = test_random() % NUM_NOISE_TYPES; /* - * Of noisy datagrams, 33% drop, 33% duplicate, 33% delay + * Of noisy datagrams, 25% drop, 25% duplicate, 25% delay, 25% flip bits * A duplicated datagram keeps the current datagram and reinjects a new * identical one after up to MAX_DGRAM_DELAY datagrams have been sent. * A delayed datagram is implemented as both a reinject and a drop, i.e. an @@ -115,16 +119,50 @@ static void get_noise(uint64_t *reinject, int *should_drop) * Where a duplicate occurs we reinject the copy of the datagram up to * MAX_DGRAM_DELAY datagrams later */ - *reinject = (type == NOISE_TYPE_DROP) - ? 0 - : (uint64_t)((test_random() % MAX_DGRAM_REINJECT) + 1); + *reinject = (type == NOISE_TYPE_DUPLICATE || type == NOISE_TYPE_DELAY) + ? (uint64_t)((test_random() % MAX_DGRAM_REINJECT) + 1) + : 0; /* * No point in reinjecting after 1 datagram if the current datagram is also * dropped (i.e. this is a delay not a duplicate), so we reinject after an * extra datagram in that case */ - *reinject += (uint64_t)(*should_drop); + *reinject += type == NOISE_TYPE_DELAY; + + /* flip some bits in the header */ + if (type == NOISE_TYPE_BITFLIPS) { + /* we flip at most 8 bits of the 16 bit value at once */ + *flip = (test_random() % 255 + 1) << (test_random() % 8); + /* + * 25/50 bytes of guesstimated header size (it depends on CID length) + * It does not matter much if it is overestimated. + */ + *flip_offset = test_random() % (25 * (1 + long_header)); + } +} + +static void flip_bits(unsigned char *msg, size_t msg_len, uint16_t flip, + size_t flip_offset) +{ + if (flip == 0) + return; + + /* None of these border conditions should happen but check them anyway */ + if (msg_len < 2) + return; + if (msg_len < flip_offset + 2) + flip_offset = msg_len - 2; + +#ifdef OSSL_NOISY_DGRAM_DEBUG + printf("**Flipping bits in a datagram at offset %u\n", + (unsigned int)flip_offset); + BIO_dump_fp(stdout, msg, msg_len); + printf("\n"); +#endif + + msg[flip_offset] ^= flip >> 8; + msg[flip_offset + 1] ^= flip & 0xff; } static int noisy_dgram_recvmmsg(BIO *bio, BIO_MSG *msg, size_t stride, @@ -181,6 +219,8 @@ static int noisy_dgram_recvmmsg(BIO *bio, BIO_MSG *msg, size_t stride, i++, thismsg++, data->this_dgram++) { uint64_t reinject; int should_drop; + uint16_t flip; + size_t flip_offset; /* If we have a message to reinject then insert it now */ if (data->reinject_dgram > 0 @@ -205,7 +245,8 @@ static int noisy_dgram_recvmmsg(BIO *bio, BIO_MSG *msg, size_t stride, data->reinject_dgram = 0; } - get_noise(&reinject, &should_drop); + get_noise(/* long header */ (((uint8_t *)thismsg->data)[0] & 0x80) != 0, + &reinject, &should_drop, &flip, &flip_offset); if (data->backoff) { /* * We might be asked to back off on introducing too much noise if @@ -214,10 +255,16 @@ static int noisy_dgram_recvmmsg(BIO *bio, BIO_MSG *msg, size_t stride, * that the connection always survives. After that we can resume * with normal noise */ +#ifdef OSSL_NOISY_DGRAM_DEBUG + printf("**Back off applied\n"); +#endif should_drop = 0; + flip = 0; data->backoff = 0; } + flip_bits(thismsg->data, thismsg->data_len, flip, flip_offset); + /* * We ignore reinjection if a message is already waiting to be * reinjected diff --git a/test/quicapitest.c b/test/quicapitest.c index 7739cbcb24..81c8c215bd 100644 --- a/test/quicapitest.c +++ b/test/quicapitest.c @@ -1439,11 +1439,11 @@ static int test_noisy_dgram(int idx) qtest_add_time(1); /* - * Send data from the server to the client. Some datagrams may get lost, - * dropped or re-ordered. We repeat 10 times to ensure we are sending - * enough datagrams for problems to be noticed. - */ - for (i = 0; i < 10; i++) { + * Send data from the server to the client. Some datagrams may get + * lost, modified, dropped or re-ordered. We repeat 20 times to ensure + * we are sending enough datagrams for problems to be noticed. + */ + for (i = 0; i < 20; i++) { if (!TEST_true(ossl_quic_tserver_write(qtserv, sid, (unsigned char *)msg, msglen, &written)) @@ -1453,10 +1453,10 @@ static int test_noisy_dgram(int idx) qtest_add_time(1); /* - * Since the underlying BIO is now noisy we may get failures that - * need to be retried - so we use unreliable_client_read() to handle - * that - */ + * Since the underlying BIO is now noisy we may get failures that + * need to be retried - so we use unreliable_client_read() to + * handle that + */ if (!TEST_true(unreliable_client_read(clientquic, &stream[j], buf, sizeof(buf), &readbytes, qtserv)) @@ -1465,7 +1465,7 @@ static int test_noisy_dgram(int idx) } /* Send data from the client to the server */ - for (i = 0; i < 10; i++) { + for (i = 0; i < 20; i++) { if (!TEST_true(SSL_write_ex(stream[j], (unsigned char *)msg, msglen, &written)) || !TEST_size_t_eq(msglen, written)) @@ -1475,10 +1475,10 @@ static int test_noisy_dgram(int idx) qtest_add_time(1); /* - * Since the underlying BIO is now noisy we may get failures that - * need to be retried - so we use unreliable_server_read() to handle - * that - */ + * Since the underlying BIO is now noisy we may get failures that + * need to be retried - so we use unreliable_server_read() to + * handle that + */ if (!TEST_true(unreliable_server_read(qtserv, sid, buf, sizeof(buf), &readbytes, clientquic)) || !TEST_mem_eq(msg, msglen, buf, readbytes)) -- cgit v1.2.3