From: Tulio A M Mendes Date: Tue, 26 May 2026 04:55:18 +0000 (-0300) Subject: security: fix initrd TAR parser with size limits and checksum validation (C3) X-Git-Url: https://projects.tadryanom.me/?a=commitdiff_plain;h=a5b1542911c18b8801effe8ca6b2d0a6e38592f7;p=AdrOS.git security: fix initrd TAR parser with size limits and checksum validation (C3) --- diff --git a/src/drivers/initrd.c b/src/drivers/initrd.c index 0a3a8c5f..a6b93218 100644 --- a/src/drivers/initrd.c +++ b/src/drivers/initrd.c @@ -376,6 +376,12 @@ fs_node_t* initrd_init(uint32_t location, uint32_t size) { uint32_t comp_sz = (uint32_t)raw[8] | ((uint32_t)raw[9] << 8) | ((uint32_t)raw[10] << 16) | ((uint32_t)raw[11] << 24); + /* Validate LZ4 header and compressed data fit within initrd bounds */ + if (LZ4B_HDR_SIZE + comp_sz > size) { + kprintf("[INITRD] LZ4: compressed data exceeds initrd bounds\n"); + return NULL; + } + decomp_buf = initrd_alloc_pages(orig_sz); if (!decomp_buf) { kprintf("[INITRD] OOM decompressing LZ4 (%u bytes)\n", orig_sz); @@ -409,9 +415,12 @@ fs_node_t* initrd_init(uint32_t location, uint32_t size) { entries[root].parent = -1; const uint8_t* p = (const uint8_t*)(uintptr_t)location; + const uint8_t* end = p + size; /* End of initrd data */ int files = 0; while (1) { + /* Validate we have at least TAR_BLOCK bytes before checking zero block */ + if (p + TAR_BLOCK > end) break; if (tar_is_zero_block(p)) break; const tar_header_t* h = (const tar_header_t*)p; @@ -440,6 +449,30 @@ fs_node_t* initrd_init(uint32_t location, uint32_t size) { return NULL; } + /* Validate payload fits within initrd bounds */ + uint32_t adv = TAR_BLOCK + ((size + (TAR_BLOCK - 1)) & ~(TAR_BLOCK - 1)); + if (p + adv > end) { + kprintf("[INITRD] TAR: payload exceeds initrd bounds\n"); + return NULL; + } + + /* Validate TAR checksum (basic check - sum of header bytes should match checksum field) */ + uint32_t checksum = tar_parse_octal(h->chksum, sizeof(h->chksum)); + uint32_t calc_checksum = 0; + const uint8_t* hp = (const uint8_t*)h; + for (int i = 0; i < 512; i++) { + if (i >= 148 && i < 156) { + /* Skip checksum field itself (treat as spaces) */ + calc_checksum += ' '; + } else { + calc_checksum += hp[i]; + } + } + if (checksum != calc_checksum) { + kprintf("[INITRD] TAR: checksum mismatch (header=%u, calc=%u)\n", checksum, calc_checksum); + return NULL; + } + // Normalize: strip leading './' if (name[0] == '.' && name[1] == '/') { size_t l = strlen(name); @@ -477,7 +510,6 @@ fs_node_t* initrd_init(uint32_t location, uint32_t size) { } } - uint32_t adv = TAR_BLOCK + ((size + (TAR_BLOCK - 1)) & ~(TAR_BLOCK - 1)); p += adv; }