android_device_peter_gsi/init/quirks/soc/mtk_trustkernel.cpp
Peter Cai e1f3a82a4f gsi: init: Support reading OS version and SPL from vbmeta
This allows installing a non-stock GSI kernel without also breaking
keymaster / keymint.
2025-06-07 17:00:47 -04:00

113 lines
3.9 KiB
C++

#include "../../quirks.h"
#include <android-base/properties.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <cstdlib>
#include <filesystem>
#include <map>
#include <optional>
#include <string>
#include <utility>
using namespace std;
map<int, string> api_to_version{
{30, "11"}, {31, "12"}, {32, "12L"},
{33, "13"}, {34, "14"}, {35, "15"},
};
optional<pair<string, string>> try_get_spl(string part_name, string os_version_prop, string spl_prop) {
string boot_part = "/dev/block/by-name/" + part_name + android::base::GetProperty("ro.boot.slot_suffix", "");
// Read from AVB footer, https://github.com/TrebleDroid/device_phh_treble/blob/android-13.0/fixSPL/getSPL.c
// First read into memory
int fd = open(boot_part.c_str(), O_RDONLY);
off_t size = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
char *buf = (char *) malloc(size);
read(fd, buf, size);
// Search for AVB footer property directly in the binary
char* p = (char *) memmem(buf, size, os_version_prop.c_str(), os_version_prop.length() + 1);
if (p == nullptr)
return nullopt;
p += os_version_prop.length() + 1;
string os_version(p);
p = (char *) memmem(buf, size, spl_prop.c_str(), spl_prop.length() + 1);
if (p == nullptr)
return nullopt;
p += spl_prop.length() + 1;
string spl(p);
return make_pair(os_version, spl);
}
optional<pair<string, string>> get_spl() {
// Read init_boot SPL and version from vbmeta
// Some MTK devices's "root of trust" is boot, but we sometimes can't access boot
// VBMETA does not contain info about boot either; the next best thing is init_boot
auto res = try_get_spl("vbmeta", "com.android.build.init_boot.os_version", "com.android.build.init_boot.security_patch");
if (res) {
return res;
}
// If init_boot doesn't exist, use the system partition's info from vbmeta
// Note that this might not be accepted on some MTK devices
res = try_get_spl("vbmeta", "com.android.build.system.os_version", "com.android.build.system.security_patch");
if (res) {
return res;
}
// Try reading OS version and SPL from boot as a final fallback
return try_get_spl("boot", "com.android.build.boot.os_version", "com.android.build.boot.security_patch");
}
class MtkTkQuirk : DeviceQuirk {
public:
bool ShouldRun() {
return filesystem::exists("/proc/tkcore/tkcore_log");
}
void Run() {
android::base::SetProperty("debug.phh.props.ice.trustkernel", "keymaster");
android::base::SetProperty("debug.phh.props.teed", "keymaster");
android::base::SetProperty("ro.keymaster.brn", "Android");
android::base::SetProperty("ro.keymaster.mod", "AOSP on ARM64");
string release = android::base::GetProperty("ro.vendor.build.version.release", "11");
string spl = android::base::GetProperty("ro.vendor.build.version.security_patch", "2023-01-05");
// Try reading version and SPL from vbmeta or boot
auto res = get_spl();
if (res) {
release = res->first;
spl = res->second;
}
// With GRF, release version from vendor or boot may not be what we need
// Because the actual first release version might not be the vendor's API level
int first_api_level = android::base::GetIntProperty("ro.product.first_api_level", 30);
if (api_to_version.count(first_api_level) > 0) {
string release_from_first_api = api_to_version[first_api_level];
if (stoi(release_from_first_api) >= stoi(release)) {
release = release_from_first_api;
}
}
android::base::SetProperty("ro.keymaster.xxx.release", release);
android::base::SetProperty("ro.keymaster.xxx.security_patch", spl);
android::base::SetProperty("ctl.restart", "teed");
}
};
LOAD_QUIRK(MtkTkQuirk)