Support installing Magisk on vendor_boot

Close #9238, fix #8835
This commit is contained in:
topjohnwu
2025-09-28 01:10:11 -07:00
parent ed206c6480
commit 742913ebcb
8 changed files with 97 additions and 61 deletions

View File

@@ -47,6 +47,8 @@ object Info {
private set private set
var slot = "" var slot = ""
private set private set
var isVendorBoot = false
private set
@JvmField val isZygiskEnabled = System.getenv("ZYGISK_ENABLED") == "1" @JvmField val isZygiskEnabled = System.getenv("ZYGISK_ENABLED") == "1"
@JvmStatic val isFDE get() = crypto == "block" @JvmStatic val isFDE get() = crypto == "block"
@JvmStatic var ramdisk = false @JvmStatic var ramdisk = false
@@ -113,6 +115,7 @@ object Info {
crypto = getVar("CRYPTOTYPE") crypto = getVar("CRYPTOTYPE")
slot = getVar("SLOT") slot = getVar("SLOT")
legacySAR = getBool("LEGACYSAR") legacySAR = getBool("LEGACYSAR")
isVendorBoot = getBool("VENDORBOOT")
// Default presets // Default presets
Config.recovery = getBool("RECOVERYMODE") Config.recovery = getBool("RECOVERYMODE")

View File

@@ -81,10 +81,12 @@ abstract class MagiskInstallImpl protected constructor(
} }
private fun findImage(slot: String): Boolean { private fun findImage(slot: String): Boolean {
val bootPath = ( val cmd =
"(RECOVERYMODE=${Config.recovery} " + "RECOVERYMODE=${Config.recovery} " +
"SLOT=$slot find_boot_image; " + "VENDORBOOT=${Info.isVendorBoot} " +
"echo \$BOOTIMAGE)").fsh() "SLOT=$slot " +
"find_boot_image; echo \$BOOTIMAGE"
val bootPath = ("($cmd)").fsh()
if (bootPath.isEmpty()) { if (bootPath.isEmpty()) {
console.add("! Unable to detect target image") console.add("! Unable to detect target image")
return false return false

View File

@@ -15,6 +15,11 @@ using namespace std;
#define SHA256_DIGEST_SIZE 32 #define SHA256_DIGEST_SIZE 32
#define SHA_DIGEST_SIZE 20 #define SHA_DIGEST_SIZE 20
#define RETURN_OK 0
#define RETURN_ERROR 1
#define RETURN_CHROMEOS 2
#define RETURN_VENDOR 3
static void decompress(FileFormat type, int fd, const void *in, size_t size) { static void decompress(FileFormat type, int fd, const void *in, size_t size) {
decompress_bytes(type, byte_view { in, size }, fd); decompress_bytes(type, byte_view { in, size }, fd);
} }
@@ -217,7 +222,7 @@ map(image), k_fmt(FileFormat::UNKNOWN), r_fmt(FileFormat::UNKNOWN), e_fmt(FileFo
break; break;
} }
} }
exit(1); exit(RETURN_ERROR);
} }
boot_img::~boot_img() { boot_img::~boot_img() {
@@ -264,7 +269,6 @@ struct [[gnu::packed]] fdt_header {
fdt32_t size_dt_struct; /* size of the structure block */ fdt32_t size_dt_struct; /* size of the structure block */
}; };
static int find_dtb_offset(const uint8_t *buf, unsigned sz) { static int find_dtb_offset(const uint8_t *buf, unsigned sz) {
const uint8_t * const end = buf + sz; const uint8_t * const end = buf + sz;
@@ -403,6 +407,23 @@ static const char *vendor_ramdisk_type(int type) {
} }
} }
std::span<const vendor_ramdisk_table_entry_v4> boot_img::vendor_ramdisk_tbl() const {
if (hdr->vendor_ramdisk_table_size() == 0) {
return {};
}
// v4 vendor boot contains multiple ramdisks
using table_entry = const vendor_ramdisk_table_entry_v4;
if (hdr->vendor_ramdisk_table_entry_size() != sizeof(table_entry)) {
fprintf(stderr,
"! Invalid vendor image: vendor_ramdisk_table_entry_size != %zu\n",
sizeof(table_entry));
exit(RETURN_ERROR);
}
return span(reinterpret_cast<table_entry *>(vendor_ramdisk_table), hdr->vendor_ramdisk_table_entry_num());
}
#define assert_off() \ #define assert_off() \
if ((base_addr + off) > (map.data() + map_end)) { \ if ((base_addr + off) > (map.data() + map_end)) { \
fprintf(stderr, "Corrupted boot image!\n"); \ fprintf(stderr, "Corrupted boot image!\n"); \
@@ -421,6 +442,7 @@ bool boot_img::parse_image(const uint8_t *p, FileFormat type) {
fprintf(stderr, "Invalid boot image header!\n"); fprintf(stderr, "Invalid boot image header!\n");
return false; return false;
} }
this->hdr = hdr;
if (const char *id = hdr->id()) { if (const char *id = hdr->id()) {
for (int i = SHA_DIGEST_SIZE + 4; i < SHA256_DIGEST_SIZE; ++i) { for (int i = SHA_DIGEST_SIZE + 4; i < SHA256_DIGEST_SIZE; ++i) {
@@ -468,9 +490,9 @@ bool boot_img::parse_image(const uint8_t *p, FileFormat type) {
k_fmt = check_fmt_lg(kernel, hdr->kernel_size()); k_fmt = check_fmt_lg(kernel, hdr->kernel_size());
} }
if (k_fmt == FileFormat::ZIMAGE) { if (k_fmt == FileFormat::ZIMAGE) {
z_hdr = reinterpret_cast<const zimage_hdr *>(kernel); z_info.hdr = reinterpret_cast<const zimage_hdr *>(kernel);
const uint8_t* found_pos = 0; const uint8_t* found_pos = nullptr;
for (const uint8_t* search_pos = kernel + 0x28; search_pos < kernel + hdr->kernel_size(); search_pos++) { for (const uint8_t* search_pos = kernel + 0x28; search_pos < kernel + hdr->kernel_size(); search_pos++) {
// ^^^^^^ +0x28 to search after zimage header and magic // ^^^^^^ +0x28 to search after zimage header and magic
@@ -480,12 +502,12 @@ bool boot_img::parse_image(const uint8_t *p, FileFormat type) {
} }
} }
if (found_pos != 0) { if (found_pos != nullptr) {
fprintf(stderr, "ZIMAGE_KERNEL\n"); fprintf(stderr, "ZIMAGE_KERNEL\n");
z_info.hdr_sz = (const uint8_t *) found_pos - kernel; z_info.hdr_sz = found_pos - kernel;
// Find end of piggy // Find end of piggy
uint32_t zImage_size = z_hdr->end - z_hdr->start; uint32_t zImage_size = z_info.hdr->end - z_info.hdr->start;
uint32_t piggy_end = zImage_size; uint32_t piggy_end = zImage_size;
uint32_t offsets[16]; uint32_t offsets[16];
memcpy(offsets, kernel + zImage_size - sizeof(offsets), sizeof(offsets)); memcpy(offsets, kernel + zImage_size - sizeof(offsets), sizeof(offsets));
@@ -513,19 +535,7 @@ bool boot_img::parse_image(const uint8_t *p, FileFormat type) {
} }
if (auto size = hdr->ramdisk_size()) { if (auto size = hdr->ramdisk_size()) {
if (hdr->vendor_ramdisk_table_size()) { if (hdr->vendor_ramdisk_table_size()) {
// v4 vendor boot contains multiple ramdisks for (auto &it : vendor_ramdisk_tbl()) {
using table_entry = const vendor_ramdisk_table_entry_v4;
if (hdr->vendor_ramdisk_table_entry_size() != sizeof(table_entry)) {
fprintf(stderr,
"! Invalid vendor image: vendor_ramdisk_table_entry_size != %zu\n",
sizeof(table_entry));
exit(1);
}
span<table_entry> table(
reinterpret_cast<table_entry *>(vendor_ramdisk_table),
hdr->vendor_ramdisk_table_entry_num());
for (auto &it : table) {
FileFormat fmt = check_fmt_lg(ramdisk + it.ramdisk_offset, it.ramdisk_size); FileFormat fmt = check_fmt_lg(ramdisk + it.ramdisk_offset, it.ramdisk_size);
fprintf(stderr, fprintf(stderr,
"%-*s name=[%s] type=[%s] size=[%u] fmt=[%s]\n", PADDING, "VND_RAMDISK", "%-*s name=[%s] type=[%s] size=[%u] fmt=[%s]\n", PADDING, "VND_RAMDISK",
@@ -579,7 +589,6 @@ bool boot_img::parse_image(const uint8_t *p, FileFormat type) {
} }
} }
this->hdr = hdr;
return true; return true;
} }
@@ -680,7 +689,9 @@ int unpack(Utf8CStr image, bool skip_decomp, bool hdr) {
// Dump bootconfig // Dump bootconfig
dump(boot.bootconfig, boot.hdr->bootconfig_size(), BOOTCONFIG_FILE); dump(boot.bootconfig, boot.hdr->bootconfig_size(), BOOTCONFIG_FILE);
return boot.flags[CHROMEOS_FLAG] ? 2 : 0; if (boot.flags[CHROMEOS_FLAG]) return RETURN_CHROMEOS;
if (boot.hdr->is_vendor()) return RETURN_VENDOR;
return RETURN_OK;
} }
#define file_align_with(page_size) \ #define file_align_with(page_size) \
@@ -744,7 +755,7 @@ void repack(Utf8CStr src_img, Utf8CStr out_img, bool skip_comp) {
} }
if (boot.flags[ZIMAGE_KERNEL]) { if (boot.flags[ZIMAGE_KERNEL]) {
// Copy zImage headers // Copy zImage headers
xwrite(fd, boot.z_hdr, boot.z_info.hdr_sz); xwrite(fd, boot.z_info.hdr, boot.z_info.hdr_sz);
} }
if (access(KERNEL_FILE, R_OK) == 0) { if (access(KERNEL_FILE, R_OK) == 0) {
mmap_data m(KERNEL_FILE); mmap_data m(KERNEL_FILE);
@@ -794,15 +805,11 @@ void repack(Utf8CStr src_img, Utf8CStr out_img, bool skip_comp) {
xwrite(fd, boot.r_hdr, sizeof(mtk_hdr)); xwrite(fd, boot.r_hdr, sizeof(mtk_hdr));
} }
using table_entry = vendor_ramdisk_table_entry_v4; vector<vendor_ramdisk_table_entry_v4> ramdisk_table;
vector<table_entry> ramdisk_table;
if (boot.hdr->vendor_ramdisk_table_size()) { if (boot.hdr->vendor_ramdisk_table_size()) {
// Create a copy so we can modify it // Create a copy so we can modify it
auto entry_start = reinterpret_cast<const table_entry *>(boot.vendor_ramdisk_table); ramdisk_table.assign_range(boot.vendor_ramdisk_tbl());
ramdisk_table.insert(
ramdisk_table.begin(),
entry_start, entry_start + boot.hdr->vendor_ramdisk_table_entry_num());
owned_fd dirfd = xopen(VND_RAMDISK_DIR, O_RDONLY | O_CLOEXEC); owned_fd dirfd = xopen(VND_RAMDISK_DIR, O_RDONLY | O_CLOEXEC);
uint32_t ramdisk_offset = 0; uint32_t ramdisk_offset = 0;
@@ -885,7 +892,7 @@ void repack(Utf8CStr src_img, Utf8CStr out_img, bool skip_comp) {
// vendor ramdisk table // vendor ramdisk table
if (!ramdisk_table.empty()) { if (!ramdisk_table.empty()) {
xwrite(fd, ramdisk_table.data(), sizeof(table_entry) * ramdisk_table.size()); xwrite(fd, ramdisk_table.data(), sizeof(*ramdisk_table.data()) * ramdisk_table.size());
file_align(); file_align();
} }

View File

@@ -437,7 +437,7 @@ private:
#define __impl_cls(name, hdr) \ #define __impl_cls(name, hdr) \
protected: name() = default; \ protected: name() = default; \
public: \ public: \
name(const void *ptr) { \ explicit name(const void *ptr) { \
raw = malloc(sizeof(hdr)); \ raw = malloc(sizeof(hdr)); \
memcpy(raw, ptr, sizeof(hdr)); \ memcpy(raw, ptr, sizeof(hdr)); \
} \ } \
@@ -651,10 +651,10 @@ struct boot_img {
// +---------------+ // +---------------+
// | z_info.tail | z_info.tail.sz() // | z_info.tail | z_info.tail.sz()
// +---------------+ // +---------------+
const zimage_hdr *z_hdr = nullptr;
struct { struct {
uint32_t hdr_sz; const zimage_hdr *hdr = nullptr;
byte_view tail; uint32_t hdr_sz = 0;
byte_view tail{};
} z_info; } z_info;
// AVB structs // AVB structs
@@ -675,14 +675,12 @@ struct boot_img {
// dtb embedded in kernel // dtb embedded in kernel
byte_view kernel_dtb; byte_view kernel_dtb;
// Blocks defined in header but we do not care explicit boot_img(const char *);
byte_view ignore;
boot_img(const char *);
~boot_img(); ~boot_img();
bool parse_image(const uint8_t *addr, FileFormat type); bool parse_image(const uint8_t *addr, FileFormat type);
std::pair<const uint8_t *, dyn_img_hdr *> create_hdr(const uint8_t *addr, FileFormat type); std::pair<const uint8_t *, dyn_img_hdr *> create_hdr(const uint8_t *addr, FileFormat type);
std::span<const vendor_ramdisk_table_entry_v4> vendor_ramdisk_tbl() const;
// Rust FFI // Rust FFI
static std::unique_ptr<boot_img> create(Utf8CStr name) { return std::make_unique<boot_img>(name.c_str()); } static std::unique_ptr<boot_img> create(Utf8CStr name) { return std::make_unique<boot_img>(name.c_str()); }

View File

@@ -25,7 +25,7 @@ use x509_cert::der::Any;
use x509_cert::der::asn1::{OctetString, PrintableString}; use x509_cert::der::asn1::{OctetString, PrintableString};
use x509_cert::spki::AlgorithmIdentifier; use x509_cert::spki::AlgorithmIdentifier;
use base::{LoggedResult, MappedFile, ResultExt, Utf8CStr, cstr, log_err}; use base::{LoggedResult, MappedFile, ResultExt, SilentLogExt, Utf8CStr, cstr, log_err};
use crate::ffi::BootImage; use crate::ffi::BootImage;
@@ -273,7 +273,7 @@ impl BootImage {
// Don't use BootSignature::from_der because tail might have trailing zeros // Don't use BootSignature::from_der because tail might have trailing zeros
let mut reader = SliceReader::new(tail)?; let mut reader = SliceReader::new(tail)?;
let mut sig = BootSignature::decode(&mut reader)?; let mut sig = BootSignature::decode(&mut reader).silent()?;
if let Some(s) = cert { if let Some(s) = cert {
let pem = MappedFile::open(s)?; let pem = MappedFile::open(s)?;
sig.certificate = Certificate::from_pem(pem)?; sig.certificate = Certificate::from_pem(pem)?;

View File

@@ -214,6 +214,7 @@ get_flags() {
PATCHVBMETAFLAG=true PATCHVBMETAFLAG=true
fi fi
[ -z $RECOVERYMODE ] && RECOVERYMODE=false [ -z $RECOVERYMODE ] && RECOVERYMODE=false
[ -z $VENDORBOOT ] && VENDORBOOT=false
} }
run_migrations() { return; } run_migrations() { return; }
@@ -243,6 +244,7 @@ app_init() {
printvar RECOVERYMODE printvar RECOVERYMODE
printvar KEEPVERITY printvar KEEPVERITY
printvar KEEPFORCEENCRYPT printvar KEEPFORCEENCRYPT
printvar VENDORBOOT
} }
export BOOTMODE=true export BOOTMODE=true

View File

@@ -86,54 +86,66 @@ chmod -R 755 .
######### #########
CHROMEOS=false CHROMEOS=false
VENDORBOOT=false
ui_print "- Unpacking boot image" ui_print "- Unpacking boot image"
./magiskboot unpack "$BOOTIMAGE" ./magiskboot unpack "$BOOTIMAGE"
case $? in case $? in
0 ) ;; 0 ) ;;
1 )
abort "! Unsupported/Unknown image format"
;;
2 ) 2 )
ui_print "- ChromeOS boot image detected" ui_print "- ChromeOS boot image detected"
CHROMEOS=true CHROMEOS=true
;; ;;
3 )
ui_print "- Vendor boot image detected"
VENDORBOOT=true
;;
* ) * )
abort "! Unable to unpack boot image" abort "! Unable to unpack boot image"
;; ;;
esac esac
################### #################
# Ramdisk Restores # Ramdisk Checks
################### #################
unset RAMDISK
for path in ramdisk.cpio vendor_ramdisk/init_boot.cpio vendor_ramdisk/ramdisk.cpio; do
if [ -e $path ]; then
RAMDISK=$path
break
fi
done
# Test patch status and do restore
ui_print "- Checking ramdisk status" ui_print "- Checking ramdisk status"
if [ -e ramdisk.cpio ]; then if [ -n "$RAMDISK" ]; then
./magiskboot cpio ramdisk.cpio test ./magiskboot cpio $RAMDISK test
STATUS=$? STATUS=$?
SKIP_BACKUP="" SKIP_BACKUP=""
else else
# Stock A only legacy SAR, or some Android 13 GKIs # No ramdisk found, create one from scratch
RAMDISK=ramdisk.cpio
# Could be stock A only legacy SAR, or some Android 13 GKIs
STATUS=0 STATUS=0
SKIP_BACKUP="#" SKIP_BACKUP="#"
fi fi
case $STATUS in case $STATUS in
0 ) 0 )
# Stock boot # Stock boot
ui_print "- Stock boot image detected" ui_print "- Stock boot image detected"
SHA1=$(./magiskboot sha1 "$BOOTIMAGE" 2>/dev/null) SHA1=$(./magiskboot sha1 "$BOOTIMAGE" 2>/dev/null)
cat $BOOTIMAGE > stock_boot.img cat $BOOTIMAGE > stock_boot.img
cp -af ramdisk.cpio ramdisk.cpio.orig 2>/dev/null cp -af $RAMDISK ramdisk.cpio.orig 2>/dev/null
;; ;;
1 ) 1 )
# Magisk patched # Magisk patched
ui_print "- Magisk patched boot image detected" ui_print "- Magisk patched boot image detected"
./magiskboot cpio ramdisk.cpio \ ./magiskboot cpio $RAMDISK \
"extract .backup/.magisk config.orig" \ "extract .backup/.magisk config.orig" \
"restore" "restore"
cp -af ramdisk.cpio ramdisk.cpio.orig cp -af $RAMDISK ramdisk.cpio.orig
rm -f stock_boot.img rm -f stock_boot.img
;; ;;
2 ) 2 )
@@ -170,13 +182,14 @@ $BOOTMODE && [ -z "$PREINITDEVICE" ] && PREINITDEVICE=$(./magisk --preinit-devic
echo "KEEPVERITY=$KEEPVERITY" > config echo "KEEPVERITY=$KEEPVERITY" > config
echo "KEEPFORCEENCRYPT=$KEEPFORCEENCRYPT" >> config echo "KEEPFORCEENCRYPT=$KEEPFORCEENCRYPT" >> config
echo "RECOVERYMODE=$RECOVERYMODE" >> config echo "RECOVERYMODE=$RECOVERYMODE" >> config
echo "VENDORBOOT=$VENDORBOOT" >> config
if [ -n "$PREINITDEVICE" ]; then if [ -n "$PREINITDEVICE" ]; then
ui_print "- Pre-init storage partition: $PREINITDEVICE" ui_print "- Pre-init storage partition: $PREINITDEVICE"
echo "PREINITDEVICE=$PREINITDEVICE" >> config echo "PREINITDEVICE=$PREINITDEVICE" >> config
fi fi
[ -n "$SHA1" ] && echo "SHA1=$SHA1" >> config [ -n "$SHA1" ] && echo "SHA1=$SHA1" >> config
./magiskboot cpio ramdisk.cpio \ ./magiskboot cpio $RAMDISK \
"add 0750 init magiskinit" \ "add 0750 init magiskinit" \
"mkdir 0750 overlay.d" \ "mkdir 0750 overlay.d" \
"mkdir 0750 overlay.d/sbin" \ "mkdir 0750 overlay.d/sbin" \

View File

@@ -325,7 +325,7 @@ mount_partitions() {
# After calling this method, the following variables will be set: # After calling this method, the following variables will be set:
# ISENCRYPTED, PATCHVBMETAFLAG, # ISENCRYPTED, PATCHVBMETAFLAG,
# KEEPVERITY, KEEPFORCEENCRYPT, RECOVERYMODE # KEEPVERITY, KEEPFORCEENCRYPT, RECOVERYMODE, VENDORBOOT
get_flags() { get_flags() {
if grep ' /data ' /proc/mounts | grep -q 'dm-'; then if grep ' /data ' /proc/mounts | grep -q 'dm-'; then
ISENCRYPTED=true ISENCRYPTED=true
@@ -348,6 +348,7 @@ get_flags() {
getvar KEEPVERITY getvar KEEPVERITY
getvar KEEPFORCEENCRYPT getvar KEEPFORCEENCRYPT
getvar RECOVERYMODE getvar RECOVERYMODE
getvar VENDORBOOT
if [ -z $KEEPVERITY ]; then if [ -z $KEEPVERITY ]; then
if $SYSTEM_AS_ROOT; then if $SYSTEM_AS_ROOT; then
KEEPVERITY=true KEEPVERITY=true
@@ -365,13 +366,23 @@ get_flags() {
fi fi
fi fi
[ -z $RECOVERYMODE ] && RECOVERYMODE=false [ -z $RECOVERYMODE ] && RECOVERYMODE=false
[ -z $VENDORBOOT ] && VENDORBOOT=false
} }
# Returns whether the device is GKI 13+
is_gt_gki_13() {
[ "$(uname -r | cut -d. -f1)" -ge 5 ] && uname -r | grep -Evq "android12-|^5\.4"
}
# Require RECOVERYMODE, VENDORBOOT, SLOT to be set.
# After calling this method, BOOTIMAGE will be set.
find_boot_image() { find_boot_image() {
BOOTIMAGE= BOOTIMAGE=
if $RECOVERYMODE; then if $VENDORBOOT; then
BOOTIMAGE="/dev/block/by-name/vendor_boot$SLOT"
elif $RECOVERYMODE; then
BOOTIMAGE=$(find_block "recovery$SLOT" "sos") BOOTIMAGE=$(find_block "recovery$SLOT" "sos")
elif [ -e "/dev/block/by-name/init_boot$SLOT" ] && [ "$(uname -r | cut -d. -f1)" -ge 5 ] && uname -r | grep -Evq "android12-|^5\.4"; then elif [ -e "/dev/block/by-name/init_boot$SLOT" ] && is_gt_gki_13; then
# init_boot is only used with GKI 13+. It is possible that some devices with init_boot # init_boot is only used with GKI 13+. It is possible that some devices with init_boot
# partition still uses Android 12 GKI or previous kernels, so we need to explicitly detect that scenario. # partition still uses Android 12 GKI or previous kernels, so we need to explicitly detect that scenario.
BOOTIMAGE="/dev/block/by-name/init_boot$SLOT" BOOTIMAGE="/dev/block/by-name/init_boot$SLOT"