Merge "init: Wait for snapuserd before starting second stage"

This commit is contained in:
Akilesh Kailash 2022-01-25 19:05:20 +00:00 committed by Gerrit Code Review
commit 286c1d58ad
3 changed files with 66 additions and 2 deletions

View file

@ -599,8 +599,13 @@ bool UserSnapshotServer::WaitForSocket() {
return false;
}
// We must re-initialize property service access, since we launched before
// second-stage init.
// This initialization of system property is important. When daemon is
// launched post selinux transition (before init second stage),
// bionic libc initializes system property as part of __libc_init_common();
// however that initialization fails silently given that fact that we don't
// have /dev/__properties__ setup which is created at init second stage.
//
// At this point, we have the handlers setup and is safe to setup property.
__system_properties_init();
if (!android::base::WaitForProperty("snapuserd.proxy_ready", "true")) {

View file

@ -32,6 +32,7 @@
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <cutils/sockets.h>
#include <fs_avb/fs_avb.h>
#include <libsnapshot/snapshot.h>
#include <private/android_filesystem_config.h>
#include <procinfo/process_map.h>
@ -247,6 +248,56 @@ void SnapuserdSelinuxHelper::FinishTransition() {
}
}
/*
* Before starting init second stage, we will wait
* for snapuserd daemon to be up and running; bionic libc
* may read /system/etc/selinux/plat_property_contexts file
* before invoking main() function. This will happen if
* init initializes property during second stage. Any access
* to /system without snapuserd daemon will lead to a deadlock.
*
* Thus, we do a simple probe by reading system partition. This
* read will eventually be serviced by daemon confirming that
* daemon is up and running. Furthermore, we are still in the kernel
* domain and sepolicy has not been enforced yet. Thus, access
* to these device mapper block devices are ok even though
* we may see audit logs.
*/
bool SnapuserdSelinuxHelper::TestSnapuserdIsReady() {
std::string dev = "/dev/block/mapper/system"s + fs_mgr_get_slot_suffix();
android::base::unique_fd fd(open(dev.c_str(), O_RDONLY | O_DIRECT));
if (fd < 0) {
PLOG(ERROR) << "open " << dev << " failed";
return false;
}
void* addr;
ssize_t page_size = getpagesize();
if (posix_memalign(&addr, page_size, page_size) < 0) {
PLOG(ERROR) << "posix_memalign with page size " << page_size;
return false;
}
std::unique_ptr<void, decltype(&::free)> buffer(addr, ::free);
int iter = 0;
while (iter < 10) {
ssize_t n = TEMP_FAILURE_RETRY(pread(fd.get(), buffer.get(), page_size, 0));
if (n < 0) {
// Wait for sometime before retry
std::this_thread::sleep_for(100ms);
} else if (n == page_size) {
return true;
} else {
LOG(ERROR) << "pread returned: " << n << " from: " << dev << " expected: " << page_size;
}
iter += 1;
}
return false;
}
void SnapuserdSelinuxHelper::RelaunchFirstStageSnapuserd() {
auto fd = GetRamdiskSnapuserdFd();
if (!fd) {
@ -268,6 +319,13 @@ void SnapuserdSelinuxHelper::RelaunchFirstStageSnapuserd() {
setenv(kSnapuserdFirstStagePidVar, std::to_string(pid).c_str(), 1);
LOG(INFO) << "Relaunched snapuserd with pid: " << pid;
if (!TestSnapuserdIsReady()) {
PLOG(FATAL) << "snapuserd daemon failed to launch";
} else {
LOG(INFO) << "snapuserd daemon is up and running";
}
return;
}

View file

@ -56,6 +56,7 @@ class SnapuserdSelinuxHelper final {
private:
void RelaunchFirstStageSnapuserd();
void ExecSnapuserd();
bool TestSnapuserdIsReady();
std::unique_ptr<SnapshotManager> sm_;
BlockDevInitializer block_dev_init_;