Loading cmds/servicemanager/Android.bp +10 −0 Original line number Diff line number Diff line Loading @@ -95,6 +95,16 @@ cc_test { static_libs: ["libgmock"], } cc_test_host { name: "servicemanager_unittest", test_suites: ["general-tests"], defaults: ["servicemanager_defaults"], srcs: [ "ServiceManagerUnittest.cpp", ], static_libs: ["libgmock"], } cc_fuzz { name: "servicemanager_fuzzer", defaults: [ Loading cmds/servicemanager/NameUtil.h 0 → 100644 +58 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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. */ #pragma once #include <string> #include <string_view> #include <android-base/strings.h> namespace android { #ifndef VENDORSERVICEMANAGER struct NativeName { std::string package; std::string instance; // Parse {package}/{instance} static bool fill(std::string_view name, NativeName* nname) { size_t slash = name.find('/'); if (slash == std::string_view::npos) { return false; } // no extra slashes if (name.find('/', slash + 1) != std::string_view::npos) { return false; } // every part should be non-empty if (slash == 0 || slash + 1 == name.size()) { return false; } // no dots in package if (name.rfind('.', slash) != std::string_view::npos) { return false; } nname->package = name.substr(0, slash); nname->instance = name.substr(slash + 1); return true; } }; #endif } // namespace android cmds/servicemanager/ServiceManager.cpp +70 −14 Original line number Diff line number Diff line Loading @@ -35,6 +35,8 @@ #include <vintf/constants.h> #endif // !VENDORSERVICEMANAGER #include "NameUtil.h" using ::android::binder::Status; using ::android::internal::Stability; Loading Loading @@ -84,6 +86,10 @@ static bool forEachManifest(const std::function<bool(const ManifestWithDescripti return false; } static std::string getNativeInstanceName(const vintf::ManifestInstance& instance) { return instance.package() + "/" + instance.instance(); } struct AidlName { std::string package; std::string iface; Loading @@ -105,7 +111,26 @@ struct AidlName { } }; static std::string getAidlInstanceName(const vintf::ManifestInstance& instance) { return instance.package() + "." + instance.interface() + "/" + instance.instance(); } static bool isVintfDeclared(const std::string& name) { NativeName nname; if (NativeName::fill(name, &nname)) { bool found = forEachManifest([&](const ManifestWithDescription& mwd) { if (mwd.manifest->hasNativeInstance(nname.package, nname.instance)) { ALOGI("Found %s in %s VINTF manifest.", name.c_str(), mwd.description); return true; // break } return false; // continue }); if (!found) { ALOGI("Could not find %s in the VINTF manifest.", name.c_str()); } return found; } AidlName aname; if (!AidlName::fill(name, &aname)) return false; Loading Loading @@ -144,6 +169,24 @@ static bool isVintfDeclared(const std::string& name) { } static std::optional<std::string> getVintfUpdatableApex(const std::string& name) { NativeName nname; if (NativeName::fill(name, &nname)) { std::optional<std::string> updatableViaApex; forEachManifest([&](const ManifestWithDescription& mwd) { bool cont = mwd.manifest->forEachInstance([&](const auto& manifestInstance) { if (manifestInstance.format() != vintf::HalFormat::NATIVE) return true; if (manifestInstance.package() != nname.package) return true; if (manifestInstance.instance() != nname.instance) return true; updatableViaApex = manifestInstance.updatableViaApex(); return false; // break (libvintf uses opposite convention) }); return !cont; }); return updatableViaApex; } AidlName aname; if (!AidlName::fill(name, &aname)) return std::nullopt; Loading @@ -164,24 +207,25 @@ static std::optional<std::string> getVintfUpdatableApex(const std::string& name) return updatableViaApex; } static std::vector<std::string> getVintfUpdatableInstances(const std::string& apexName) { std::vector<std::string> instances; static std::vector<std::string> getVintfUpdatableNames(const std::string& apexName) { std::vector<std::string> names; forEachManifest([&](const ManifestWithDescription& mwd) { mwd.manifest->forEachInstance([&](const auto& manifestInstance) { if (manifestInstance.format() == vintf::HalFormat::AIDL && manifestInstance.updatableViaApex().has_value() && if (manifestInstance.updatableViaApex().has_value() && manifestInstance.updatableViaApex().value() == apexName) { std::string aname = manifestInstance.package() + "." + manifestInstance.interface() + "/" + manifestInstance.instance(); instances.push_back(aname); if (manifestInstance.format() == vintf::HalFormat::NATIVE) { names.push_back(getNativeInstanceName(manifestInstance)); } else if (manifestInstance.format() == vintf::HalFormat::AIDL) { names.push_back(getAidlInstanceName(manifestInstance)); } } return true; // continue (libvintf uses opposite convention) }); return false; // continue }); return instances; return names; } static std::optional<ConnectionInfo> getVintfConnectionInfo(const std::string& name) { Loading Loading @@ -216,6 +260,18 @@ static std::optional<ConnectionInfo> getVintfConnectionInfo(const std::string& n static std::vector<std::string> getVintfInstances(const std::string& interface) { size_t lastDot = interface.rfind('.'); if (lastDot == std::string::npos) { // This might be a package for native instance. std::vector<std::string> ret; (void)forEachManifest([&](const ManifestWithDescription& mwd) { auto instances = mwd.manifest->getNativeInstances(interface); ret.insert(ret.end(), instances.begin(), instances.end()); return false; // continue }); // If found, return it without error log. if (!ret.empty()) { return ret; } ALOGE("VINTF interfaces require names in Java package format (e.g. some.package.foo.IFoo) " "but got: %s", interface.c_str()); Loading Loading @@ -593,20 +649,20 @@ Status ServiceManager::getUpdatableNames([[maybe_unused]] const std::string& ape std::vector<std::string>* outReturn) { auto ctx = mAccess->getCallingContext(); std::vector<std::string> apexUpdatableInstances; std::vector<std::string> apexUpdatableNames; #ifndef VENDORSERVICEMANAGER apexUpdatableInstances = getVintfUpdatableInstances(apexName); apexUpdatableNames = getVintfUpdatableNames(apexName); #endif outReturn->clear(); for (const std::string& instance : apexUpdatableInstances) { if (mAccess->canFind(ctx, instance)) { outReturn->push_back(instance); for (const std::string& name : apexUpdatableNames) { if (mAccess->canFind(ctx, name)) { outReturn->push_back(name); } } if (outReturn->size() == 0 && apexUpdatableInstances.size() != 0) { if (outReturn->size() == 0 && apexUpdatableNames.size() != 0) { return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denied."); } Loading cmds/servicemanager/ServiceManagerUnittest.cpp 0 → 100644 +39 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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> #include "NameUtil.h" namespace android { TEST(ServiceManager, NativeName) { NativeName nname; EXPECT_TRUE(NativeName::fill("mapper/default", &nname)); EXPECT_EQ("mapper", nname.package); EXPECT_EQ("default", nname.instance); } TEST(ServiceManager, NativeName_Malformed) { NativeName nname; EXPECT_FALSE(NativeName::fill("mapper", &nname)); EXPECT_FALSE(NativeName::fill("mapper/", &nname)); EXPECT_FALSE(NativeName::fill("/default", &nname)); EXPECT_FALSE(NativeName::fill("mapper/default/0", &nname)); EXPECT_FALSE(NativeName::fill("aidl.like.IType/default", &nname)); } } // namespace android cmds/servicemanager/test_sm.cpp +18 −0 Original line number Diff line number Diff line Loading @@ -361,6 +361,24 @@ TEST(Vintf, GetUpdatableNames_InvalidApexNameReturnsEmpty) { EXPECT_EQ(std::vector<std::string>{}, names); } TEST(Vintf, IsDeclared_native) { if (!isCuttlefishPhone()) GTEST_SKIP() << "Skipping non-Cuttlefish-phone devices"; auto sm = getPermissiveServiceManager(); bool declared = false; EXPECT_TRUE(sm->isDeclared("mapper/minigbm", &declared).isOk()); EXPECT_TRUE(declared); } TEST(Vintf, GetDeclaredInstances_native) { if (!isCuttlefishPhone()) GTEST_SKIP() << "Skipping non-Cuttlefish-phone devices"; auto sm = getPermissiveServiceManager(); std::vector<std::string> instances; EXPECT_TRUE(sm->getDeclaredInstances("mapper", &instances).isOk()); EXPECT_EQ(std::vector<std::string>{"minigbm"}, instances); } class CallbackHistorian : public BnServiceCallback { Status onRegistration(const std::string& name, const sp<IBinder>& binder) override { registrations.push_back(name); Loading Loading
cmds/servicemanager/Android.bp +10 −0 Original line number Diff line number Diff line Loading @@ -95,6 +95,16 @@ cc_test { static_libs: ["libgmock"], } cc_test_host { name: "servicemanager_unittest", test_suites: ["general-tests"], defaults: ["servicemanager_defaults"], srcs: [ "ServiceManagerUnittest.cpp", ], static_libs: ["libgmock"], } cc_fuzz { name: "servicemanager_fuzzer", defaults: [ Loading
cmds/servicemanager/NameUtil.h 0 → 100644 +58 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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. */ #pragma once #include <string> #include <string_view> #include <android-base/strings.h> namespace android { #ifndef VENDORSERVICEMANAGER struct NativeName { std::string package; std::string instance; // Parse {package}/{instance} static bool fill(std::string_view name, NativeName* nname) { size_t slash = name.find('/'); if (slash == std::string_view::npos) { return false; } // no extra slashes if (name.find('/', slash + 1) != std::string_view::npos) { return false; } // every part should be non-empty if (slash == 0 || slash + 1 == name.size()) { return false; } // no dots in package if (name.rfind('.', slash) != std::string_view::npos) { return false; } nname->package = name.substr(0, slash); nname->instance = name.substr(slash + 1); return true; } }; #endif } // namespace android
cmds/servicemanager/ServiceManager.cpp +70 −14 Original line number Diff line number Diff line Loading @@ -35,6 +35,8 @@ #include <vintf/constants.h> #endif // !VENDORSERVICEMANAGER #include "NameUtil.h" using ::android::binder::Status; using ::android::internal::Stability; Loading Loading @@ -84,6 +86,10 @@ static bool forEachManifest(const std::function<bool(const ManifestWithDescripti return false; } static std::string getNativeInstanceName(const vintf::ManifestInstance& instance) { return instance.package() + "/" + instance.instance(); } struct AidlName { std::string package; std::string iface; Loading @@ -105,7 +111,26 @@ struct AidlName { } }; static std::string getAidlInstanceName(const vintf::ManifestInstance& instance) { return instance.package() + "." + instance.interface() + "/" + instance.instance(); } static bool isVintfDeclared(const std::string& name) { NativeName nname; if (NativeName::fill(name, &nname)) { bool found = forEachManifest([&](const ManifestWithDescription& mwd) { if (mwd.manifest->hasNativeInstance(nname.package, nname.instance)) { ALOGI("Found %s in %s VINTF manifest.", name.c_str(), mwd.description); return true; // break } return false; // continue }); if (!found) { ALOGI("Could not find %s in the VINTF manifest.", name.c_str()); } return found; } AidlName aname; if (!AidlName::fill(name, &aname)) return false; Loading Loading @@ -144,6 +169,24 @@ static bool isVintfDeclared(const std::string& name) { } static std::optional<std::string> getVintfUpdatableApex(const std::string& name) { NativeName nname; if (NativeName::fill(name, &nname)) { std::optional<std::string> updatableViaApex; forEachManifest([&](const ManifestWithDescription& mwd) { bool cont = mwd.manifest->forEachInstance([&](const auto& manifestInstance) { if (manifestInstance.format() != vintf::HalFormat::NATIVE) return true; if (manifestInstance.package() != nname.package) return true; if (manifestInstance.instance() != nname.instance) return true; updatableViaApex = manifestInstance.updatableViaApex(); return false; // break (libvintf uses opposite convention) }); return !cont; }); return updatableViaApex; } AidlName aname; if (!AidlName::fill(name, &aname)) return std::nullopt; Loading @@ -164,24 +207,25 @@ static std::optional<std::string> getVintfUpdatableApex(const std::string& name) return updatableViaApex; } static std::vector<std::string> getVintfUpdatableInstances(const std::string& apexName) { std::vector<std::string> instances; static std::vector<std::string> getVintfUpdatableNames(const std::string& apexName) { std::vector<std::string> names; forEachManifest([&](const ManifestWithDescription& mwd) { mwd.manifest->forEachInstance([&](const auto& manifestInstance) { if (manifestInstance.format() == vintf::HalFormat::AIDL && manifestInstance.updatableViaApex().has_value() && if (manifestInstance.updatableViaApex().has_value() && manifestInstance.updatableViaApex().value() == apexName) { std::string aname = manifestInstance.package() + "." + manifestInstance.interface() + "/" + manifestInstance.instance(); instances.push_back(aname); if (manifestInstance.format() == vintf::HalFormat::NATIVE) { names.push_back(getNativeInstanceName(manifestInstance)); } else if (manifestInstance.format() == vintf::HalFormat::AIDL) { names.push_back(getAidlInstanceName(manifestInstance)); } } return true; // continue (libvintf uses opposite convention) }); return false; // continue }); return instances; return names; } static std::optional<ConnectionInfo> getVintfConnectionInfo(const std::string& name) { Loading Loading @@ -216,6 +260,18 @@ static std::optional<ConnectionInfo> getVintfConnectionInfo(const std::string& n static std::vector<std::string> getVintfInstances(const std::string& interface) { size_t lastDot = interface.rfind('.'); if (lastDot == std::string::npos) { // This might be a package for native instance. std::vector<std::string> ret; (void)forEachManifest([&](const ManifestWithDescription& mwd) { auto instances = mwd.manifest->getNativeInstances(interface); ret.insert(ret.end(), instances.begin(), instances.end()); return false; // continue }); // If found, return it without error log. if (!ret.empty()) { return ret; } ALOGE("VINTF interfaces require names in Java package format (e.g. some.package.foo.IFoo) " "but got: %s", interface.c_str()); Loading Loading @@ -593,20 +649,20 @@ Status ServiceManager::getUpdatableNames([[maybe_unused]] const std::string& ape std::vector<std::string>* outReturn) { auto ctx = mAccess->getCallingContext(); std::vector<std::string> apexUpdatableInstances; std::vector<std::string> apexUpdatableNames; #ifndef VENDORSERVICEMANAGER apexUpdatableInstances = getVintfUpdatableInstances(apexName); apexUpdatableNames = getVintfUpdatableNames(apexName); #endif outReturn->clear(); for (const std::string& instance : apexUpdatableInstances) { if (mAccess->canFind(ctx, instance)) { outReturn->push_back(instance); for (const std::string& name : apexUpdatableNames) { if (mAccess->canFind(ctx, name)) { outReturn->push_back(name); } } if (outReturn->size() == 0 && apexUpdatableInstances.size() != 0) { if (outReturn->size() == 0 && apexUpdatableNames.size() != 0) { return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denied."); } Loading
cmds/servicemanager/ServiceManagerUnittest.cpp 0 → 100644 +39 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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> #include "NameUtil.h" namespace android { TEST(ServiceManager, NativeName) { NativeName nname; EXPECT_TRUE(NativeName::fill("mapper/default", &nname)); EXPECT_EQ("mapper", nname.package); EXPECT_EQ("default", nname.instance); } TEST(ServiceManager, NativeName_Malformed) { NativeName nname; EXPECT_FALSE(NativeName::fill("mapper", &nname)); EXPECT_FALSE(NativeName::fill("mapper/", &nname)); EXPECT_FALSE(NativeName::fill("/default", &nname)); EXPECT_FALSE(NativeName::fill("mapper/default/0", &nname)); EXPECT_FALSE(NativeName::fill("aidl.like.IType/default", &nname)); } } // namespace android
cmds/servicemanager/test_sm.cpp +18 −0 Original line number Diff line number Diff line Loading @@ -361,6 +361,24 @@ TEST(Vintf, GetUpdatableNames_InvalidApexNameReturnsEmpty) { EXPECT_EQ(std::vector<std::string>{}, names); } TEST(Vintf, IsDeclared_native) { if (!isCuttlefishPhone()) GTEST_SKIP() << "Skipping non-Cuttlefish-phone devices"; auto sm = getPermissiveServiceManager(); bool declared = false; EXPECT_TRUE(sm->isDeclared("mapper/minigbm", &declared).isOk()); EXPECT_TRUE(declared); } TEST(Vintf, GetDeclaredInstances_native) { if (!isCuttlefishPhone()) GTEST_SKIP() << "Skipping non-Cuttlefish-phone devices"; auto sm = getPermissiveServiceManager(); std::vector<std::string> instances; EXPECT_TRUE(sm->getDeclaredInstances("mapper", &instances).isOk()); EXPECT_EQ(std::vector<std::string>{"minigbm"}, instances); } class CallbackHistorian : public BnServiceCallback { Status onRegistration(const std::string& name, const sp<IBinder>& binder) override { registrations.push_back(name); Loading