From 1ad46e69ec239e65cd268ab43971ea3662b3d1be Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Thu, 11 Jun 2026 18:15:57 +0000 Subject: [PATCH 1/2] init: add disable_hardened_malloc service option --- init/service.cpp | 21 +++++++++++++++++++-- init/service.h | 2 ++ init/service_parser.cpp | 6 ++++++ init/service_parser.h | 1 + 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/init/service.cpp b/init/service.cpp index c255704beee6..9d5b427f71fa 100644 --- a/init/service.cpp +++ b/init/service.cpp @@ -114,7 +114,8 @@ static Result ComputeContextFromExecutable(const std::string& servi return computed_context; } -static bool ExpandArgsAndExecv(const std::vector& args, bool sigstop) { +static bool ExpandArgsAndExecv(const std::vector& args, bool sigstop, + bool disable_hardened_malloc) { std::vector expanded_args; std::vector c_strings; @@ -134,6 +135,22 @@ static bool ExpandArgsAndExecv(const std::vector& args, bool sigsto kill(getpid(), SIGSTOP); } + + if (disable_hardened_malloc) { +#if defined(__BIONIC__) + if (setenv("DISABLE_HARDENED_MALLOC", "1", 1) != 0) { + LOG(ERROR) << "setenv(DISABLE_HARDENED_MALLOC) failed: " << strerror(errno); + } +#if defined(__aarch64__) + const int FLAG_COMPAT_VA_39_BIT = 1 << 30; + execveat(-1, c_strings[0], c_strings.data(), environ, FLAG_COMPAT_VA_39_BIT); + LOG(ERROR) << "execveat with FLAG_COMPAT_VA_39_BIT failed for " << c_strings[0] << ": " << strerror(errno); +#endif // defined(__aarch64__) +#else + LOG(ERROR) << "ignored disable_hardened_malloc option in non-bionic environment"; +#endif // defined(__BIONIC__) + } + return execv(c_strings[0], c_strings.data()) == 0; } @@ -578,7 +595,7 @@ void Service::RunService(const std::vector& descriptors, // priority. Aborts on failure. SetProcessAttributesAndCaps(std::move(setsid_finished)); - if (!ExpandArgsAndExecv(args_, sigstop_)) { + if (!ExpandArgsAndExecv(args_, sigstop_, disable_hardened_malloc_)) { PLOG(ERROR) << "cannot execv('" << args_[0] << "'). See the 'Debugging init' section of init's README.md for tips"; } diff --git a/init/service.h b/init/service.h index 0095c827062a..b71028975d14 100644 --- a/init/service.h +++ b/init/service.h @@ -233,6 +233,8 @@ class Service { bool sigstop_ = false; + bool disable_hardened_malloc_ = false; + const std::chrono::seconds default_restart_period_ = 5s; std::chrono::seconds restart_period_ = default_restart_period_; std::optional timeout_period_; diff --git a/init/service_parser.cpp b/init/service_parser.cpp index 8049762b0b94..54bed4add9b0 100644 --- a/init/service_parser.cpp +++ b/init/service_parser.cpp @@ -387,6 +387,11 @@ Result ServiceParser::ParseSigstop(std::vector&& args) { return {}; } +Result ServiceParser::ParseDisableHardenedMalloc(std::vector&& args) { + service_->disable_hardened_malloc_ = true; + return {}; +} + Result ServiceParser::ParseSetenv(std::vector&& args) { service_->environment_vars_.emplace_back(std::move(args[1]), std::move(args[2])); return {}; @@ -612,6 +617,7 @@ const KeywordMap& ServiceParser::GetParserMap() con {"shared_kallsyms", {0, 0, &ServiceParser::ParseSharedKallsyms}}, {"shutdown", {1, 1, &ServiceParser::ParseShutdown}}, {"sigstop", {0, 0, &ServiceParser::ParseSigstop}}, + {"disable_hardened_malloc", {0, 0, &ServiceParser::ParseDisableHardenedMalloc}}, {"socket", {3, 6, &ServiceParser::ParseSocket}}, {"stdio_to_kmsg", {0, 0, &ServiceParser::ParseStdioToKmsg}}, {"task_profiles", {1, kMax, &ServiceParser::ParseTaskProfiles}}, diff --git a/init/service_parser.h b/init/service_parser.h index e42b62b5cc6e..2a30f2c10bc9 100644 --- a/init/service_parser.h +++ b/init/service_parser.h @@ -70,6 +70,7 @@ class ServiceParser : public SectionParser { Result ParseSharedKallsyms(std::vector&& args); Result ParseShutdown(std::vector&& args); Result ParseSigstop(std::vector&& args); + Result ParseDisableHardenedMalloc(std::vector&& args); Result ParseSocket(std::vector&& args); Result ParseStdioToKmsg(std::vector&& args); Result ParseTaskProfiles(std::vector&& args); From 36e6282d743aa973437373ca1aa4d4ae8589b939 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Thu, 11 Jun 2026 18:16:57 +0000 Subject: [PATCH 2/2] add zygote_compat service --- rootdir/Android.bp | 7 +++++++ rootdir/init.rc | 1 + rootdir/init.zygote64_compat.rc | 14 ++++++++++++++ toolbox/start.cpp | 5 +++++ 4 files changed, 27 insertions(+) create mode 100644 rootdir/init.zygote64_compat.rc diff --git a/rootdir/Android.bp b/rootdir/Android.bp index 45287775d09c..87b0e6e3551b 100644 --- a/rootdir/Android.bp +++ b/rootdir/Android.bp @@ -130,6 +130,13 @@ prebuilt_etc { name: "init.zygote64.rc", src: "init.zygote64.rc", sub_dir: "init/hw", + required: ["init.zygote64_compat.rc"], +} + +prebuilt_etc { + name: "init.zygote64_compat.rc", + src: "init.zygote64_compat.rc", + sub_dir: "init/hw", } prebuilt_etc { diff --git a/rootdir/init.rc b/rootdir/init.rc index 7e1a7eb2ca43..65cb99e250f3 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -10,6 +10,7 @@ import /init.${ro.hardware}.rc import /vendor/etc/init/hw/init.${ro.hardware}.rc import /system/etc/init/hw/init.usb.configfs.rc import /system/etc/init/hw/init.${ro.zygote}.rc +import /system/etc/init/hw/init.zygote64_compat.rc # Cgroups are mounted right before early-init using list from /etc/cgroups.json on early-init diff --git a/rootdir/init.zygote64_compat.rc b/rootdir/init.zygote64_compat.rc new file mode 100644 index 000000000000..4a155fee9a4e --- /dev/null +++ b/rootdir/init.zygote64_compat.rc @@ -0,0 +1,14 @@ +service zygote_compat /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_compat + disable_hardened_malloc + class main + priority -20 + user root + group root readproc reserved_disk + rlimit nofile 32768 262144 + socket zygote_compat stream 660 root system + socket usap_pool_compat stream 660 root system + task_profiles ProcessCapacityHigh MaxPerformance + disabled + +on property:sys.start_compat_zygote=1 + start zygote_compat diff --git a/toolbox/start.cpp b/toolbox/start.cpp index 46314cfcf1bf..5f12af447ed0 100644 --- a/toolbox/start.cpp +++ b/toolbox/start.cpp @@ -49,6 +49,11 @@ static void ControlDefaultServices(bool start) { services.emplace_back("zygote_secondary"); } + if (!start) { + // compat zygote is started on-demand + services.emplace_back("zygote_compat"); + } + if (start) { for (const auto& service : services) { ControlService(true, service);