diff options
author | Lev Rumyantsev <levarum@google.com> | 2019-12-13 15:49:37 -0800 |
---|---|---|
committer | Lev Rumyantsev <levarum@google.com> | 2020-01-21 23:09:34 +0000 |
commit | abafbe759a354dd6c6d81d4aba3f0aec9aca3d5b (patch) | |
tree | abd0c540ee97708916450c07bc37d4cd5229a902 /libnativebridge | |
parent | 7ec3e60dd656509f4346fc94968f9de22cedcaaf (diff) |
nativebridge: Add PreZygoteFork callback
It's required to clean-up the emulated enviroment (e.g. close file
descriptors) after emulated execution in doPreload() in app-zygote.
Test: NativeBridge6PreZygoteFork_test
Test: CtsSeccompHostTestCases
android.seccomp.cts.SeccompHostJUnit4DeviceTest
testAppZygoteSyscalls
both for Q.sdk_gphone_x86_arm.armeabi-v7a
Bug: 146904103
Change-Id: Id192a1647c2f405570bf196daf65b3f2a9faca42
Diffstat (limited to 'libnativebridge')
-rw-r--r-- | libnativebridge/include/nativebridge/native_bridge.h | 8 | ||||
-rw-r--r-- | libnativebridge/libnativebridge.map.txt | 1 | ||||
-rw-r--r-- | libnativebridge/native_bridge.cc | 13 | ||||
-rw-r--r-- | libnativebridge/native_bridge_lazy.cc | 5 | ||||
-rw-r--r-- | libnativebridge/tests/Android.bp | 18 | ||||
-rw-r--r-- | libnativebridge/tests/DummyNativeBridge6.cpp | 133 | ||||
-rw-r--r-- | libnativebridge/tests/NativeBridge6PreZygoteFork_lib.cpp | 29 | ||||
-rw-r--r-- | libnativebridge/tests/NativeBridge6PreZygoteFork_lib.h | 27 | ||||
-rw-r--r-- | libnativebridge/tests/NativeBridge6PreZygoteFork_test.cpp | 40 |
9 files changed, 274 insertions, 0 deletions
diff --git a/libnativebridge/include/nativebridge/native_bridge.h b/libnativebridge/include/nativebridge/native_bridge.h index 22c128ba1f..e20b6270a1 100644 --- a/libnativebridge/include/nativebridge/native_bridge.h +++ b/libnativebridge/include/nativebridge/native_bridge.h @@ -50,6 +50,10 @@ bool NeedsNativeBridge(const char* instruction_set); // high privileges. bool PreInitializeNativeBridge(const char* app_data_dir, const char* instruction_set); +// Prepare to fork from zygote. May be required to clean-up the enviroment, e.g. +// close emulated file descriptors, after doPreload() in app-zygote. +void PreZygoteForkNativeBridge(); + // Initialize the native bridge, if any. Should be called by Runtime::DidForkFromZygote. The JNIEnv* // will be used to modify the app environment for the bridge. bool InitializeNativeBridge(JNIEnv* env, const char* instruction_set); @@ -374,6 +378,10 @@ struct NativeBridgeCallbacks { // Returns: // exported namespace or null if it was not set up for the device struct native_bridge_namespace_t* (*getExportedNamespace)(const char* name); + + // If native bridge is used in app-zygote (in doPreload()) this callback is + // required to clean-up the environment before the fork (see b/146904103). + void (*preZygoteFork)(); }; // Runtime interfaces to native bridge. diff --git a/libnativebridge/libnativebridge.map.txt b/libnativebridge/libnativebridge.map.txt index a6841a3a81..158363b0f0 100644 --- a/libnativebridge/libnativebridge.map.txt +++ b/libnativebridge/libnativebridge.map.txt @@ -32,6 +32,7 @@ LIBNATIVEBRIDGE_1 { NativeBridgeGetTrampoline; LoadNativeBridge; PreInitializeNativeBridge; + PreZygoteForkNativeBridge; InitializeNativeBridge; NativeBridgeGetVersion; NativeBridgeGetSignalHandler; diff --git a/libnativebridge/native_bridge.cc b/libnativebridge/native_bridge.cc index 1a54ace2e0..b24d14ade2 100644 --- a/libnativebridge/native_bridge.cc +++ b/libnativebridge/native_bridge.cc @@ -103,6 +103,8 @@ enum NativeBridgeImplementationVersion { VENDOR_NAMESPACE_VERSION = 4, // The version with runtime namespaces RUNTIME_NAMESPACE_VERSION = 5, + // The version with pre-zygote-fork hook to support app-zygotes. + PRE_ZYGOTE_FORK_VERSION = 6, }; // Whether we had an error at some point. @@ -328,6 +330,17 @@ bool PreInitializeNativeBridge(const char* app_data_dir_in, const char* instruct return true; } +void PreZygoteForkNativeBridge() { + if (NativeBridgeInitialized()) { + if (isCompatibleWith(PRE_ZYGOTE_FORK_VERSION)) { + return callbacks->preZygoteFork(); + } else { + ALOGE("not compatible with version %d, preZygoteFork() isn't invoked", + PRE_ZYGOTE_FORK_VERSION); + } + } +} + static void SetCpuAbi(JNIEnv* env, jclass build_class, const char* field, const char* value) { if (value != nullptr) { jfieldID field_id = env->GetStaticFieldID(build_class, field, "Ljava/lang/String;"); diff --git a/libnativebridge/native_bridge_lazy.cc b/libnativebridge/native_bridge_lazy.cc index 94c80848ee..edc7848bba 100644 --- a/libnativebridge/native_bridge_lazy.cc +++ b/libnativebridge/native_bridge_lazy.cc @@ -60,6 +60,11 @@ bool PreInitializeNativeBridge(const char* app_data_dir, const char* instruction return f(app_data_dir, instruction_set); } +void PreZygoteForkNativeBridge() { + static auto f = GET_FUNC_PTR(PreZygoteForkNativeBridge); + return f(); +} + bool InitializeNativeBridge(JNIEnv* env, const char* instruction_set) { static auto f = GET_FUNC_PTR(InitializeNativeBridge); return f(env, instruction_set); diff --git a/libnativebridge/tests/Android.bp b/libnativebridge/tests/Android.bp index 92116340b3..4ccf35e7d8 100644 --- a/libnativebridge/tests/Android.bp +++ b/libnativebridge/tests/Android.bp @@ -54,6 +54,22 @@ cc_library_shared { defaults: ["libnativebridge-dummy-defaults"], } +cc_library_shared { + name: "libnativebridge6-dummy", + srcs: ["DummyNativeBridge6.cpp"], + defaults: ["libnativebridge-dummy-defaults"], + shared_libs: [ + "libnativebridge6prezygotefork", + ], +} + +// A helper library to produce dummy side effect of PreZygoteForkNativeBridge. +cc_library_shared { + name: "libnativebridge6prezygotefork", + srcs: ["NativeBridge6PreZygoteFork_lib.cpp"], + defaults: ["libnativebridge-dummy-defaults"], +} + // Build the unit tests. cc_defaults { name: "libnativebridge-tests-defaults", @@ -96,11 +112,13 @@ cc_defaults { "NativeBridge3InitAnonymousNamespace_test.cpp", "NativeBridge3CreateNamespace_test.cpp", "NativeBridge3LoadLibraryExt_test.cpp", + "NativeBridge6PreZygoteFork_test.cpp", ], shared_libs: [ "liblog", "libnativebridge-dummy", + "libnativebridge6prezygotefork", ], header_libs: ["libbase_headers"], } diff --git a/libnativebridge/tests/DummyNativeBridge6.cpp b/libnativebridge/tests/DummyNativeBridge6.cpp new file mode 100644 index 0000000000..ce27e67d14 --- /dev/null +++ b/libnativebridge/tests/DummyNativeBridge6.cpp @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2020 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. + */ + +// A dummy implementation of the native-bridge interface. + +#include "nativebridge/native_bridge.h" + +#include "NativeBridge6PreZygoteFork_lib.h" + +// NativeBridgeCallbacks implementations +extern "C" bool native_bridge6_initialize( + const android::NativeBridgeRuntimeCallbacks* /* art_cbs */, + const char* /* app_code_cache_dir */, + const char* /* isa */) { + return true; +} + +extern "C" void* native_bridge6_loadLibrary(const char* /* libpath */, int /* flag */) { + return nullptr; +} + +extern "C" void* native_bridge6_getTrampoline(void* /* handle */, const char* /* name */, + const char* /* shorty */, uint32_t /* len */) { + return nullptr; +} + +extern "C" bool native_bridge6_isSupported(const char* /* libpath */) { + return false; +} + +extern "C" const struct android::NativeBridgeRuntimeValues* native_bridge6_getAppEnv( + const char* /* abi */) { + return nullptr; +} + +extern "C" bool native_bridge6_isCompatibleWith(uint32_t version) { + // For testing, allow 1-6, but disallow 7+. + return version <= 6; +} + +extern "C" android::NativeBridgeSignalHandlerFn native_bridge6_getSignalHandler(int /* signal */) { + return nullptr; +} + +extern "C" int native_bridge6_unloadLibrary(void* /* handle */) { + return 0; +} + +extern "C" const char* native_bridge6_getError() { + return nullptr; +} + +extern "C" bool native_bridge6_isPathSupported(const char* /* path */) { + return true; +} + +extern "C" bool native_bridge6_initAnonymousNamespace(const char* /* public_ns_sonames */, + const char* /* anon_ns_library_path */) { + return true; +} + +extern "C" android::native_bridge_namespace_t* +native_bridge6_createNamespace(const char* /* name */, + const char* /* ld_library_path */, + const char* /* default_library_path */, + uint64_t /* type */, + const char* /* permitted_when_isolated_path */, + android::native_bridge_namespace_t* /* parent_ns */) { + return nullptr; +} + +extern "C" bool native_bridge6_linkNamespaces(android::native_bridge_namespace_t* /* from */, + android::native_bridge_namespace_t* /* to */, + const char* /* shared_libs_soname */) { + return true; +} + +extern "C" void* native_bridge6_loadLibraryExt(const char* /* libpath */, + int /* flag */, + android::native_bridge_namespace_t* /* ns */) { + return nullptr; +} + +extern "C" android::native_bridge_namespace_t* native_bridge6_getVendorNamespace() { + return nullptr; +} + +extern "C" android::native_bridge_namespace_t* native_bridge6_getExportedNamespace(const char* /* name */) { + return nullptr; +} + +extern "C" void native_bridge6_preZygoteFork() { + android::SetPreZygoteForkDone(); +} + +android::NativeBridgeCallbacks NativeBridgeItf{ + // v1 + .version = 6, + .initialize = &native_bridge6_initialize, + .loadLibrary = &native_bridge6_loadLibrary, + .getTrampoline = &native_bridge6_getTrampoline, + .isSupported = &native_bridge6_isSupported, + .getAppEnv = &native_bridge6_getAppEnv, + // v2 + .isCompatibleWith = &native_bridge6_isCompatibleWith, + .getSignalHandler = &native_bridge6_getSignalHandler, + // v3 + .unloadLibrary = &native_bridge6_unloadLibrary, + .getError = &native_bridge6_getError, + .isPathSupported = &native_bridge6_isPathSupported, + .initAnonymousNamespace = &native_bridge6_initAnonymousNamespace, + .createNamespace = &native_bridge6_createNamespace, + .linkNamespaces = &native_bridge6_linkNamespaces, + .loadLibraryExt = &native_bridge6_loadLibraryExt, + // v4 + &native_bridge6_getVendorNamespace, + // v5 + &native_bridge6_getExportedNamespace, + // v6 + &native_bridge6_preZygoteFork}; diff --git a/libnativebridge/tests/NativeBridge6PreZygoteFork_lib.cpp b/libnativebridge/tests/NativeBridge6PreZygoteFork_lib.cpp new file mode 100644 index 0000000000..0da5bb6c29 --- /dev/null +++ b/libnativebridge/tests/NativeBridge6PreZygoteFork_lib.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2020 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. + */ + +namespace android { + +static bool g_pre_zygote_fork_done = false; + +bool IsPreZygoteForkDone() { + return g_pre_zygote_fork_done; +} + +void SetPreZygoteForkDone() { + g_pre_zygote_fork_done = true; +} + +} // namespace android diff --git a/libnativebridge/tests/NativeBridge6PreZygoteFork_lib.h b/libnativebridge/tests/NativeBridge6PreZygoteFork_lib.h new file mode 100644 index 0000000000..bcbf0d3a2a --- /dev/null +++ b/libnativebridge/tests/NativeBridge6PreZygoteFork_lib.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2020 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 ART_LIBNATIVEBRIDGE_TESTS_NATIVEBRIDGE6PREZYGOTEFORK_LIB_H_ +#define ART_LIBNATIVEBRIDGE_TESTS_NATIVEBRIDGE6PREZYGOTEFORK_LIB_H_ + +namespace android { + +bool IsPreZygoteForkDone(); +void SetPreZygoteForkDone(); + +} // namespace android + +#endif // ART_LIBNATIVEBRIDGE_TESTS_NATIVEBRIDGE6PREZYGOTEFORK_LIB_H_ diff --git a/libnativebridge/tests/NativeBridge6PreZygoteFork_test.cpp b/libnativebridge/tests/NativeBridge6PreZygoteFork_test.cpp new file mode 100644 index 0000000000..9e348a2d26 --- /dev/null +++ b/libnativebridge/tests/NativeBridge6PreZygoteFork_test.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2020 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 "NativeBridgeTest.h" +#include "NativeBridge6PreZygoteFork_lib.h" + +namespace android { + +constexpr const char* kNativeBridgeLibrary6 = "libnativebridge6-dummy.so"; + +TEST_F(NativeBridgeTest, V6_PreZygoteFork) { + // Init + ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary6, nullptr)); + ASSERT_TRUE(NativeBridgeAvailable()); + ASSERT_TRUE(PreInitializeNativeBridge(".", "isa")); + ASSERT_TRUE(NativeBridgeAvailable()); + ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr)); + ASSERT_TRUE(NativeBridgeAvailable()); + + ASSERT_EQ(6U, NativeBridgeGetVersion()); + + ASSERT_FALSE(IsPreZygoteForkDone()); + PreZygoteForkNativeBridge(); + ASSERT_TRUE(IsPreZygoteForkDone()); +} + +} // namespace android |