]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
RPKI: Fix several errors in handling of Error PDU
authorOndrej Zajicek <santiago@crfreenet.org>
Tue, 3 Dec 2024 00:19:44 +0000 (01:19 +0100)
committerOndrej Zajicek <santiago@crfreenet.org>
Tue, 3 Dec 2024 00:19:44 +0000 (01:19 +0100)
Fix several errors including:
 - Unaligned memory access to 'Length of Error Text' field
 - No validation of 'Length of Encapsulated PDU' field
 - No validation of 'Error Code' field
 - No validation of characters in diagnostic message

lib/unaligned.h
proto/rpki/packets.c

index dfe0906f8d1118adf97f3a36c48ea916c10a5362..0ea4dfb7e76f0b64881f177df857b04ff52a9e74 100644 (file)
@@ -113,4 +113,19 @@ put_u32s(void *p, const u32 *x, int n)
 }
 
 
+static inline u32
+get_u32he(const void *p)
+{
+  u32 x;
+  memcpy(&x, p, 4);
+  return x;
+}
+
+static inline void
+put_u32he(void *p, u32 x)
+{
+  memcpy(p, &x, 4);
+}
+
+
 #endif
index 3300c9c9affbbd6bc68dce3f167590f0be44234f..bbef16ef52cfcf82d50296441cd51b7307e0dd38 100644 (file)
@@ -38,7 +38,7 @@ enum pdu_error_type {
   PDU_TOO_BIG                  = 32
 };
 
-static const char *str_pdu_error_type[] = {
+static const char *str_pdu_error_type_[] = {
   [CORRUPT_DATA]               = "Corrupt-Data",
   [INTERNAL_ERROR]             = "Internal-Error",
   [NO_DATA_AVAIL]              = "No-Data-Available",
@@ -50,6 +50,13 @@ static const char *str_pdu_error_type[] = {
   [PDU_TOO_BIG]                = "PDU-Too-Big",
 };
 
+static const char *
+str_pdu_error_type(uint type)
+{
+  return (type < ARRAY_SIZE(str_pdu_error_type_)) ?
+    str_pdu_error_type_[type] : "Unknown error type";
+}
+
 enum pdu_type {
   SERIAL_NOTIFY                = 0,
   SERIAL_QUERY                         = 1,
@@ -289,8 +296,8 @@ rpki_pdu_to_network_byte_order(struct pdu_header *pdu)
   case ERROR:
   {
     struct pdu_error *err = (void *) pdu;
-    u32 *err_text_len = (u32 *)(err->rest + err->len_enc_pdu);
-    *err_text_len = htonl(*err_text_len);
+    byte *err_text_len = err->rest + err->len_enc_pdu;
+    put_u32(err_text_len, get_u32he(err_text_len));
     err->len_enc_pdu = htonl(err->len_enc_pdu);
     break;
   }
@@ -355,8 +362,13 @@ rpki_pdu_to_host_byte_order(struct pdu_header *pdu)
     struct pdu_error *err = (void *) pdu;
     err->error_code = ntohs(err->error_code);
     err->len_enc_pdu = ntohl(err->len_enc_pdu);
-    u32 *err_text_len = (u32 *)(err->rest + err->len_enc_pdu);
-    *err_text_len = htonl(*err_text_len);
+
+    /* Check if len_enc_pdu is sane */
+    if (err->len_enc_pdu > pdu->len - 16)
+      break;
+
+    byte *err_text_len = err->rest + err->len_enc_pdu;
+    put_u32he(err_text_len, get_u32(err_text_len));
     break;
   }
 
@@ -475,19 +487,31 @@ rpki_log_packet(struct rpki_cache *cache, const struct pdu_header *pdu, const en
   case ERROR:
   {
     const struct pdu_error *err = (void *) pdu;
-    SAVE(bsnprintf(detail, sizeof(detail), "(%s", str_pdu_error_type[err->error_code]));
+    SAVE(bsnprintf(detail, sizeof(detail), "(%s", str_pdu_error_type(err->error_code)));
+
+    if (err->len_enc_pdu > err->len - 16)
+    {
+      SAVE(bsnprintf(detail + strlen(detail), sizeof(detail) - strlen(detail), ", malformed encapsulated PDU length)"));
+      break;
+    }
 
     /* Optional description of error */
-    const u32 len_err_txt = *((u32 *) (err->rest + err->len_enc_pdu));
+    const u32 len_err_txt = get_u32he(err->rest + err->len_enc_pdu);
     if (len_err_txt > 0)
     {
       size_t expected_len = err->len_enc_pdu + len_err_txt + 16;
       if (expected_len == err->len)
       {
-        char txt[len_err_txt + 1];
-        char *pdu_txt = (char *) err->rest + err->len_enc_pdu + 4;
-        bsnprintf(txt, sizeof(txt), "%s", pdu_txt); /* it's ensured that txt is ended with a null byte */
-        SAVE(bsnprintf(detail + strlen(detail), sizeof(detail) - strlen(detail), ": '%s'", txt));
+       char *msg = tmp_alloc(len_err_txt + 1);
+       memcpy(msg, err->rest + err->len_enc_pdu + 4, len_err_txt);
+       msg[len_err_txt] = 0;
+
+       /* Some elementary cleanup */
+       for (int i = 0; i < (int) len_err_txt; i++)
+         if (msg[i] < ' ')
+           msg[i] = ' ';
+
+        SAVE(bsnprintf(detail + strlen(detail), sizeof(detail) - strlen(detail), ": '%s'", msg));
       }
       else
       {
@@ -499,11 +523,8 @@ rpki_log_packet(struct rpki_cache *cache, const struct pdu_header *pdu, const en
     if (err->len_enc_pdu)
     {
       SAVE(bsnprintf(detail + strlen(detail), sizeof(detail) - strlen(detail), ", %s packet:", str_pdu_type(((struct pdu_header *) err->rest)->type)));
-      if (err->rest + err->len_enc_pdu <= (byte *)err + err->len)
-      {
-       for (const byte *c = err->rest; c != err->rest + err->len_enc_pdu; c++)
-         SAVE(bsnprintf(detail + strlen(detail), sizeof(detail) - strlen(detail), " %02X", *c));
-      }
+      for (const byte *c = err->rest; c != err->rest + err->len_enc_pdu; c++)
+       SAVE(bsnprintf(detail + strlen(detail), sizeof(detail) - strlen(detail), " %02X", *c));
     }
 
     SAVE(bsnprintf(detail + strlen(detail), sizeof(detail) - strlen(detail), ")"));
@@ -1180,7 +1201,7 @@ rpki_send_error_pdu(struct rpki_cache *cache, const enum pdu_error_type error_co
   if (err_pdu_len > 0)
     memcpy(e->rest, erroneous_pdu, err_pdu_len);
 
-  *((u32 *)(e->rest + err_pdu_len)) = msg_len;
+  put_u32he(e->rest + err_pdu_len, msg_len);
   if (msg_len > 0)
     memcpy(e->rest + err_pdu_len + 4, msg, msg_len);