Skip to content

Fix misaligned uint32_t load of dex map_list.size - #2249

Merged
plusvic merged 2 commits into
VirusTotal:masterfrom
Rakesh717:fix/dex-map-list-misaligned-read
Oct 15, 2026
Merged

plusvic merged 2 commits into
VirusTotal:masterfrom
Rakesh717:fix/dex-map-list-misaligned-read

Conversation

@Rakesh717

@Rakesh717 Rakesh717 commented Oct 3, 2026 •

Copy link
Copy Markdown

The map list size was read by casting dex->data + map_offset to uint32_t* and dereferencing, but map_offset comes straight from the DEX header and is never alignment checked, so any file whose map_offset is not a multiple of 4 is undefined behavior. Found with an ASan+UBSan build fuzzing the dex module over tests/oss-fuzz/dex_fuzzer_corpus; UBSan reports the load at dex.c:1163 and 1165, and the loop bound at 1171 reads the same pointer:

libyara/modules/dex/dex.c:1163:5: runtime error: load of misaligned address
0x000100fd0005 for type 'uint32_t', which requires 4 byte alignment

A 160-byte DEX with map_offset = 5 reproduces it deterministically:

import struct
buf = bytearray(160)
buf[0:8] = b'dex\n035\x00'
buf[32:36] = struct.pack('<I', 160)          # file_size
buf[36:40] = struct.pack('<I', 112)          # header_size
buf[40:44] = struct.pack('<I', 0x12345678)   # endian_tag
buf[52:56] = struct.pack('<I', 5)            # map_offset: odd, misaligned
open('misaligned.dex', 'wb').write(bytes(buf))
echo 'import "dex" rule t { condition: dex.map_list.size }' > r.yar
./yara -w r.yar misaligned.dex    # UBSan fires before the patch, silent after

The size is now read through memcpy into a local with yr_le32toh applied once, which also collapses the repeated yr_le32toh(*map_list_size) in the loop bound. This is the only bare (uint32_t*) cast-deref in the module; every other structure access goes through the #pragma pack(1) types in yara/dex.h, whose member loads tolerate any alignment. Same bytes, same endian conversion, same fits_in_dex bounds checks, so no behavior change: the reproducer is UBSan-silent after the fix and every file in tests/oss-fuzz/dex_fuzzer_corpus still parses.

map_offset comes straight from the DEX file and is never alignment
checked, but the map list size was read by casting dex->data +
map_offset to uint32_t* and dereferencing. Any file whose map_offset is
not a multiple of 4 is undefined behavior. UBSan reports:

  libyara/modules/dex/dex.c:1163:5: runtime error: load of misaligned
  address 0x... for type 'uint32_t', which requires 4 byte alignment

Read the size through memcpy instead. This is the only bare
(uint32_t*) cast-deref in the module; every other structure access goes
through the pragma pack(1) types, whose member loads tolerate any
alignment. No behavior change: same bytes, same yr_le32toh conversion,
same bounds checks.
@google-cla

google-cla Bot commented Oct 3, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@Rakesh717

Copy link
Copy Markdown
Author

@google-cla bot check

@plusvic
plusvic merged commit ce129f2 into VirusTotal:master Oct 15, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants