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