Previously, decompress_bytes dropped the LoggedResult from decoding,
returning void. In bootimg.cpp, unpack and split_image_dtb never checked
whether decompression succeeded, leaving empty 0-byte output files and
returning RETURN_OK (0).
Return a boolean status from decompress_bytes and check it during unpack
and split_image_dtb. On decompression failure, remove any incomplete
output files and return RETURN_ERROR (1).
Assisted-by: Gemini 3.8 Flash
When locating the compressed piggy payload in a zImage, check only
formats where fmt.is_compressed() to avoid false positives on container
or header formats (such as DTB or Android boot magic).
Additionally, prioritize 4-byte aligned offsets since ARM kernel linker
scripts align .piggydata to 4 bytes, falling back to an unaligned scan
only if no candidate is found.
Assisted-by: Gemini 3.8 Flash
XZ decompressor stubs in 32-bit ARM Linux zImage (lib/decompress_unxz.c)
include the HEADER_MAGIC string literal "\3757zXZ" in .rodata, which
appears before the compressed payload. check_fmt previously matched
only the first 5 bytes, falsely identifying the .rodata string literal
as an XZ payload.
Validate the 12-byte XZ stream header by verifying the 6-byte magic,
stream flags, and IEEE 802.3 CRC32 of the stream flags. In addition,
harden GZIP, BZIP2, and LZOP checks with stricter header validation
to prevent false positives when scanning raw binaries.
Assisted-by: Gemini 3.8 Flash
When a UID makes a root request for the first time, no row exists in
the policies table. Previously, RootSettings derived Default, which
initialized log and notify to false. As a result, connect_app() skipped
calling app_log() or app_notify() immediately after user approval on
the initial su request.
Explicitly implement Default for RootSettings with log and notify set
to true by default.
Assisted-by: Gemini 3.7 Flash
Meta Quest (Horizon OS) does not start the zygote the normal way: ro.zygote=
zygote64_stub32 launches /system/bin/stub_zygote, which forks a separate
app_process64 zygote PER security partition (system/trusted vs untrusted-app),
driven by hzos_security_zygote_partitioning_policy. The untrusted-app partition
zygote -- the one that forks 3rd-party apps and the Magisk manager -- is spawned
LAZILY, after boot-complete.
magiskd sets ro.dalvik.vm.native.bridge=libzygisk.so during boot but clears it
again at boot-complete (ZygiskState::reset). On a normal device every zygote has
already started by then, so clearing it is harmless. On Quest the untrusted-app
partition zygote reads the (now cleared) property when it finally execve's
app_process64, never loads libzygisk.so, so 3rd-party apps + the Magisk manager
are never injected -> "Zygisk: N/A".
Fix (daemon.rs): on the boot-complete reset(restore=true) path, reset the crash
counter but KEEP native.bridge set (set_prop) instead of clearing it
(restore_prop); only the >3-crash rollback path still clears. The lazily-spawned
partition zygotes then load the loader when they start.
Also (hook.cpp), robustness fixes the loader needs on this device:
- Wrap hook_zygote_jni()'s JNI locals in PushLocalFrame(64)/PopLocalFrame so
leaking locals can't trip ART's "non-empty local reference table" abort, and
bail if GetEnv returns no env.
- Make the strdup(ZygoteInit) trigger a substring match + add an idempotency
guard so the zygote hooks install exactly once per process.
Verified on Quest 3 (Android 14): system_server + every app fork is intercepted
and LSPosed loads end-to-end.
Support dynamic zImage piggy payload sizes during repacking by updating
the zImage decompressor stub headers, symbol tables, and GOT entries.
Previously, magiskboot padded repacked zImage files to preserve the
exact original file size. For non-gzip compressed zImages (such as XZ),
repacking with a different payload size broke stub symbol resolution
and resulted in ununpackable or unbootable images.
Key changes:
- Encapsulate zImage parsing and patching in a dedicated struct ZImage
in Rust with CXX FFI, new_head, and new_tail methods.
- Locate piggy_end using table references or GOT table entries bounded
by LC0.
- Relocate LC0 table entries, LC1 table, and GOT table entries with
4-byte padding/alignment when payload size changes.
- Relocate R_ARM_GOTPC PC-relative literal pools in decompressor .text.
- Append uncompressed size for non-gzip algorithms per size_append.
- Remove zopfli compression support across magiskboot as dynamic zImage
piggy sizing supersedes the need for exact size matching.
Fix#9880
Assisted-by: Gemini 3.7 Flash
Port find_dtb_offset from C++ to Rust in dtb.rs, using the fdt crate
for header parsing and root node validation.
Key changes:
- Upgrade fdt crate to 0.2.0-alpha2 and adapt dtb.rs to updated APIs.
- Implement find_dtb_offset using Fdt::new_unaligned_fallible.
- Define MIN_NON_EMPTY_DTB_SIZE (0x48) per Linux kernel ARM zImage
specification to ignore empty or false positive DTB headers.
- Expose find_dtb_offset to C++ via CXX bridge and clean up legacy
structs and declarations.
Assisted-by: Gemini 3.7 Flash
magiskboot: Lower the compression presets for XZ & LZMA
The compression routine always uses the maximum compression preset for all formats.
This is problematic with XZ and LZMA because they use far more memory than the other formats, while just providing a very marginal advantage in the resulting file size.
The compression preset was changed from 9 to 6, which is often the default value and provides more than enough compression.
Tested on Samsung Galaxy Fame (512MB RAM, perfect for this).
b55f597c ("Skip loading magisk in charger mode") aborts when
androidboot.mode=charger, but the check sits after the force_normal_boot
branch. Devices that set androidboot.force_normal_boot=1 during off-mode
charging (e.g. some Motorola models) take force_normal_boot -> first_stage()
and never reach the charger check, so Magisk still loads in charger mode and
bumps the never-reset bootloop counter until safe mode trips.
Move the charger check ahead of skip_initramfs/force_normal_boot so charger
boots abort regardless, matching AOSP treating charger mode first.
Fixes#9967.
Address clippy warnings including collapsible match statements in
bootstages, daemon, su daemon, and db modules, as well as iterator
loops in files.rs.
Assisted-by: Gemini 3.6 Flash
Update extract_token to only split hyphens when preceding a valid
hex xperm. Revert parse_xperm and parse_xperms to pure token-based
AST parsing without inspecting ID strings.
Assisted-by: Gemini 3.6 Flash
* Use major number check to filter out device-mapper devices while preserving virtio-blk compatibility.
* Introduce `klogdump` partition support for Smartisan devices as a valid preinit target.
- Old behavior: Switching to a non-zero UID was implicitly interpreted as a request to drop capabilities, thereby preventing subsequent reacquisition via `su`.
- New behavior: Switching to a non-zero UID now requires the `--drop-cap` argument to explicitly prevent the reacquisition of capabilities.