pe-binary: only read the raw data of a section

pe_read_section_data() reads VirtualSize bytes starting at
PointerToRawData. When VirtualSize is larger than SizeOfRawData, because
the section ends with zero-initialized data, it returns the start of the
next section, or fails with EBADMSG at the end of the file. Read
MIN(VirtualSize, SizeOfRawData) bytes, like systemd-stub and uki_hash()
do.

(cherry picked from commit f219e7e790ec7b1064b71173ad697f48a5d71830)
This commit is contained in:
Daan De Meyer
2026-10-16 17:24:51 +01:00
committed by Luca Boccassi
parent 6f076ff729
commit 762840e4e0
2 changed files with 38 additions and 1 deletions
+4 -1
View File
@@ -251,7 +251,10 @@ int pe_read_section_data(
assert(fd >= 0);
assert(section);
size_t n = le32toh(section->VirtualSize);
/* SizeOfRawData includes padding up to the file alignment. VirtualSize is larger than
* SizeOfRawData when the section ends with zero-initialized data. The file does not contain
* that data. Reading VirtualSize bytes would return bytes of the next section instead. */
size_t n = MIN(le32toh(section->VirtualSize), le32toh(section->SizeOfRawData));
if (n > MIN(max_size, (size_t) SSIZE_MAX))
return -EBADMSG;
+34
View File
@@ -342,6 +342,40 @@ TEST(pe_load_sections_multi_one_past_eof) {
ASSERT_ERROR(load_headers_and_sections(fd, &dos, &pe, &sections), EBADMSG);
}
/* ======================================================================
* pe_read_section_data
* ====================================================================== */
/* The bytes after the SizeOfRawData bytes of .cmdline belong to .uname, so reading .cmdline must not
* return them. */
TEST(pe_read_section_data_reads_raw_data_only) {
size_t base = SECTION_TABLE_OFFSET + 2 * IMAGE_SECTION_HEADER_BYTES;
SectionSpec specs[2] = {
{ .name = ".cmdline", .virtual_size = 32, .size_of_raw_data = 16,
.pointer_to_raw_data = (uint32_t) base },
{ .name = ".uname", .virtual_size = 8, .size_of_raw_data = 16,
.pointer_to_raw_data = (uint32_t) (base + 16) },
};
static const char contents[] = "0123456789abcdefABCDEFGHIJKLMNOP";
_cleanup_close_ int fd = build_pe_file(specs, /* n_sections= */ 2, /* override_file_size= */ 0);
ASSERT_OK_EQ_ERRNO(pwrite(fd, contents, strlen(contents), base), (ssize_t) strlen(contents));
_cleanup_free_ PeHeader *pe = NULL;
_cleanup_free_ IMAGE_SECTION_HEADER *sections = NULL;
ASSERT_OK(pe_load_headers_and_sections(fd, &pe, &sections));
_cleanup_free_ void *data = NULL;
size_t size;
ASSERT_OK(pe_read_section_data(fd, sections + 0, SIZE_MAX, &data, &size));
ASSERT_EQ(size, 16U);
ASSERT_EQ(memcmp(data, "0123456789abcdef", size), 0);
data = mfree(data);
ASSERT_OK(pe_read_section_data(fd, sections + 1, SIZE_MAX, &data, &size));
ASSERT_EQ(size, 8U);
ASSERT_EQ(memcmp(data, "ABCDEFGH", size), 0);
}
/* ======================================================================
* uki_hash — zero-padding cap from PLAN §3.2
* ====================================================================== */