From: Ondrej Zajicek Date: Tue, 3 Dec 2024 00:19:44 +0000 (+0100) Subject: RPKI: Fix several errors in handling of Error PDU X-Git-Tag: v2.16~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ef4561185055cb66dd2d141623bdbcbb306a5403;p=thirdparty%2Fbird.git RPKI: Fix several errors in handling of Error PDU 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 --- diff --git a/lib/unaligned.h b/lib/unaligned.h index dfe0906f8..0ea4dfb7e 100644 --- a/lib/unaligned.h +++ b/lib/unaligned.h @@ -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 diff --git a/proto/rpki/packets.c b/proto/rpki/packets.c index 3300c9c9a..bbef16ef5 100644 --- a/proto/rpki/packets.c +++ b/proto/rpki/packets.c @@ -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);