dynamic linker is running for init

init is now built as a dynamic executable, so the dynamic linker has to
be able to run in the init process. However, since init is launched so
early, even /dev/* and /proc/* file systems are not mounted and thus
some APIs that rely on the paths do not work. The dynamic linker now
goes alternative path when it is running in the init process.

For example, /proc/self/exe is not read for the init since we always now
the path of the init (/init). Also, arc4random* APIs are not used since
the APIs rely on /dev/urandom. Linker now does not randomize library
loading order and addresses when running in the init process.

Bug: 80454183
Test: `adb reboot recovery; adb devices` shows the device ID
Change-Id: I29b6d70e4df5f7f690876126d5fe81258c1d3115
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 9503a49..9094b0a 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -1489,6 +1489,11 @@
 static void soinfo_unload(soinfo* si);
 
 static void shuffle(std::vector<LoadTask*>* v) {
+  if (is_init()) {
+    // arc4random* is not available in init because /dev/random hasn't yet been
+    // created.
+    return;
+  }
   for (size_t i = 0, size = v->size(); i < size; ++i) {
     size_t n = size - i;
     size_t r = arc4random_uniform(n);
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index 1a0d164..a874152 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -197,12 +197,16 @@
 static const char* get_executable_path() {
   static std::string executable_path;
   if (executable_path.empty()) {
-    char path[PATH_MAX];
-    ssize_t path_len = readlink("/proc/self/exe", path, sizeof(path));
-    if (path_len == -1 || path_len >= static_cast<ssize_t>(sizeof(path))) {
-      async_safe_fatal("readlink('/proc/self/exe') failed: %s", strerror(errno));
+    if (!is_init()) {
+      char path[PATH_MAX];
+      ssize_t path_len = readlink("/proc/self/exe", path, sizeof(path));
+      if (path_len == -1 || path_len >= static_cast<ssize_t>(sizeof(path))) {
+        async_safe_fatal("readlink('/proc/self/exe') failed: %s", strerror(errno));
+      }
+      executable_path = std::string(path, path_len);
+    } else {
+      executable_path = "/init";
     }
-    executable_path = std::string(path, path_len);
   }
 
   return executable_path.c_str();
@@ -288,8 +292,14 @@
   // Stat "/proc/self/exe" instead of executable_path because
   // the executable could be unlinked by this point and it should
   // not cause a crash (see http://b/31084669)
-  if (TEMP_FAILURE_RETRY(stat("/proc/self/exe", &file_stat)) != 0) {
-    async_safe_fatal("unable to stat \"/proc/self/exe\": %s", strerror(errno));
+  if (!is_init()) {
+    if (TEMP_FAILURE_RETRY(stat("/proc/self/exe", &file_stat)) != 0) {
+      async_safe_fatal("unable to stat \"/proc/self/exe\": %s", strerror(errno));
+    }
+  } else {
+    // /proc fs is not mounted when init starts. Therefore we can't use
+    // /proc/self/exe for init.
+    stat("/init", &file_stat);
   }
 
   const char* executable_path = get_executable_path();
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index a5eab44..b24be92 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -547,7 +547,10 @@
 
   uint8_t* first = align_up(mmap_ptr, align);
   uint8_t* last = align_down(mmap_ptr + mmap_size, align) - size;
-  size_t n = arc4random_uniform((last - first) / PAGE_SIZE + 1);
+
+  // arc4random* is not available in init because /dev/urandom hasn't yet been
+  // created. Don't randomize then.
+  size_t n = is_init() ? 0 : arc4random_uniform((last - first) / PAGE_SIZE + 1);
   uint8_t* start = first + n * PAGE_SIZE;
   munmap(mmap_ptr, start - mmap_ptr);
   munmap(start + size, mmap_ptr + mmap_size - (start + size));
diff --git a/linker/linker_soinfo.cpp b/linker/linker_soinfo.cpp
index 3191ac7..795b01d 100644
--- a/linker/linker_soinfo.cpp
+++ b/linker/linker_soinfo.cpp
@@ -748,7 +748,14 @@
   // Make sure the handle is unique and does not collide
   // with special values which are RTLD_DEFAULT and RTLD_NEXT.
   do {
-    arc4random_buf(&handle_, sizeof(handle_));
+    if (!is_init()) {
+      arc4random_buf(&handle_, sizeof(handle_));
+    } else {
+      // arc4random* is not available in init because /dev/urandom hasn't yet been
+      // created. So, when running with init, use the monotonically increasing
+      // numbers as handles
+      handle_ += 2;
+    }
     // the least significant bit for the handle is always 1
     // making it easy to test the type of handle passed to
     // dl* functions.
diff --git a/linker/linker_utils.cpp b/linker/linker_utils.cpp
index 661e7cb..789d5c1 100644
--- a/linker/linker_utils.cpp
+++ b/linker/linker_utils.cpp
@@ -239,3 +239,8 @@
     }
   }
 }
+
+bool is_init() {
+  static bool ret = (getpid() == 1);
+  return ret;
+}
diff --git a/linker/linker_utils.h b/linker/linker_utils.h
index 214646c..b15082d 100644
--- a/linker/linker_utils.h
+++ b/linker/linker_utils.h
@@ -55,3 +55,4 @@
 off64_t page_start(off64_t offset);
 size_t page_offset(off64_t offset);
 bool safe_add(off64_t* out, off64_t a, size_t b);
+bool is_init();