Add android_dlwarning() method

This is temporary method intended to use
for a toast message on preview and beta
releases. Will be removed before the
production release.

Bug: http://b/27365747
Change-Id: I39cc716bb82863ae761b6821bcec77cce6db3781
diff --git a/libc/include/android/dlext.h b/libc/include/android/dlext.h
index d5ec386..76d19ae 100644
--- a/libc/include/android/dlext.h
+++ b/libc/include/android/dlext.h
@@ -194,6 +194,8 @@
                                                             uint64_t type,
                                                             const char* permitted_when_isolated_path);
 
+const char* android_dlwarning();
+
 __END_DECLS
 
 #endif /* __ANDROID_DLEXT_H__ */
diff --git a/libdl/libdl.arm.map b/libdl/libdl.arm.map
index b9e494a..98c0685 100644
--- a/libdl/libdl.arm.map
+++ b/libdl/libdl.arm.map
@@ -21,10 +21,15 @@
     dlvsym;
 } LIBC;
 
+LIBC_PLATFORM {
+  global:
+    android_dlwarning;
+} LIBC_N;
+
 LIBC_PRIVATE {
   global:
     android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
     android_get_LD_LIBRARY_PATH;
     android_update_LD_LIBRARY_PATH;
-} LIBC_N;
+} LIBC_PLATFORM;
diff --git a/libdl/libdl.arm64.map b/libdl/libdl.arm64.map
index a8c98da..b3de6bf 100644
--- a/libdl/libdl.arm64.map
+++ b/libdl/libdl.arm64.map
@@ -20,10 +20,15 @@
     dlvsym;
 } LIBC;
 
+LIBC_PLATFORM {
+  global:
+    android_dlwarning;
+} LIBC_N;
+
 LIBC_PRIVATE {
   global:
     android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
     android_get_LD_LIBRARY_PATH;
     android_update_LD_LIBRARY_PATH;
-} LIBC_N;
+} LIBC_PLATFORM;
diff --git a/libdl/libdl.c b/libdl/libdl.c
index fa5237f..d2e5e31 100644
--- a/libdl/libdl.c
+++ b/libdl/libdl.c
@@ -69,3 +69,5 @@
                                                      const char* permitted_when_isolated_path __unused) {
   return 0;
 }
+
+const char* android_dlwarning(void) { return 0; }
diff --git a/libdl/libdl.map.txt b/libdl/libdl.map.txt
index 55a03cb..e827e22 100644
--- a/libdl/libdl.map.txt
+++ b/libdl/libdl.map.txt
@@ -35,10 +35,15 @@
     dlvsym;
 } LIBC;
 
+LIBC_PLATFORM {
+  global:
+    android_dlwarning;
+} LIBC_N;
+
 LIBC_PRIVATE {
   global:
     android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
     android_get_LD_LIBRARY_PATH;
     android_update_LD_LIBRARY_PATH;
-} LIBC_N;
+} LIBC_PLATFORM;
diff --git a/libdl/libdl.mips.map b/libdl/libdl.mips.map
index a8c98da..b3de6bf 100644
--- a/libdl/libdl.mips.map
+++ b/libdl/libdl.mips.map
@@ -20,10 +20,15 @@
     dlvsym;
 } LIBC;
 
+LIBC_PLATFORM {
+  global:
+    android_dlwarning;
+} LIBC_N;
+
 LIBC_PRIVATE {
   global:
     android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
     android_get_LD_LIBRARY_PATH;
     android_update_LD_LIBRARY_PATH;
-} LIBC_N;
+} LIBC_PLATFORM;
diff --git a/libdl/libdl.mips64.map b/libdl/libdl.mips64.map
index a8c98da..b3de6bf 100644
--- a/libdl/libdl.mips64.map
+++ b/libdl/libdl.mips64.map
@@ -20,10 +20,15 @@
     dlvsym;
 } LIBC;
 
