libc: Add membarrier to common seccomp allowed list
Allows ART JIT use membarrier to invalidate instruction
pipelines.
Bug: 66095511
Test: bionic-unit-tests
Change-Id: I8cf83929f00baf5a3c440a899d2667a992bda8e2
diff --git a/libc/SECCOMP_WHITELIST_COMMON.TXT b/libc/SECCOMP_WHITELIST_COMMON.TXT
index 60568e6..f6e9539 100644
--- a/libc/SECCOMP_WHITELIST_COMMON.TXT
+++ b/libc/SECCOMP_WHITELIST_COMMON.TXT
@@ -59,6 +59,9 @@
# already allowed.
ssize_t readlink:readlink(const char *path, char *buf, size_t bufsiz) arm,x86,x86_64,mips
+# Probed for and conditionally used by ART.
+int membarrier(int cmd, int flags) all
+
# Useful new syscalls which we don't yet use in bionic.
int sched_getattr(pid_t pid, struct sched_attr* attr, unsigned int flags) all
int sched_setattr(pid_t pid, struct sched_attr* attr, unsigned int size, unsigned int flags) all
diff --git a/tests/Android.bp b/tests/Android.bp
index fa66f93..ffa6b2a 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -104,6 +104,7 @@
"malloc_test.cpp",
"math_test.cpp",
"math_force_long_double_test.cpp",
+ "membarrier_test.cpp",
"mntent_test.cpp",
"netdb_test.cpp",
"net_if_test.cpp",
diff --git a/tests/membarrier_test.cpp b/tests/membarrier_test.cpp
new file mode 100644
index 0000000..4c58d30
--- /dev/null
+++ b/tests/membarrier_test.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2018 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 <gtest/gtest.h>
+
+// membarrier(2) is only supported for bionic builds (b/111199492).
+#if defined(__BIONIC__)
+
+#include <linux/membarrier.h>
+#include <sys/syscall.h>
+
+class ScopedErrnoCleaner {
+ public:
+ ScopedErrnoCleaner() { errno = 0; }
+ ~ScopedErrnoCleaner() { errno = 0; }
+};
+
+bool HasMembarrier() {
+ ScopedErrnoCleaner errno_cleaner;
+ bool present = syscall(__NR_membarrier, MEMBARRIER_CMD_QUERY, 0) > 0;
+ return present;
+}
+
+TEST(membarrier, query) {
+ ScopedErrnoCleaner errno_cleaner;
+ int supported = syscall(__NR_membarrier, MEMBARRIER_CMD_QUERY, 0);
+ if (errno == 0) {
+ ASSERT_TRUE(supported >= 0);
+ } else {
+ ASSERT_TRUE(errno == ENOSYS && supported == -1);
+ }
+}
+
+TEST(membarrier, global_barrier) {
+ if (!HasMembarrier()) {
+ return;
+ }
+
+ ScopedErrnoCleaner errno_cleaner;
+ int supported = syscall(__NR_membarrier, MEMBARRIER_CMD_QUERY, 0);
+ ASSERT_LE(0, supported);
+
+ if ((supported & MEMBARRIER_CMD_GLOBAL) != 0) {
+ ASSERT_EQ(0, syscall(__NR_membarrier, MEMBARRIER_CMD_GLOBAL, 0));
+ }
+}
+
+static void TestRegisterAndBarrierCommands(int membarrier_cmd_register,
+ int membarrier_cmd_barrier) {
+ if (!HasMembarrier()) {
+ return;
+ }
+
+ ScopedErrnoCleaner errno_cleaner;
+
+ // Check barrier use without prior registration.
+ if (membarrier_cmd_register == MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED) {
+ // Global barrier use is always okay.
+ ASSERT_EQ(0, syscall(__NR_membarrier, membarrier_cmd_barrier, 0));
+ } else {
+ // Private barrier should fail.
+ ASSERT_EQ(-1, syscall(__NR_membarrier, membarrier_cmd_barrier, 0));
+ ASSERT_EQ(EPERM, errno);
+ errno = 0;
+ }
+
+ // Check registration for barrier succeeds.
+ ASSERT_EQ(0, syscall(__NR_membarrier, membarrier_cmd_register, 0));
+
+ // Check barrier use after registration succeeds.
+ ASSERT_EQ(0, syscall(__NR_membarrier, membarrier_cmd_barrier, 0));
+}
+
+TEST(membarrier, global_expedited) {
+ TestRegisterAndBarrierCommands(MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED,
+ MEMBARRIER_CMD_GLOBAL_EXPEDITED);
+}
+
+TEST(membarrier, private_expedited) {
+ TestRegisterAndBarrierCommands(MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED,
+ MEMBARRIER_CMD_PRIVATE_EXPEDITED);
+}
+
+TEST(membarrier, private_expedited_sync_core) {
+ TestRegisterAndBarrierCommands(MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE,
+ MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE);
+}
+
+#endif // __BIONIC__