]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
pe-binary: fix missing le16toh() on NumberOfSections in pe_hash/uki_hash
authorOblivionsage <cookieandcream560@gmail.com>
Tue, 17 Feb 2026 18:39:05 +0000 (19:39 +0100)
committerLuca Boccassi <luca.boccassi@gmail.com>
Fri, 27 Feb 2026 20:05:57 +0000 (20:05 +0000)
pe_hash() and uki_hash() pass pe_header->pe.NumberOfSections directly
to typesafe_qsort() and FOREACH_ARRAY() without le16toh(). On
big-endian (s390x), NumberOfSections=3 gets read as 0x0300 (768),
while pe_load_sections() correctly converts it and only allocates 3
sections. This makes qsort process 768 elements on a 3-element
buffer, causing a heap-buffer-overflow (confirmed with ASAN on
native s390x).

Wrap all three raw usages with le16toh() to match pe_load_sections().

(cherry picked from commit 02cab70acf5ca67e838d0d34860baacbf9fc3b6c)
(cherry picked from commit 79ecdd1e9811e190d0a19f927d2670e52360f375)
(cherry picked from commit f9c00b1950e8b6e738b3bd8ae20bc55987fc2a6f)

src/shared/pe-binary.c

index c9bb09c77a40ac988ec71dcdfda373f21a98f5e1..0e15846e8abc69387ae783c4b786279f2831ae00 100644 (file)
@@ -241,7 +241,7 @@ int pe_read_section_data_by_name(
 
         assert(fd >= 0);
         assert(pe_header);
-        assert(sections || pe_header->pe.NumberOfSections == 0);
+        assert(sections || le16toh(pe_header->pe.NumberOfSections) == 0);
         assert(name);
 
         section = pe_header_find_section(pe_header, sections, name);
@@ -407,9 +407,9 @@ int pe_hash(int fd,
                 return r;
 
         /* Sort by location in file */
-        typesafe_qsort(sections, pe_header->pe.NumberOfSections, section_offset_cmp);
+        typesafe_qsort(sections, le16toh(pe_header->pe.NumberOfSections), section_offset_cmp);
 
-        FOREACH_ARRAY(section, sections, pe_header->pe.NumberOfSections) {
+        FOREACH_ARRAY(section, sections, le16toh(pe_header->pe.NumberOfSections)) {
                 r = hash_file(fd, mdctx, section->PointerToRawData, section->SizeOfRawData);
                 if (r < 0)
                         return r;
@@ -541,7 +541,7 @@ int uki_hash(int fd,
         if (hsz < 0)
                 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to get hash size.");
 
-        FOREACH_ARRAY(section, sections, pe_header->pe.NumberOfSections) {
+        FOREACH_ARRAY(section, sections, le16toh(pe_header->pe.NumberOfSections)) {
                 _cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX *mdctx = NULL;
                 _cleanup_free_ char *n = NULL;
                 ssize_t i;