+LIBC_PLATFORM {
+  global:
+    android_dlwarning;
+} LIBC_N;
+
 LIBC_PRIVATE {
   global:
     android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
     android_get_LD_LIBRARY_PATH;
     android_update_LD_LIBRARY_PATH;
-} LIBC_N;
+} LIBC_PLATFORM;
diff --git a/libdl/libdl.x86.map b/libdl/libdl.x86.map
index a8c98da..b3de6bf 100644
--- a/libdl/libdl.x86.map
+++ b/libdl/libdl.x86.map
@@ -20,10 +20,15 @@
     dlvsym;
 } LIBC;
 
+LIBC_PLATFORM {
+  global:
+    android_dlwarning;
+} LIBC_N;
+
 LIBC_PRIVATE {
   global:
     android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
     android_get_LD_LIBRARY_PATH;
     android_update_LD_LIBRARY_PATH;
-} LIBC_N;
+} LIBC_PLATFORM;
diff --git a/libdl/libdl.x86_64.map b/libdl/libdl.x86_64.map
index a8c98da..b3de6bf 100644
--- a/libdl/libdl.x86_64.map
+++ b/libdl/libdl.x86_64.map
@@ -20,10 +20,15 @@
     dlvsym;
 } LIBC;
 
+LIBC_PLATFORM {
+  global:
+    android_dlwarning;
+} LIBC_N;
+
 LIBC_PRIVATE {
   global:
     android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
     android_get_LD_LIBRARY_PATH;
     android_update_LD_LIBRARY_PATH;
-} LIBC_N;
+} LIBC_PLATFORM;
diff --git a/linker/Android.mk b/linker/Android.mk
index 85ac0ca..1620888 100644
--- a/linker/Android.mk
+++ b/linker/Android.mk
@@ -10,6 +10,7 @@
     linker.cpp \
     linker_allocator.cpp \
     linker_block_allocator.cpp \
+    linker_dlwarning.cpp \
     linker_libc_support.c \
     linker_mapped_file_fragment.cpp \
     linker_memory.cpp \
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index a7c3fb0..89b2a36 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "linker.h"
+#include "linker_dlwarning.h"
 
 #include <pthread.h>
 #include <stdio.h>
@@ -136,6 +137,11 @@
   return get_application_target_sdk_version();
 }
 
+const char* android_dlwarning() {
+  ScopedPthreadMutexLocker locker(&g_dl_mutex);
+  return get_dlwarning();
+}
+
 bool android_init_namespaces(const char* public_ns_sonames,
                              const char* anon_ns_library_path) {
   ScopedPthreadMutexLocker locker(&g_dl_mutex);
@@ -190,11 +196,11 @@
   // 00000000001 1111111112222222222 3333333333444444444455555555556666666666777 777777788888888889999999999
   // 01234567890 1234567890123456789 0123456789012345678901234567890123456789012 345678901234567890123456789
     "erate_phdr\0android_dlopen_ext\0android_set_application_target_sdk_version\0android_get_application_tar"
-  // 0000000000111111 111122222222223333333333 4444444444555555555566666 6666677
-  // 0123456789012345 678901234567890123456789 0123456789012345678901234 5678901
-    "get_sdk_version\0android_init_namespaces\0android_create_namespace\0dlvsym\0"
+  // 0000000000111111 111122222222223333333333 4444444444555555555566666 6666677 777777778888888888
+  // 0123456789012345 678901234567890123456789 0123456789012345678901234 5678901 234567890123456789
+    "get_sdk_version\0android_init_namespaces\0android_create_namespace\0dlvsym\0android_dlwarning\0"
 #if defined(__arm__)
-  // 272
+  // 290
     "dl_unwind_find_exidx\0"
 #endif
     ;
@@ -219,8 +225,9 @@
   ELFW(SYM_INITIALIZER)(216, &android_init_namespaces, 1),
   ELFW(SYM_INITIALIZER)(240, &android_create_namespace, 1),
   ELFW(SYM_INITIALIZER)(265, &dlvsym, 1),
+  ELFW(SYM_INITIALIZER)(272, &android_dlwarning, 1),
 #if defined(__arm__)
-  ELFW(SYM_INITIALIZER)(272, &dl_unwind_find_exidx, 1),
+  ELFW(SYM_INITIALIZER)(290, &dl_unwind_find_exidx, 1),
 #endif
 };
 
@@ -237,9 +244,9 @@
 // Note that adding any new symbols here requires stubbing them out in libdl.
 static unsigned g_libdl_buckets[1] = { 1 };
 #if defined(__arm__)
