]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Add testing of bitflips in packet headers
authorTomas Mraz <tomas@openssl.org>
Tue, 3 Oct 2023 15:19:16 +0000 (17:19 +0200)
committerTomas Mraz <tomas@openssl.org>
Fri, 6 Oct 2023 08:24:58 +0000 (10:24 +0200)
A new type of noise is introduced in the noisy dgram bio
filter.

Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Paul Dale <pauli@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/22267)

test/helpers/noisydgrambio.c
test/quicapitest.c

index 33cf84c3c6c0a86f493ed54b2892015ecff9bd1f..445ae3c4ad1b3712d99b6265250ee3295db11824 100644 (file)
@@ -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
index 7739cbcb24b0ed4a6577c535f2bfc8b28b4c3c66..81c8c215bd43a9666754f0228a0efe39d60148b9 100644 (file)
@@ -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))