From d1006fe659c2ba8d30494e28f7080beeb1e04eb4 Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Wed, 8 Nov 2017 18:44:09 +0900 Subject: [PATCH] Support partners to expose their own system libs to Android apps Partners (entities other than AOSP) can expose their own system libraries which are in /system/lib[64] to Android apps. This can be done by adding the name of the libs into the files /system/etc/public.libraries-.txt. There can be multiple of the txt files on a device, which is for the case that multiple partners contributing to the same system image have their own set of public libraries. The public libraries MUST be named as lib..so. This is to prevent accidental exposure of AOSP-defined system private libs. Note 1: doesn't need to be the same as the value of the sysprop ro.product.manufacturer or anything that can be part of a file path. Note 2: This feature is not for exposing SoC-specific libs to Android apps. That is already done by /vendor/etc/public.libraries.txt and is only for libs in /vendor/lib[64]. Bug: 68280171 Test: mm -j under /system/core/libnativeloader/test cts-tradefed run commandAndExit cts-dev -m CtsJniTestCases -t android.jni.cts.JniStaticTest#test_linker_namespaces Change-Id: I7d32ec27c7858e35b96c7c98223cc110acb35b81 --- libnativeloader/native_loader.cpp | 98 +++++++++++++++---- libnativeloader/test/Android.bp | 48 +++++++++ libnativeloader/test/Android.mk | 30 ++++++ .../test/public.libraries-oem1.txt | 2 + .../test/public.libraries-oem2.txt | 2 + libnativeloader/test/test.cpp | 21 ++++ 6 files changed, 183 insertions(+), 18 deletions(-) create mode 100644 libnativeloader/test/Android.bp create mode 100644 libnativeloader/test/Android.mk create mode 100644 libnativeloader/test/public.libraries-oem1.txt create mode 100644 libnativeloader/test/public.libraries-oem2.txt create mode 100644 libnativeloader/test/test.cpp diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp index f3c70de6c..8c8d064a2 100644 --- a/libnativeloader/native_loader.cpp +++ b/libnativeloader/native_loader.cpp @@ -24,12 +24,15 @@ #include "cutils/properties.h" #include "log/log.h" #endif +#include +#include #include "nativebridge/native_bridge.h" #include -#include -#include +#include #include +#include +#include #include #include @@ -82,15 +85,20 @@ class NativeLoaderNamespace { native_bridge_namespace_t* native_bridge_ns_; }; -static constexpr const char* kPublicNativeLibrariesSystemConfigPathFromRoot = - "/etc/public.libraries.txt"; -static constexpr const char* kPublicNativeLibrariesVendorConfig = - "/vendor/etc/public.libraries.txt"; -static constexpr const char* kLlndkNativeLibrariesSystemConfigPathFromRoot = - "/etc/llndk.libraries.txt"; -static constexpr const char* kVndkspNativeLibrariesSystemConfigPathFromRoot = - "/etc/vndksp.libraries.txt"; - +static constexpr const char kPublicNativeLibrariesSystemConfigPathFromRoot[] = + "/etc/public.libraries.txt"; +static constexpr const char kPublicNativeLibrariesExtensionConfigPrefix[] = "public.libraries-"; +static constexpr const size_t kPublicNativeLibrariesExtensionConfigPrefixLen = + sizeof(kPublicNativeLibrariesExtensionConfigPrefix) - 1; +static constexpr const char kPublicNativeLibrariesExtensionConfigSuffix[] = ".txt"; +static constexpr const size_t kPublicNativeLibrariesExtensionConfigSuffixLen = + sizeof(kPublicNativeLibrariesExtensionConfigSuffix) - 1; +static constexpr const char kPublicNativeLibrariesVendorConfig[] = + "/vendor/etc/public.libraries.txt"; +static constexpr const char kLlndkNativeLibrariesSystemConfigPathFromRoot[] = + "/etc/llndk.libraries.txt"; +static constexpr const char kVndkspNativeLibrariesSystemConfigPathFromRoot[] = + "/etc/vndksp.libraries.txt"; // The device may be configured to have the vendor libraries loaded to a separate namespace. // For historical reasons this namespace was named sphal but effectively it is intended @@ -133,6 +141,9 @@ static void insert_vndk_version_str(std::string* file_name) { file_name->insert(insert_pos, vndk_version_str()); } +static const std::function always_true = + [](const std::string&, std::string*) { return true; }; + class LibraryNamespaces { public: LibraryNamespaces() : initialized_(false) { } @@ -337,9 +348,54 @@ class LibraryNamespaces { root_dir + kVndkspNativeLibrariesSystemConfigPathFromRoot; std::string error_msg; - LOG_ALWAYS_FATAL_IF(!ReadConfig(public_native_libraries_system_config, &sonames, &error_msg), - "Error reading public native library list from \"%s\": %s", - public_native_libraries_system_config.c_str(), error_msg.c_str()); + LOG_ALWAYS_FATAL_IF( + !ReadConfig(public_native_libraries_system_config, &sonames, always_true, &error_msg), + "Error reading public native library list from \"%s\": %s", + public_native_libraries_system_config.c_str(), error_msg.c_str()); + + // read /system/etc/public.libraries-.txt which contain partner defined + // system libs that are exposed to apps. The libs in the txt files must be + // named as lib..so. + std::string dirname = base::Dirname(public_native_libraries_system_config); + std::unique_ptr dir(opendir(dirname.c_str()), closedir); + if (dir != nullptr) { + // Failing to opening the dir is not an error, which can happen in + // webview_zygote. + struct dirent* ent; + while ((ent = readdir(dir.get())) != nullptr) { + if (ent->d_type != DT_REG && ent->d_type != DT_LNK) { + continue; + } + const std::string filename(ent->d_name); + if (android::base::StartsWith(filename, kPublicNativeLibrariesExtensionConfigPrefix) && + android::base::EndsWith(filename, kPublicNativeLibrariesExtensionConfigSuffix)) { + const size_t start = kPublicNativeLibrariesExtensionConfigPrefixLen; + const size_t end = filename.size() - kPublicNativeLibrariesExtensionConfigSuffixLen; + const std::string company_name = filename.substr(start, end - start); + const std::string config_file_path = dirname + "/" + filename; + LOG_ALWAYS_FATAL_IF( + company_name.empty(), + "Error extracting company name from public native library list file path \"%s\"", + config_file_path.c_str()); + LOG_ALWAYS_FATAL_IF( + !ReadConfig( + config_file_path, &sonames, + [&company_name](const std::string& soname, std::string* error_msg) { + if (android::base::StartsWith(soname, "lib") && + android::base::EndsWith(soname, ("." + company_name + ".so").c_str())) { + return true; + } else { + *error_msg = "Library name \"" + soname + + "\" does not end with the company name: " + company_name + "."; + return false; + } + }, + &error_msg), + "Error reading public native library list from \"%s\": %s", config_file_path.c_str(), + error_msg.c_str()); + } + } + } // Insert VNDK version to llndk and vndksp config file names. insert_vndk_version_str(&llndk_native_libraries_system_config); @@ -374,16 +430,16 @@ class LibraryNamespaces { system_public_libraries_ = base::Join(sonames, ':'); sonames.clear(); - ReadConfig(llndk_native_libraries_system_config, &sonames); + ReadConfig(llndk_native_libraries_system_config, &sonames, always_true); system_llndk_libraries_ = base::Join(sonames, ':'); sonames.clear(); - ReadConfig(vndksp_native_libraries_system_config, &sonames); + ReadConfig(vndksp_native_libraries_system_config, &sonames, always_true); system_vndksp_libraries_ = base::Join(sonames, ':'); sonames.clear(); // This file is optional, quietly ignore if the file does not exist. - ReadConfig(kPublicNativeLibrariesVendorConfig, &sonames); + ReadConfig(kPublicNativeLibrariesVendorConfig, &sonames, always_true, nullptr); vendor_public_libraries_ = base::Join(sonames, ':'); } @@ -394,6 +450,8 @@ class LibraryNamespaces { private: bool ReadConfig(const std::string& configFile, std::vector* sonames, + const std::function& check_soname, std::string* error_msg = nullptr) { // Read list of public native libraries from the config file. std::string file_content; @@ -430,7 +488,11 @@ class LibraryNamespaces { trimmed_line.resize(space_pos); } - sonames->push_back(trimmed_line); + if (check_soname(trimmed_line, error_msg)) { + sonames->push_back(trimmed_line); + } else { + return false; + } } return true; diff --git a/libnativeloader/test/Android.bp b/libnativeloader/test/Android.bp new file mode 100644 index 000000000..2d3370435 --- /dev/null +++ b/libnativeloader/test/Android.bp @@ -0,0 +1,48 @@ +// +// 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. +// + +cc_library { + name: "libfoo.oem1", + srcs: ["test.cpp"], + cflags : ["-DLIBNAME=\"libfoo.oem1.so\""], + shared_libs: [ + "libbase", + ], +} +cc_library { + name: "libbar.oem1", + srcs: ["test.cpp"], + cflags : ["-DLIBNAME=\"libbar.oem1.so\""], + shared_libs: [ + "libbase", + ], +} +cc_library { + name: "libfoo.oem2", + srcs: ["test.cpp"], + cflags : ["-DLIBNAME=\"libfoo.oem2.so\""], + shared_libs: [ + "libbase", + ], +} +cc_library { + name: "libbar.oem2", + srcs: ["test.cpp"], + cflags : ["-DLIBNAME=\"libbar.oem2.so\""], + shared_libs: [ + "libbase", + ], +} diff --git a/libnativeloader/test/Android.mk b/libnativeloader/test/Android.mk new file mode 100644 index 000000000..4c3da4ac5 --- /dev/null +++ b/libnativeloader/test/Android.mk @@ -0,0 +1,30 @@ +# +# 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. +# +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := public.libraries-oem1.txt +LOCAL_SRC_FILES:= $(LOCAL_MODULE) +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_PATH := $(TARGET_OUT_ETC) +include $(BUILD_PREBUILT) + +include $(CLEAR_VARS) +LOCAL_MODULE := public.libraries-oem2.txt +LOCAL_SRC_FILES:= $(LOCAL_MODULE) +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_PATH := $(TARGET_OUT_ETC) +include $(BUILD_PREBUILT) diff --git a/libnativeloader/test/public.libraries-oem1.txt b/libnativeloader/test/public.libraries-oem1.txt new file mode 100644 index 000000000..f9433e2a0 --- /dev/null +++ b/libnativeloader/test/public.libraries-oem1.txt @@ -0,0 +1,2 @@ +libfoo.oem1.so +libbar.oem1.so diff --git a/libnativeloader/test/public.libraries-oem2.txt b/libnativeloader/test/public.libraries-oem2.txt new file mode 100644 index 000000000..de6bdb08e --- /dev/null +++ b/libnativeloader/test/public.libraries-oem2.txt @@ -0,0 +1,2 @@ +libfoo.oem2.so +libbar.oem2.so diff --git a/libnativeloader/test/test.cpp b/libnativeloader/test/test.cpp new file mode 100644 index 000000000..b166928f0 --- /dev/null +++ b/libnativeloader/test/test.cpp @@ -0,0 +1,21 @@ +/* + * 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. + */ +#define LOG_TAG "oemlib" +#include + +static __attribute__((constructor)) void test_lib_init() { + LOG(DEBUG) << LIBNAME << " loaded"; +}