-static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0 };
+static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0 };
 #else
-static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0 };
+static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0 };
 #endif
 
 static uint8_t __libdl_info_buf[sizeof(soinfo)] __attribute__((aligned(8)));
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 77642e7..a38a566 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -52,6 +52,7 @@
 #include "linker.h"
 #include "linker_block_allocator.h"
 #include "linker_debug.h"
+#include "linker_dlwarning.h"
 #include "linker_sleb128.h"
 #include "linker_phdr.h"
 #include "linker_relocs.h"
@@ -1707,6 +1708,7 @@
     const char* bname = basename(dt_needed);
     if (bname != dt_needed) {
       DL_WARN("'%s' library has invalid DT_NEEDED entry '%s'", sopath, dt_needed);
+      add_dlwarning(sopath, "invalid DT_NEEDED entry",  dt_needed);
     }
 
     return bname;
@@ -1803,12 +1805,12 @@
       // print warning only if needed by non-system library
       if (needed_by == nullptr || !is_system_library(needed_by->get_realpath())) {
         const soinfo* needed_or_dlopened_by = task->get_needed_by();
+        const char* sopath = needed_or_dlopened_by == nullptr ? "(unknown)" :
+                                                      needed_or_dlopened_by->get_realpath();
         DL_WARN("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the namespace \"%s\""
                 " - the access is temporarily granted as a workaround for http://b/26394120",
-                name, realpath.c_str(),
-                needed_or_dlopened_by == nullptr ? "(unknown)" :
-                                         needed_or_dlopened_by->get_realpath(),
-                ns->get_name());
+                name, realpath.c_str(), sopath, ns->get_name());
+        add_dlwarning(sopath, "unauthorized access to",  name);
       }
     } else {
       // do not load libraries if they are not accessible for the specified namespace.
@@ -3809,6 +3811,7 @@
     soname_ = basename(realpath_.c_str());
     DL_WARN("%s: is missing DT_SONAME will use basename as a replacement: \"%s\"",
         get_realpath(), soname_);
+    add_dlwarning(get_realpath(), "missing DT_SONAME");
   }
   return true;
 }
@@ -3843,6 +3846,7 @@
     // phdr_table_protect_segments() after all of them are applied.
     DL_WARN("%s has text relocations. This is wasting memory and prevents "
             "security hardening. Please fix.", get_realpath());
+    add_dlwarning(get_realpath(), "text relocations");
     if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
       DL_ERR("can't unprotect loadable segments for \"%s\": %s",
              get_realpath(), strerror(errno));
diff --git a/linker/linker_dlwarning.cpp b/linker/linker_dlwarning.cpp
new file mode 100644
index 0000000..f4a3daf
--- /dev/null
+++ b/linker/linker_dlwarning.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "linker_dlwarning.h"
+
+#include <strings.h>
+
+#include <string>
+
+static std::string current_msg;
+static std::string old_msg;
+
+void add_dlwarning(const char* sopath, const char* message, const char* value) {
+  if (!current_msg.empty()) {
+    current_msg += '\n';
+  }
+
+  current_msg = current_msg + basename(sopath) + ": " + message;
+
+  if (value != nullptr) {
+    current_msg = current_msg + " \'" + value + "\'";
+  }
+
+}
+
+// Resets the current one (like dlerror but instead of
+// being thread-local it is process-local).
+const char* get_dlwarning() {
+  if (current_msg.empty()) {
+    return nullptr;
+  }
+
+  old_msg = current_msg;
+  current_msg.clear();
+
+  return old_msg.c_str();
+}
diff --git a/linker/linker_dlwarning.h b/linker/linker_dlwarning.h
new file mode 100644
index 0000000..b67032c
--- /dev/null
+++ b/linker/linker_dlwarning.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LINKER_DLWARNING_H
+#define __LINKER_DLWARNING_H
+
+void add_dlwarning(const char* sopath, const char* message, const char* value = nullptr);
+
+// Resets the current one (like dlerror but instead of
+// being thread-local it is process-local).
+const char* get_dlwarning();
+
+#endif  /* __LINKER_DLWARNING_H */