OSDN Git Service

Fix x86 system calls made from ELF preinit.
authorElliott Hughes <enh@google.com>
Wed, 29 Mar 2017 20:48:02 +0000 (13:48 -0700)
committerElliott Hughes <enh@google.com>
Wed, 29 Mar 2017 23:15:08 +0000 (16:15 -0700)
Used by CFI, so broke cfi_test#early_init@x86, but I've added a specific
test for this (and a similar test for getauxval from preinit, which this
patch does not fix).

Bug: http://b/35885875
Test: ran tests

(cherry picked from commit eb04ed506fbb0561b677d9518c9bae33f0262b03)

Change-Id: Ie9da1bf4c2dcc23be7d75c739ae8549309813f88

libc/bionic/libc_init_common.cpp
tests/dl_test.cpp
tests/libs/Android.bp
tests/libs/libs_utils.h
tests/libs/preinit_getauxval_test_helper.cpp [new file with mode: 0644]
tests/libs/preinit_syscall_test_helper.cpp [new file with mode: 0644]

index e5654c3..9094fc5 100644 (file)
@@ -62,7 +62,11 @@ const char* __progname;
 char** environ;
 
 #if defined(__i386__)
-__LIBC_HIDDEN__ void* __libc_sysinfo = nullptr;
+__attribute__((__naked__)) static void __libc_int0x80() {
+  __asm__ volatile("int $0x80; ret");
+}
+
+__LIBC_HIDDEN__ void* __libc_sysinfo = reinterpret_cast<void*>(__libc_int0x80);
 
 __LIBC_HIDDEN__ void __libc_init_sysinfo(KernelArgumentBlock& args) {
   __libc_sysinfo = reinterpret_cast<void*>(args.getauxval(AT_SYSINFO));
index ee9b2e1..aa8bd57 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <string>
 
+#include "gtest_globals.h"
 #include "utils.h"
 
 extern "C" int main_global_default_serial() {
@@ -86,4 +87,26 @@ TEST(dl, exec_linker) {
 #endif
 }
 
+TEST(dl, preinit_system_calls) {
+#if defined(__BIONIC__)
+  std::string helper = get_testlib_root() +
+      "/preinit_syscall_test_helper/preinit_syscall_test_helper";
+  chmod(helper.c_str(), 0755); // TODO: "x" lost in CTS, b/34945607
+  ExecTestHelper eth;
+  eth.SetArgs({ helper.c_str(), nullptr });
+  eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, nullptr);
+#endif
+}
+
+TEST(dl, xfail_preinit_getauxval) {
+#if defined(__BIONIC__)
+  std::string helper = get_testlib_root() +
+      "/preinit_getauxval_test_helper/preinit_getauxval_test_helper";
+  chmod(helper.c_str(), 0755); // TODO: "x" lost in CTS, b/34945607
+  ExecTestHelper eth;
+  eth.SetArgs({ helper.c_str(), nullptr });
+  eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, nullptr);
+#endif
+}
+
 // TODO: Add tests for LD_PRELOADs
index 5eb16c5..a031fe9 100644 (file)
@@ -547,3 +547,17 @@ cc_test {
     shared_libs: ["libcfi-test"],
     ldflags: ["-Wl,--rpath,${ORIGIN}/.."],
 }
+
+cc_test {
+    name: "preinit_getauxval_test_helper",
+    host_supported: false,
+    defaults: ["bionic_testlib_defaults"],
+    srcs: ["preinit_getauxval_test_helper.cpp"],
+}
+
+cc_test {
+    name: "preinit_syscall_test_helper",
+    host_supported: false,
+    defaults: ["bionic_testlib_defaults"],
+    srcs: ["preinit_syscall_test_helper.cpp"],
+}
index f11cbe7..7dae241 100644 (file)
 #ifndef LIBS_UTILS_H
 #define LIBS_UTILS_H
 
+#include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 
-#define CHECK(x)                                                            \
-  do {                                                                      \
-    fprintf(stderr, "CHECK(" #x ") failed at %s:%d\n", __FILE__, __LINE__); \
-    if (!(x)) abort();                                                      \
-  } while (0)
+#define CHECK(e) \
+    ((e) ? static_cast<void>(0) : __assert2(__FILE__, __LINE__, __PRETTY_FUNCTION__, #e))
 
 #endif  // LIBS_UTILS_H
diff --git a/tests/libs/preinit_getauxval_test_helper.cpp b/tests/libs/preinit_getauxval_test_helper.cpp
new file mode 100644 (file)
index 0000000..2a79b97
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 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 <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/auxv.h>
+
+#include "libs_utils.h"
+
+static unsigned long g_AT_RANDOM;
+static unsigned long g_AT_PAGESZ;
+
+static void preinit_ctor() {
+  g_AT_RANDOM = getauxval(AT_RANDOM);
+  g_AT_PAGESZ = getauxval(AT_PAGESZ);
+}
+
+__attribute__((section(".preinit_array"), used)) void (*preinit_ctor_p)(void) = preinit_ctor;
+
+int main() {
+  // Did getauxval during preinit get the same results as getauxval now?
+  CHECK(getauxval(AT_RANDOM) == g_AT_RANDOM);
+  CHECK(getauxval(AT_PAGESZ) == g_AT_PAGESZ);
+  return 0;
+}
diff --git a/tests/libs/preinit_syscall_test_helper.cpp b/tests/libs/preinit_syscall_test_helper.cpp
new file mode 100644 (file)
index 0000000..9b6b6df
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017 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 <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/auxv.h>
+
+#include "libs_utils.h"
+
+static ssize_t g_result;
+static int g_errno;
+
+static void preinit_ctor() {
+  // Can we make a system call?
+  g_result = write(-1, "", 1);
+  g_errno = errno;
+}
+
+__attribute__((section(".preinit_array"), used)) void (*preinit_ctor_p)(void) = preinit_ctor;
+
+int main() {
+  // Did we get the expected failure?
+  CHECK(g_result == -1);
+  CHECK(g_errno == EBADF);
+  return 0;
+}