linker: changes to init work arounds

Change three things regarding the work around to the fact that init is
special:

1) Only first stage init is special, so we change the check to include
   accessing /proc/self/exe, which if is available, means that we're
   not first stage init and do not need any work arounds.
2) Fix the fact that /init may be a symlink and may need readlink()
3) Suppress errors from realpath_fd() since these are expected to fail
   due to /proc not being mounted.

Bug: 80395578
Test: sailfish boots without the audit generated from calling stat()
      on /init and without the errors from realpath_fd()

Change-Id: I266f1486b142cb9a41ec791eba74122bdf38cf12
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 0470d7a..6d646a2 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -354,7 +354,9 @@
   std::vector<char> buf(PATH_MAX), proc_self_fd(PATH_MAX);
   async_safe_format_buffer(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd);
   if (readlink(&proc_self_fd[0], &buf[0], buf.size()) == -1) {
-    PRINT("readlink(\"%s\") failed: %s [fd=%d]", &proc_self_fd[0], strerror(errno), fd);
+    if (!is_first_stage_init()) {
+      PRINT("readlink(\"%s\") failed: %s [fd=%d]", &proc_self_fd[0], strerror(errno), fd);
+    }
     return false;
   }
 
@@ -993,8 +995,10 @@
   if (realpath_fd(fd, realpath)) {
     *realpath += separator;
   } else {
-    PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.",
-          normalized_path.c_str());
+    if (!is_first_stage_init()) {
+      PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.",
+            normalized_path.c_str());
+    }
     *realpath = normalized_path;
   }
 
@@ -1024,7 +1028,10 @@
     if (fd != -1) {
       *file_offset = 0;
       if (!realpath_fd(fd, realpath)) {
-        PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", path);
+        if (!is_first_stage_init()) {
+          PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.",
+                path);
+        }
         *realpath = path;
       }
     }
@@ -1071,7 +1078,10 @@
       if (fd != -1) {
         *file_offset = 0;
         if (!realpath_fd(fd, realpath)) {
-          PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", name);
+          if (!is_first_stage_init()) {
+            PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.",
+                  name);
+          }
           *realpath = name;
         }
       }
@@ -1354,8 +1364,12 @@
     }
 
     if (!realpath_fd(extinfo->library_fd, &realpath)) {
-      PRINT("warning: unable to get realpath for the library \"%s\" by extinfo->library_fd. "
-            "Will use given name.", name);
+      if (!is_first_stage_init()) {
+        PRINT(
+            "warning: unable to get realpath for the library \"%s\" by extinfo->library_fd. "
+            "Will use given name.",
+            name);
+      }
       realpath = name;
     }
 
@@ -1510,9 +1524,9 @@
 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.
+  if (is_first_stage_init()) {
+    // arc4random* is not available in first stage init because /dev/random
+    // hasn't yet been created.
     return;
   }
   for (size_t i = 0, size = v->size(); i < size; ++i) {
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index f7c496a..d88fc75 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -195,11 +195,19 @@
 static ExecutableInfo get_executable_info(KernelArgumentBlock& args) {
   ExecutableInfo result = {};
 
-  if (is_init()) {
-    // /proc fs is not mounted when init starts. Therefore we can't use
-    // /proc/self/exe for init.
+  if (is_first_stage_init()) {
+    // /proc fs is not mounted when first stage init starts. Therefore we can't
+    // use /proc/self/exe for init.
     stat("/init", &result.file_stat);
-    result.path = "/init";
+
+    // /init may be a symlink, so try to read it as such.
+    char path[PATH_MAX];
+    ssize_t path_len = readlink("/init", path, sizeof(path));
+    if (path_len == -1 || path_len >= static_cast<ssize_t>(sizeof(path))) {
+      result.path = "/init";
+    } else {
+      result.path = std::string(path, path_len);
+    }
   } else {
     // Stat "/proc/self/exe" instead of executable_path because
     // the executable could be unlinked by this point and it should
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index 8bf4c94..741d4e0 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -551,9 +551,9 @@
   uint8_t* first = align_up(mmap_ptr, align);
   uint8_t* last = align_down(mmap_ptr + mmap_size, align) - size;
 
-  // arc4random* is not available in init because /dev/urandom hasn't yet been
+  // arc4random* is not available in first stage 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);
+  size_t n = is_first_stage_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 795b01d..e630297 100644
--- a/linker/linker_soinfo.cpp
+++ b/linker/linker_soinfo.cpp
@@ -748,7 +748,7 @@
   // Make sure the handle is unique and does not collide
   // with special values which are RTLD_DEFAULT and RTLD_NEXT.
   do {
-    if (!is_init()) {
+    if (!is_first_stage_init()) {
       arc4random_buf(&handle_, sizeof(handle_));
     } else {
       // arc4random* is not available in init because /dev/urandom hasn't yet been
diff --git a/linker/linker_utils.cpp b/linker/linker_utils.cpp
index 6b9aec9..72a8fa8 100644
--- a/linker/linker_utils.cpp
+++ b/linker/linker_utils.cpp
@@ -240,7 +240,7 @@
   }
 }
 
-bool is_init() {
-  static bool ret = (getpid() == 1);
+bool is_first_stage_init() {
+  static bool ret = (getpid() == 1 && access("/proc/self/exe", F_OK) == -1);
   return ret;
 }
diff --git a/linker/linker_utils.h b/linker/linker_utils.h
index b15082d..34a597b 100644
--- a/linker/linker_utils.h
+++ b/linker/linker_utils.h
@@ -55,4 +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();
+bool is_first_stage_init();