xref: /aosp_15_r20/system/linkerconfig/modules/tests/section_test.cc (revision e5eeaa8e05bc25a862c0c861bda7c8a6bfb42dad)
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "linkerconfig/section.h"
18 
19 #include <android-base/result.h>
20 #include <gmock/gmock.h>
21 #include <gtest/gtest.h>
22 
23 #include "linkerconfig/apex.h"
24 #include "linkerconfig/basecontext.h"
25 #include "linkerconfig/configwriter.h"
26 #include "linkerconfig/variables.h"
27 #include "modules_testbase.h"
28 
29 using namespace android::linkerconfig::modules;
30 
31 constexpr const char* kSectionWithNamespacesExpectedResult =
32     R"([test_section]
33 additional.namespaces = namespace1,namespace2
34 namespace.default.isolated = true
35 namespace.default.visible = true
36 namespace.default.search.paths = /search_path1
37 namespace.default.search.paths += /apex/search_path2
38 namespace.default.permitted.paths = /permitted_path1
39 namespace.default.permitted.paths += /apex/permitted_path2
40 namespace.default.asan.search.paths = /data/asan/search_path1
41 namespace.default.asan.search.paths += /search_path1
42 namespace.default.asan.search.paths += /apex/search_path2
43 namespace.default.asan.permitted.paths = /data/asan/permitted_path1
44 namespace.default.asan.permitted.paths += /permitted_path1
45 namespace.default.asan.permitted.paths += /apex/permitted_path2
46 namespace.default.hwasan.search.paths = /search_path1/hwasan
47 namespace.default.hwasan.search.paths += /search_path1
48 namespace.default.hwasan.search.paths += /apex/search_path2/hwasan
49 namespace.default.hwasan.search.paths += /apex/search_path2
50 namespace.default.hwasan.permitted.paths = /permitted_path1/hwasan
51 namespace.default.hwasan.permitted.paths += /permitted_path1
52 namespace.default.hwasan.permitted.paths += /apex/permitted_path2/hwasan
53 namespace.default.hwasan.permitted.paths += /apex/permitted_path2
54 namespace.default.links = namespace1,namespace2
55 namespace.default.link.namespace1.shared_libs = lib1.so:lib2.so:lib3.so
56 namespace.default.link.namespace2.allow_all_shared_libs = true
57 namespace.namespace1.isolated = false
58 namespace.namespace1.search.paths = /search_path1
59 namespace.namespace1.search.paths += /apex/search_path2
60 namespace.namespace1.permitted.paths = /permitted_path1
61 namespace.namespace1.permitted.paths += /apex/permitted_path2
62 namespace.namespace1.asan.search.paths = /data/asan/search_path1
63 namespace.namespace1.asan.search.paths += /search_path1
64 namespace.namespace1.asan.search.paths += /apex/search_path2
65 namespace.namespace1.asan.permitted.paths = /data/asan/permitted_path1
66 namespace.namespace1.asan.permitted.paths += /permitted_path1
67 namespace.namespace1.asan.permitted.paths += /apex/permitted_path2
68 namespace.namespace1.hwasan.search.paths = /search_path1/hwasan
69 namespace.namespace1.hwasan.search.paths += /search_path1
70 namespace.namespace1.hwasan.search.paths += /apex/search_path2/hwasan
71 namespace.namespace1.hwasan.search.paths += /apex/search_path2
72 namespace.namespace1.hwasan.permitted.paths = /permitted_path1/hwasan
73 namespace.namespace1.hwasan.permitted.paths += /permitted_path1
74 namespace.namespace1.hwasan.permitted.paths += /apex/permitted_path2/hwasan
75 namespace.namespace1.hwasan.permitted.paths += /apex/permitted_path2
76 namespace.namespace1.links = default,namespace2
77 namespace.namespace1.link.default.shared_libs = lib1.so:lib2.so:lib3.so
78 namespace.namespace1.link.namespace2.allow_all_shared_libs = true
79 namespace.namespace2.isolated = false
80 namespace.namespace2.search.paths = /search_path1
81 namespace.namespace2.search.paths += /apex/search_path2
82 namespace.namespace2.permitted.paths = /permitted_path1
83 namespace.namespace2.permitted.paths += /apex/permitted_path2
84 namespace.namespace2.asan.search.paths = /data/asan/search_path1
85 namespace.namespace2.asan.search.paths += /search_path1
86 namespace.namespace2.asan.search.paths += /apex/search_path2
87 namespace.namespace2.asan.permitted.paths = /data/asan/permitted_path1
88 namespace.namespace2.asan.permitted.paths += /permitted_path1
89 namespace.namespace2.asan.permitted.paths += /apex/permitted_path2
90 namespace.namespace2.hwasan.search.paths = /search_path1/hwasan
91 namespace.namespace2.hwasan.search.paths += /search_path1
92 namespace.namespace2.hwasan.search.paths += /apex/search_path2/hwasan
93 namespace.namespace2.hwasan.search.paths += /apex/search_path2
94 namespace.namespace2.hwasan.permitted.paths = /permitted_path1/hwasan
95 namespace.namespace2.hwasan.permitted.paths += /permitted_path1
96 namespace.namespace2.hwasan.permitted.paths += /apex/permitted_path2/hwasan
97 namespace.namespace2.hwasan.permitted.paths += /apex/permitted_path2
98 )";
99 
100 constexpr const char* kSectionWithOneNamespaceExpectedResult =
101     R"([test_section]
102 namespace.default.isolated = false
103 namespace.default.search.paths = /search_path1
104 namespace.default.search.paths += /apex/search_path2
105 namespace.default.permitted.paths = /permitted_path1
106 namespace.default.permitted.paths += /apex/permitted_path2
107 namespace.default.asan.search.paths = /data/asan/search_path1
108 namespace.default.asan.search.paths += /search_path1
109 namespace.default.asan.search.paths += /apex/search_path2
110 namespace.default.asan.permitted.paths = /data/asan/permitted_path1
111 namespace.default.asan.permitted.paths += /permitted_path1
112 namespace.default.asan.permitted.paths += /apex/permitted_path2
113 namespace.default.hwasan.search.paths = /search_path1/hwasan
114 namespace.default.hwasan.search.paths += /search_path1
115 namespace.default.hwasan.search.paths += /apex/search_path2/hwasan
116 namespace.default.hwasan.search.paths += /apex/search_path2
117 namespace.default.hwasan.permitted.paths = /permitted_path1/hwasan
118 namespace.default.hwasan.permitted.paths += /permitted_path1
119 namespace.default.hwasan.permitted.paths += /apex/permitted_path2/hwasan
120 namespace.default.hwasan.permitted.paths += /apex/permitted_path2
121 )";
122 
TEST(linkerconfig_section,section_with_namespaces)123 TEST(linkerconfig_section, section_with_namespaces) {
124   ConfigWriter writer;
125 
126   std::vector<Namespace> namespaces;
127 
128   namespaces.emplace_back(CreateNamespaceWithLinks(
129       "default", true, true, "namespace1", "namespace2"));
130   namespaces.emplace_back(CreateNamespaceWithLinks(
131       "namespace1", false, false, "default", "namespace2"));
132   namespaces.emplace_back(CreateNamespaceWithPaths("namespace2", false, false));
133 
134   Section section("test_section", std::move(namespaces));
135 
136   section.WriteConfig(writer);
137   auto config = writer.ToString();
138   ASSERT_EQ(kSectionWithNamespacesExpectedResult, config);
139 }
140 
TEST(linkerconfig_section,section_with_one_namespace)141 TEST(linkerconfig_section, section_with_one_namespace) {
142   android::linkerconfig::modules::ConfigWriter writer;
143 
144   std::vector<Namespace> namespaces;
145   namespaces.emplace_back(CreateNamespaceWithPaths("default", false, false));
146 
147   Section section("test_section", std::move(namespaces));
148   section.WriteConfig(writer);
149   auto config = writer.ToString();
150   ASSERT_EQ(kSectionWithOneNamespaceExpectedResult, config);
151 }
152 
TEST(linkerconfig_section,resolve_contraints)153 TEST(linkerconfig_section, resolve_contraints) {
154   BaseContext ctx;
155   std::vector<Namespace> namespaces;
156   Namespace& foo = namespaces.emplace_back("foo");
157   foo.AddProvides(std::vector{"libfoo.so"});
158   foo.AddRequires(std::vector{"libbar.so"});
159   Namespace& bar = namespaces.emplace_back("bar");
160   bar.AddProvides(std::vector{"libbar.so"});
161   Namespace& baz = namespaces.emplace_back("baz");
162   baz.AddRequires(std::vector{"libfoo.so"});
163 
164   Section section("section", std::move(namespaces));
165   section.Resolve(ctx);
166 
167   ConfigWriter writer;
168   section.WriteConfig(writer);
169 
170   ASSERT_EQ(
171       "[section]\n"
172       "additional.namespaces = bar,baz,foo\n"
173       "namespace.bar.isolated = false\n"
174       "namespace.baz.isolated = false\n"
175       "namespace.baz.links = foo\n"
176       "namespace.baz.link.foo.shared_libs = libfoo.so\n"
177       "namespace.foo.isolated = false\n"
178       "namespace.foo.links = bar\n"
179       "namespace.foo.link.bar.shared_libs = libbar.so\n",
180       writer.ToString());
181 }
182 
TEST(linkerconfig_section,error_if_duplicate_providing)183 TEST(linkerconfig_section, error_if_duplicate_providing) {
184   BaseContext ctx;
185   // TODO(b/297821005) : remove vendor / product vndk version set up
186   android::linkerconfig::modules::Variables::AddValue("ro.vndk.version", "99");
187   android::linkerconfig::modules::Variables::AddValue("ro.product.vndk.version",
188                                                       "99");
189   std::vector<Namespace> namespaces;
190   Namespace& foo1 = namespaces.emplace_back("foo1");
191   foo1.AddProvides(std::vector{"libfoo.so"});
192   Namespace& foo2 = namespaces.emplace_back("foo2");
193   foo2.AddProvides(std::vector{"libfoo.so"});
194   Namespace& bar = namespaces.emplace_back("bar");
195   bar.AddRequires(std::vector{"libfoo.so"});
196 
197   Section section("section", std::move(namespaces));
198   ASSERT_EXIT(section.Resolve(ctx),
199               testing::KilledBySignal(SIGABRT),
200 #ifndef __ANDROID__
201               "duplicate: libfoo\\.so is provided by foo1 and foo2"
202 #else
203               ""
204 #endif
205   );
206 }
207 
TEST(linkerconfig_section,error_if_no_providers_in_strict_mode)208 TEST(linkerconfig_section, error_if_no_providers_in_strict_mode) {
209   BaseContext ctx;
210   ctx.SetStrictMode(true);
211 
212   std::vector<Namespace> namespaces;
213   Namespace& foo = namespaces.emplace_back("foo");
214   foo.AddRequires(std::vector{"libfoo.so"});
215 
216   Section section("section", std::move(namespaces));
217   ASSERT_EXIT(section.Resolve(ctx),
218               testing::KilledBySignal(SIGABRT),
219 #ifndef __ANDROID__
220               "not found: libfoo\\.so is required by foo"
221 #else
222               ""
223 #endif
224   );
225 }
226 
TEST(linkerconfig_section,ignore_unmet_requirements)227 TEST(linkerconfig_section, ignore_unmet_requirements) {
228   BaseContext ctx;
229   ctx.SetStrictMode(false);  // default
230 
231   std::vector<Namespace> namespaces;
232   Namespace& foo = namespaces.emplace_back("foo");
233   foo.AddRequires(std::vector{"libfoo.so"});
234 
235   Section section("section", std::move(namespaces));
236   section.Resolve(ctx);
237 
238   ConfigWriter writer;
239   section.WriteConfig(writer);
240 
241   ASSERT_EQ(
242       "[section]\n"
243       "namespace.foo.isolated = false\n",
244       writer.ToString());
245 }
246 
TEST(linkerconfig_section,resolve_section_with_apex)247 TEST(linkerconfig_section, resolve_section_with_apex) {
248   BaseContext ctx;
249   ctx.SetApexModules(
250       {ApexInfo("foo", "", {"a.so"}, {"b.so"}, {}, {}, true, true, false, false),
251        ApexInfo("bar", "", {"b.so"}, {}, {}, {}, true, true, false, false),
252        ApexInfo(
253            "baz", "", {"c.so"}, {"a.so"}, {}, {}, true, true, false, false)});
254   std::vector<Namespace> namespaces;
255   Namespace& default_ns = namespaces.emplace_back("default");
256   default_ns.AddRequires(std::vector{"a.so", "b.so"});
257 
258   Section section("section", std::move(namespaces));
259   section.Resolve(ctx);
260 
261   EXPECT_THAT(
262       std::vector<std::string>{"a.so"},
263       ::testing::ContainerEq(
264           section.GetNamespace("default")->GetLink("foo").GetSharedLibs()));
265   EXPECT_THAT(
266       std::vector<std::string>{"b.so"},
267       ::testing::ContainerEq(
268           section.GetNamespace("default")->GetLink("bar").GetSharedLibs()));
269   EXPECT_THAT(std::vector<std::string>{"b.so"},
270               ::testing::ContainerEq(
271                   section.GetNamespace("foo")->GetLink("bar").GetSharedLibs()));
272   EXPECT_EQ(nullptr, section.GetNamespace("baz"));
273 }
274 
TEST(linkerconfig_section,resolve_link_modifiers)275 TEST(linkerconfig_section, resolve_link_modifiers) {
276   BaseContext ctx;
277   std::vector<Namespace> namespaces;
278   Namespace& default_ns = namespaces.emplace_back("default");
279   default_ns.AddRequires(std::vector{":foo", ":bar"});
280 
281   LibProviders providers;
282   providers[":foo"].emplace_back(LibProvider{
283       "foo",
284       []() { return Namespace("foo"); },
285       AllowAllSharedLibs{},
286   });
287   providers[":bar"].emplace_back(LibProvider{
288       "bar",
289       []() { return Namespace("bar"); },
290       SharedLibs{{"libbar.so"}},
291   });
292 
293   Section section("section", std::move(namespaces));
294   section.Resolve(ctx, providers);
295 
296   EXPECT_TRUE(
297       section.GetNamespace("default")->GetLink("foo").IsAllSharedLibsAllowed());
298   EXPECT_THAT(section.GetNamespace("default")->GetLink("bar").GetSharedLibs(),
299               ::testing::ContainerEq(std::vector<std::string>{"libbar.so"}));
300 }
301