Merge "vts_libprocessgroup: Add vts_libprocessgroup" into main
diff --git a/debuggerd/crasher/crasher.cpp b/debuggerd/crasher/crasher.cpp
index 05143ed..c3dd92b 100644
--- a/debuggerd/crasher/crasher.cpp
+++ b/debuggerd/crasher/crasher.cpp
@@ -402,6 +402,8 @@
return EXIT_SUCCESS;
}
+} // extern "C"
+
int main(int argc, char** argv) {
#if defined(STATIC_CRASHER)
debuggerd_callbacks_t callbacks = {
@@ -427,5 +429,3 @@
return usage();
}
-
-};
diff --git a/fastboot/OWNERS b/fastboot/OWNERS
index 3dec07e..2444081 100644
--- a/fastboot/OWNERS
+++ b/fastboot/OWNERS
@@ -1,5 +1,6 @@
dvander@google.com
elsk@google.com
enh@google.com
+sanglardf@google.com
zhangkelvin@google.com
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 8e62d93..931de89 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -3072,6 +3072,18 @@
::testing::AddGlobalTestEnvironment(new ::android::snapshot::SnapshotTestEnvironment());
gflags::ParseCommandLineFlags(&argc, &argv, false);
+ // During incremental flashing, snapshot updates are in progress.
+ //
+ // When snapshot update is in-progress, snapuserd daemon
+ // will be up and running. These tests will start and stop the daemon
+ // thereby interfering with the update and snapshot-merge progress.
+ // Hence, wait until the update is complete.
+ auto sm = android::snapshot::SnapshotManager::New();
+ while (sm->IsUserspaceSnapshotUpdateInProgress()) {
+ LOG(INFO) << "Snapshot update is in progress. Waiting...";
+ std::this_thread::sleep_for(std::chrono::milliseconds(1000));
+ }
+
bool vab_legacy = false;
if (FLAGS_force_mode == "vab-legacy") {
vab_legacy = true;
diff --git a/init/README.md b/init/README.md
index 560c528..251fe98 100644
--- a/init/README.md
+++ b/init/README.md
@@ -369,6 +369,17 @@
`setenv <name> <value>`
> Set the environment variable _name_ to _value_ in the launched process.
+`shared_kallsyms`
+> If set, init will behave as if the service specified "file /proc/kallsyms r",
+ except the service will receive a duplicate of a single fd that init saved
+ during early second\_stage. This fd retains address visibility even after the
+ systemwide kptr\_restrict sysctl is set to its steady state on Android. The
+ ability to read from this fd is still constrained by selinux permissions,
+ which need to be granted separately and are gated by a neverallow.
+ Because of performance gotchas of concurrent use of this shared fd, all uses
+ need to coordinate via provisional flock(LOCK\_EX) locks on separately opened
+ /proc/kallsyms fds (since locking requires distinct open file descriptions).
+
`shutdown <shutdown_behavior>`
> Set shutdown behavior of the service process. When this is not specified,
the service is killed during shutdown process by using SIGTERM and SIGKILL.
@@ -475,6 +486,12 @@
2. Any time that property a transitions to value b, while property c already equals d.
3. Any time that property c transitions to value d, while property a already equals b.
+Note that, for bootloader-provided properties (ro.boot.*), their action cannot be
+auto-triggered until `boot` stage. If they need to be triggered earlier, like at `early-boot`
+stage, they should be tied to the `event`. For example:
+
+`on early-boot && property:a=b`.
+
Trigger Sequence
----------------
diff --git a/init/init.cpp b/init/init.cpp
index 5b0b0dd..b6ba6a8 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -1055,6 +1055,14 @@
}
}
+ // This needs to happen before SetKptrRestrictAction, as we are trying to
+ // open /proc/kallsyms while still being allowed to see the full addresses
+ // (since init holds CAP_SYSLOG, and Linux boots with kptr_restrict=0). The
+ // address visibility through the saved fd (more specifically, the backing
+ // open file description) will then be remembered by the kernel for the rest
+ // of its lifetime, even after we raise the kptr_restrict.
+ Service::OpenAndSaveStaticKallsymsFd();
+
am.QueueBuiltinAction(SetupCgroupsAction, "SetupCgroups");
am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
am.QueueBuiltinAction(TestPerfEventSelinuxAction, "TestPerfEventSelinux");
diff --git a/init/property_service.cpp b/init/property_service.cpp
index f2606e3..31af94e 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -595,7 +595,7 @@
}
static void handle_property_set_fd(int fd) {
- static constexpr uint32_t kDefaultSocketTimeout = 2000; /* ms */
+ static constexpr uint32_t kDefaultSocketTimeout = 5000; /* ms */
int s = accept4(fd, nullptr, nullptr, SOCK_CLOEXEC);
if (s == -1) {
diff --git a/init/service.cpp b/init/service.cpp
index d76a5d5..5630020 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -34,6 +34,7 @@
#include <android-base/scopeguard.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include <cutils/android_get_control_file.h>
#include <cutils/sockets.h>
#include <processgroup/processgroup.h>
#include <selinux/selinux.h>
@@ -672,6 +673,14 @@
}
}
+ if (shared_kallsyms_file_) {
+ if (auto result = CreateSharedKallsymsFd(); result.ok()) {
+ descriptors.emplace_back(std::move(*result));
+ } else {
+ LOG(INFO) << "Could not obtain a copy of /proc/kallsyms: " << result.error();
+ }
+ }
+
pid_t pid = -1;
if (namespaces_.flags) {
pid = clone(nullptr, nullptr, namespaces_.flags | SIGCHLD, nullptr);
@@ -835,6 +844,35 @@
return unique_fd(signalfd(-1, &mask, SFD_CLOEXEC));
}
+void Service::OpenAndSaveStaticKallsymsFd() {
+ Result<Descriptor> result = CreateSharedKallsymsFd();
+ if (!result.ok()) {
+ LOG(ERROR) << result.error();
+ }
+}
+
+// This function is designed to be called in two situations:
+// 1) early during second_stage init, to open and save the shared fd as a
+// static (see OpenAndSaveStaticKallsymsFd).
+// 2) whenever a service requesting a copy of the fd is being started, at which
+// point it will get a duplicated copy of the static fd.
+Result<Descriptor> Service::CreateSharedKallsymsFd() {
+ static constexpr char kallsyms_path[] = "/proc/kallsyms";
+ static int static_fd = open(kallsyms_path, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
+ if (static_fd < 0) {
+ return ErrnoError() << "failed to open " << kallsyms_path;
+ }
+
+ unique_fd fd{fcntl(static_fd, F_DUPFD_CLOEXEC, /*min_fd=*/3)};
+ if (fd < 0) {
+ return ErrnoError() << "failed fcntl(F_DUPFD_CLOEXEC)";
+ }
+
+ // Use the same environment variable as if the service specified
+ // "file /proc/kallsyms r".
+ return Descriptor(std::string(ANDROID_FILE_ENV_PREFIX) + kallsyms_path, std::move(fd));
+}
+
void Service::SetStartedInFirstStage(pid_t pid) {
LOG(INFO) << "adding first-stage service '" << name_ << "'...";
diff --git a/init/service.h b/init/service.h
index ae75553..7193d7e 100644
--- a/init/service.h
+++ b/init/service.h
@@ -158,6 +158,7 @@
static int sigchld_fd = CreateSigchldFd().release();
return sigchld_fd;
}
+ static void OpenAndSaveStaticKallsymsFd();
private:
void NotifyStateChange(const std::string& new_state) const;
@@ -171,6 +172,7 @@
InterprocessFifo setsid_finished);
void SetMountNamespace();
static ::android::base::unique_fd CreateSigchldFd();
+ static Result<Descriptor> CreateSharedKallsymsFd();
static unsigned long next_start_order_;
static bool is_exec_service_running_;
@@ -188,6 +190,7 @@
std::optional<std::string> fatal_reboot_target_; // reboot target of fatal handler
bool was_last_exit_ok_ =
true; // true if the service never exited, or exited with status code 0
+ bool shared_kallsyms_file_ = false; // pass the service a pre-opened fd to /proc/kallsyms
std::optional<CapSet> capabilities_;
ProcessAttributes proc_attr_;
diff --git a/init/service_parser.cpp b/init/service_parser.cpp
index ec3b176..4c31718 100644
--- a/init/service_parser.cpp
+++ b/init/service_parser.cpp
@@ -309,6 +309,11 @@
return {};
}
+Result<void> ServiceParser::ParseSharedKallsyms(std::vector<std::string>&& args) {
+ service_->shared_kallsyms_file_ = true;
+ return {};
+}
+
Result<void> ServiceParser::ParseMemcgSwappiness(std::vector<std::string>&& args) {
if (!ParseInt(args[1], &service_->swappiness_, 0)) {
return Error() << "swappiness value must be equal or greater than 0";
@@ -603,6 +608,7 @@
{"rlimit", {3, 3, &ServiceParser::ParseProcessRlimit}},
{"seclabel", {1, 1, &ServiceParser::ParseSeclabel}},
{"setenv", {2, 2, &ServiceParser::ParseSetenv}},
+ {"shared_kallsyms", {0, 0, &ServiceParser::ParseSharedKallsyms}},
{"shutdown", {1, 1, &ServiceParser::ParseShutdown}},
{"sigstop", {0, 0, &ServiceParser::ParseSigstop}},
{"socket", {3, 6, &ServiceParser::ParseSocket}},
diff --git a/init/service_parser.h b/init/service_parser.h
index f06cfc4..e42b62b 100644
--- a/init/service_parser.h
+++ b/init/service_parser.h
@@ -67,6 +67,7 @@
Result<void> ParseRestartPeriod(std::vector<std::string>&& args);
Result<void> ParseSeclabel(std::vector<std::string>&& args);
Result<void> ParseSetenv(std::vector<std::string>&& args);
+ Result<void> ParseSharedKallsyms(std::vector<std::string>&& args);
Result<void> ParseShutdown(std::vector<std::string>&& args);
Result<void> ParseSigstop(std::vector<std::string>&& args);
Result<void> ParseSocket(std::vector<std::string>&& args);
diff --git a/janitors/OWNERS b/janitors/OWNERS
index c25d9e4..b317151 100644
--- a/janitors/OWNERS
+++ b/janitors/OWNERS
@@ -1,7 +1,19 @@
-# OWNERS file for projects that don't really have owners so much as volunteer janitors.
+# go/android-3p requires that all external projects have the "janitors" in
+# their OWNERS files.
+
+# These are also the "owners" for projects that don't really have owners
+# so much as volunteer janitors.
+
+# General maintenance.
+sadafebrahimi@google.com
+
+# C/C++.
ccross@google.com
cferris@google.com
-dwillemsen@google.com
enh@google.com
+
+# Java.
maco@google.com
-sadafebrahimi@google.com
+
+# Python.
+dwillemsen@google.com
diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h
index 28b17c1..98179e8 100644
--- a/libprocessgroup/include/processgroup/processgroup.h
+++ b/libprocessgroup/include/processgroup/processgroup.h
@@ -32,6 +32,8 @@
// Provides the path for an attribute in a specific process group
// Returns false in case of error, true in case of success
bool CgroupGetAttributePathForTask(const std::string& attr_name, pid_t tid, std::string* path);
+bool CgroupGetAttributePathForProcess(std::string_view attr_name, uid_t uid, pid_t pid,
+ std::string &path);
bool SetTaskProfiles(pid_t tid, const std::vector<std::string>& profiles,
bool use_fd_cache = false);
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 53168e3..a8fa50a 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -85,7 +85,8 @@
CgroupGetControllerPath(CGROUPV2_HIERARCHY_NAME, &cg_kill);
// cgroup.kill is not on the root cgroup, so check a non-root cgroup that should always
// exist
- cg_kill = ConvertUidToPath(cg_kill.c_str(), AID_ROOT) + '/' + PROCESSGROUP_CGROUP_KILL_FILE;
+ cg_kill = ConvertUidToPath(cg_kill.c_str(), AID_ROOT, true) + '/' +
+ PROCESSGROUP_CGROUP_KILL_FILE;
cgroup_kill_available = access(cg_kill.c_str(), F_OK) == 0;
});
@@ -154,6 +155,23 @@
return true;
}
+bool CgroupGetAttributePathForProcess(std::string_view attr_name, uid_t uid, pid_t pid,
+ std::string &path) {
+ const TaskProfiles& tp = TaskProfiles::GetInstance();
+ const IProfileAttribute* attr = tp.GetAttribute(attr_name);
+
+ if (attr == nullptr) {
+ return false;
+ }
+
+ if (!attr->GetPathForProcess(uid, pid, &path)) {
+ LOG(ERROR) << "Failed to find cgroup for uid " << uid << " pid " << pid;
+ return false;
+ }
+
+ return true;
+}
+
bool UsePerAppMemcg() {
bool low_ram_device = GetBoolProperty("ro.config.low_ram", false);
return GetBoolProperty("ro.config.per_app_memcg", low_ram_device);
@@ -224,14 +242,14 @@
false);
}
-static int RemoveCgroup(const char* cgroup, uid_t uid, pid_t pid) {
- auto path = ConvertUidPidToPath(cgroup, uid, pid);
+static int RemoveCgroup(const char* cgroup, uid_t uid, pid_t pid, bool v2_path) {
+ auto path = ConvertUidPidToPath(cgroup, uid, pid, v2_path);
int ret = TEMP_FAILURE_RETRY(rmdir(path.c_str()));
if (!ret && uid >= AID_ISOLATED_START && uid <= AID_ISOLATED_END) {
// Isolated UIDs are unlikely to be reused soon after removal,
// so free up the kernel resources for the UID level cgroup.
- path = ConvertUidToPath(cgroup, uid);
+ path = ConvertUidToPath(cgroup, uid, v2_path);
ret = TEMP_FAILURE_RETRY(rmdir(path.c_str()));
}
@@ -368,7 +386,7 @@
if (CgroupsAvailable()) {
std::string hierarchy_root_path, cgroup_v2_path;
CgroupGetControllerPath(CGROUPV2_HIERARCHY_NAME, &hierarchy_root_path);
- cgroup_v2_path = ConvertUidPidToPath(hierarchy_root_path.c_str(), uid, initialPid);
+ cgroup_v2_path = ConvertUidPidToPath(hierarchy_root_path.c_str(), uid, initialPid, true);
if (signal == SIGKILL && CgroupKillAvailable()) {
LOG(VERBOSE) << "Using " << PROCESSGROUP_CGROUP_KILL_FILE << " to SIGKILL "
@@ -539,7 +557,7 @@
CgroupGetControllerPath(CGROUPV2_HIERARCHY_NAME, &hierarchy_root_path);
const std::string cgroup_v2_path =
- ConvertUidPidToPath(hierarchy_root_path.c_str(), uid, initialPid);
+ ConvertUidPidToPath(hierarchy_root_path.c_str(), uid, initialPid, true);
const std::string eventsfile = cgroup_v2_path + '/' + PROCESSGROUP_CGROUP_EVENTS_FILE;
android::base::unique_fd events_fd(open(eventsfile.c_str(), O_RDONLY));
@@ -605,7 +623,7 @@
<< " after " << kill_duration.count() << " ms";
}
- ret = RemoveCgroup(hierarchy_root_path.c_str(), uid, initialPid);
+ ret = RemoveCgroup(hierarchy_root_path.c_str(), uid, initialPid, true);
if (ret)
PLOG(ERROR) << "Unable to remove cgroup " << cgroup_v2_path;
else
@@ -616,9 +634,9 @@
// memcg v2.
std::string memcg_apps_path;
if (CgroupGetMemcgAppsPath(&memcg_apps_path) &&
- (ret = RemoveCgroup(memcg_apps_path.c_str(), uid, initialPid)) < 0) {
+ (ret = RemoveCgroup(memcg_apps_path.c_str(), uid, initialPid, false)) < 0) {
const auto memcg_v1_cgroup_path =
- ConvertUidPidToPath(memcg_apps_path.c_str(), uid, initialPid);
+ ConvertUidPidToPath(memcg_apps_path.c_str(), uid, initialPid, false);
PLOG(ERROR) << "Unable to remove memcg v1 cgroup " << memcg_v1_cgroup_path;
}
}
@@ -640,7 +658,7 @@
static int createProcessGroupInternal(uid_t uid, pid_t initialPid, std::string cgroup,
bool activate_controllers) {
- auto uid_path = ConvertUidToPath(cgroup.c_str(), uid);
+ auto uid_path = ConvertUidToPath(cgroup.c_str(), uid, activate_controllers);
struct stat cgroup_stat;
mode_t cgroup_mode = 0750;
@@ -667,7 +685,7 @@
}
}
- auto uid_pid_path = ConvertUidPidToPath(cgroup.c_str(), uid, initialPid);
+ auto uid_pid_path = ConvertUidPidToPath(cgroup.c_str(), uid, initialPid, activate_controllers);
if (!MkdirAndChown(uid_pid_path, cgroup_mode, cgroup_uid, cgroup_gid)) {
PLOG(ERROR) << "Failed to make and chown " << uid_pid_path;
diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json
index 28902ef..720cb30 100644
--- a/libprocessgroup/profiles/task_profiles.json
+++ b/libprocessgroup/profiles/task_profiles.json
@@ -81,6 +81,11 @@
"Name": "FreezerState",
"Controller": "freezer",
"File": "cgroup.freeze"
+ },
+ {
+ "Name": "CgroupProcs",
+ "Controller": "cgroup2",
+ "File": "cgroup.procs"
}
],
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index dc6c8c0..c03c257 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -150,8 +150,8 @@
return uid < AID_APP_START;
}
-std::string ConvertUidToPath(const char* root_cgroup_path, uid_t uid) {
- if (android::libprocessgroup_flags::cgroup_v2_sys_app_isolation()) {
+std::string ConvertUidToPath(const char* root_cgroup_path, uid_t uid, bool v2_path) {
+ if (android::libprocessgroup_flags::cgroup_v2_sys_app_isolation() && v2_path) {
if (isSystemApp(uid))
return StringPrintf("%s/system/uid_%u", root_cgroup_path, uid);
else
@@ -160,14 +160,14 @@
return StringPrintf("%s/uid_%u", root_cgroup_path, uid);
}
-std::string ConvertUidPidToPath(const char* root_cgroup_path, uid_t uid, pid_t pid) {
- const std::string uid_path = ConvertUidToPath(root_cgroup_path, uid);
+std::string ConvertUidPidToPath(const char* root_cgroup_path, uid_t uid, pid_t pid, bool v2_path) {
+ const std::string uid_path = ConvertUidToPath(root_cgroup_path, uid, v2_path);
return StringPrintf("%s/pid_%d", uid_path.c_str(), pid);
}
bool ProfileAttribute::GetPathForProcess(uid_t uid, pid_t pid, std::string* path) const {
if (controller()->version() == 2) {
- const std::string cgroup_path = ConvertUidPidToPath(controller()->path(), uid, pid);
+ const std::string cgroup_path = ConvertUidPidToPath(controller()->path(), uid, pid, true);
*path = cgroup_path + "/" + file_name();
return true;
}
@@ -199,7 +199,7 @@
return true;
}
- const std::string cgroup_path = ConvertUidToPath(controller()->path(), uid);
+ const std::string cgroup_path = ConvertUidToPath(controller()->path(), uid, true);
*path = cgroup_path + "/" + file_name();
return true;
}
diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h
index d0b5043..b1d6115 100644
--- a/libprocessgroup/task_profiles.h
+++ b/libprocessgroup/task_profiles.h
@@ -258,5 +258,5 @@
std::map<std::string, std::unique_ptr<IProfileAttribute>, std::less<>> attributes_;
};
-std::string ConvertUidToPath(const char* root_cgroup_path, uid_t uid);
-std::string ConvertUidPidToPath(const char* root_cgroup_path, uid_t uid, pid_t pid);
+std::string ConvertUidToPath(const char* root_cgroup_path, uid_t uid, bool v2_path);
+std::string ConvertUidPidToPath(const char* root_cgroup_path, uid_t uid, pid_t pid, bool v2_path);
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 883ed9c..f1670ae 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -569,6 +569,9 @@
chown root log /proc/vmallocinfo
chmod 0440 /proc/vmallocinfo
+ chown root log /proc/allocinfo
+ chmod 0440 /proc/allocinfo
+
chown root log /proc/slabinfo
chmod 0440 /proc/slabinfo