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 "modules_testbase.h"
27 
28 using namespace android::linkerconfig::modules;
29 
30 constexpr const char* kSectionWithNamespacesExpectedResult =
31     R"([test_section]
32 additional.namespaces = namespace1,namespace2
33 namespace.default.isolated = true
34 namespace.default.visible = true
35 namespace.default.search.paths = /search_path1
36 namespace.default.search.paths += /apex/search_path2
37 namespace.default.permitted.paths = /permitted_path1
38 namespace.default.permitted.paths += /apex/permitted_path2
39 namespace.default.asan.search.paths = /data/asan/search_path1
40 namespace.default.asan.search.paths += /search_path1
41 namespace.default.asan.search.paths += /apex/search_path2
42 namespace.default.asan.permitted.paths = /data/asan/permitted_path1
43 namespace.default.asan.permitted.paths += /permitted_path1
44 namespace.default.asan.permitted.paths += /apex/permitted_path2
45 namespace.default.links = namespace1,namespace2
46 namespace.default.link.namespace1.shared_libs = lib1.so
47 namespace.default.link.namespace1.shared_libs += lib2.so
48 namespace.default.link.namespace1.shared_libs += lib3.so
49 namespace.default.link.namespace2.allow_all_shared_libs = true
50 namespace.namespace1.isolated = false
51 namespace.namespace1.search.paths = /search_path1
52 namespace.namespace1.search.paths += /apex/search_path2
53 namespace.namespace1.permitted.paths = /permitted_path1
54 namespace.namespace1.permitted.paths += /apex/permitted_path2
55 namespace.namespace1.asan.search.paths = /data/asan/search_path1
56 namespace.namespace1.asan.search.paths += /search_path1
57 namespace.namespace1.asan.search.paths += /apex/search_path2
58 namespace.namespace1.asan.permitted.paths = /data/asan/permitted_path1
59 namespace.namespace1.asan.permitted.paths += /permitted_path1
60 namespace.namespace1.asan.permitted.paths += /apex/permitted_path2
61 namespace.namespace1.links = default,namespace2
62 namespace.namespace1.link.default.shared_libs = lib1.so
63 namespace.namespace1.link.default.shared_libs += lib2.so
64 namespace.namespace1.link.default.shared_libs += lib3.so
65 namespace.namespace1.link.namespace2.allow_all_shared_libs = true
66 namespace.namespace2.isolated = false
67 namespace.namespace2.search.paths = /search_path1
68 namespace.namespace2.search.paths += /apex/search_path2
69 namespace.namespace2.permitted.paths = /permitted_path1
70 namespace.namespace2.permitted.paths += /apex/permitted_path2
71 namespace.namespace2.asan.search.paths = /data/asan/search_path1
72 namespace.namespace2.asan.search.paths += /search_path1
73 namespace.namespace2.asan.search.paths += /apex/search_path2
74 namespace.namespace2.asan.permitted.paths = /data/asan/permitted_path1
75 namespace.namespace2.asan.permitted.paths += /permitted_path1
76 namespace.namespace2.asan.permitted.paths += /apex/permitted_path2
77 )";
78 
79 constexpr const char* kSectionWithOneNamespaceExpectedResult =
80     R"([test_section]
81 namespace.default.isolated = false
82 namespace.default.search.paths = /search_path1
83 namespace.default.search.paths += /apex/search_path2
84 namespace.default.permitted.paths = /permitted_path1
85 namespace.default.permitted.paths += /apex/permitted_path2
86 namespace.default.asan.search.paths = /data/asan/search_path1
87 namespace.default.asan.search.paths += /search_path1
88 namespace.default.asan.search.paths += /apex/search_path2
89 namespace.default.asan.permitted.paths = /data/asan/permitted_path1
90 namespace.default.asan.permitted.paths += /permitted_path1
91 namespace.default.asan.permitted.paths += /apex/permitted_path2
92 )";
93 
TEST(linkerconfig_section,section_with_namespaces)94 TEST(linkerconfig_section, section_with_namespaces) {
95   ConfigWriter writer;
96 
97   std::vector<Namespace> namespaces;
98 
99   namespaces.emplace_back(CreateNamespaceWithLinks(
100       "default", true, true, "namespace1", "namespace2"));
101   namespaces.emplace_back(CreateNamespaceWithLinks(
102       "namespace1", false, false, "default", "namespace2"));
103   namespaces.emplace_back(CreateNamespaceWithPaths("namespace2", false, false));
104 
105   Section section("test_section", std::move(namespaces));
106 
107   section.WriteConfig(writer);
108   auto config = writer.ToString();
109   ASSERT_EQ(kSectionWithNamespacesExpectedResult, config);
110 }
111 
TEST(linkerconfig_section,section_with_one_namespace)112 TEST(linkerconfig_section, section_with_one_namespace) {
113   android::linkerconfig::modules::ConfigWriter writer;
114 
115   std::vector<Namespace> namespaces;
116   namespaces.emplace_back(CreateNamespaceWithPaths("default", false, false));
117 
118   Section section("test_section", std::move(namespaces));
119   section.WriteConfig(writer);
120   auto config = writer.ToString();
121   ASSERT_EQ(kSectionWithOneNamespaceExpectedResult, config);
122 }
123 
TEST(linkerconfig_section,resolve_contraints)124 TEST(linkerconfig_section, resolve_contraints) {
125   BaseContext ctx;
126   std::vector<Namespace> namespaces;
127   Namespace& foo = namespaces.emplace_back("foo");
128   foo.AddProvides(std::vector{"libfoo.so"});
129   foo.AddRequires(std::vector{"libbar.so"});
130   Namespace& bar = namespaces.emplace_back("bar");
131   bar.AddProvides(std::vector{"libbar.so"});
132   Namespace& baz = namespaces.emplace_back("baz");
133   baz.AddRequires(std::vector{"libfoo.so"});
134 
135   Section section("section", std::move(namespaces));
136   section.Resolve(ctx);
137 
138   ConfigWriter writer;
139   section.WriteConfig(writer);
140 
141   ASSERT_EQ(
142       "[section]\n"
143       "additional.namespaces = bar,baz,foo\n"
144       "namespace.bar.isolated = false\n"
145       "namespace.baz.isolated = false\n"
146       "namespace.baz.links = foo\n"
147       "namespace.baz.link.foo.shared_libs = libfoo.so\n"
148       "namespace.foo.isolated = false\n"
149       "namespace.foo.links = bar\n"
150       "namespace.foo.link.bar.shared_libs = libbar.so\n",
151       writer.ToString());
152 }
153 
TEST(linkerconfig_section,error_if_duplicate_providing)154 TEST(linkerconfig_section, error_if_duplicate_providing) {
155   BaseContext ctx;
156   std::vector<Namespace> namespaces;
157   Namespace& foo1 = namespaces.emplace_back("foo1");
158   foo1.AddProvides(std::vector{"libfoo.so"});
159   Namespace& foo2 = namespaces.emplace_back("foo2");
160   foo2.AddProvides(std::vector{"libfoo.so"});
161   Namespace& bar = namespaces.emplace_back("bar");
162   bar.AddRequires(std::vector{"libfoo.so"});
163 
164   Section section("section", std::move(namespaces));
165   auto result = section.Resolve(ctx);
166   ASSERT_EQ("duplicate: libfoo.so is provided by foo1 and foo2 in [section]",
167             result.error().message());
168 }
169 
TEST(linkerconfig_section,error_if_no_providers_in_strict_mode)170 TEST(linkerconfig_section, error_if_no_providers_in_strict_mode) {
171   BaseContext ctx;
172   ctx.SetStrictMode(true);
173 
174   std::vector<Namespace> namespaces;
175   Namespace& foo = namespaces.emplace_back("foo");
176   foo.AddRequires(std::vector{"libfoo.so"});
177 
178   Section section("section", std::move(namespaces));
179   auto result = section.Resolve(ctx);
180   ASSERT_EQ("not found: libfoo.so is required by foo in [section]",
181             result.error().message());
182 }
183 
TEST(linkerconfig_section,ignore_unmet_requirements)184 TEST(linkerconfig_section, ignore_unmet_requirements) {
185   BaseContext ctx;
186   ctx.SetStrictMode(false);  // default
187 
188   std::vector<Namespace> namespaces;
189   Namespace& foo = namespaces.emplace_back("foo");
190   foo.AddRequires(std::vector{"libfoo.so"});
191 
192   Section section("section", std::move(namespaces));
193   auto result = section.Resolve(ctx);
194   ASSERT_RESULT_OK(result);
195 
196   ConfigWriter writer;
197   section.WriteConfig(writer);
198 
199   ASSERT_EQ(
200       "[section]\n"
201       "namespace.foo.isolated = false\n",
202       writer.ToString());
203 }
204 
TEST(linkerconfig_section,resolve_section_with_apex)205 TEST(linkerconfig_section, resolve_section_with_apex) {
206   BaseContext ctx;
207   ctx.AddApexModule(ApexInfo(
208       "foo", "", {"a.so"}, {"b.so"}, {}, {}, true, true, false, false));
209   ctx.AddApexModule(
210       ApexInfo("bar", "", {"b.so"}, {}, {}, {}, true, true, false, false));
211   ctx.AddApexModule(ApexInfo(
212       "baz", "", {"c.so"}, {"a.so"}, {}, {}, true, true, false, false));
213 
214   std::vector<Namespace> namespaces;
215   Namespace& default_ns = namespaces.emplace_back("default");
216   default_ns.AddRequires(std::vector{"a.so", "b.so"});
217 
218   Section section("section", std::move(namespaces));
219   auto result = section.Resolve(ctx);
220 
221   EXPECT_RESULT_OK(result);
222   EXPECT_THAT(
223       std::vector<std::string>{"a.so"},
224       ::testing::ContainerEq(
225           section.GetNamespace("default")->GetLink("foo").GetSharedLibs()));
226   EXPECT_THAT(
227       std::vector<std::string>{"b.so"},
228       ::testing::ContainerEq(
229           section.GetNamespace("default")->GetLink("bar").GetSharedLibs()));
230   EXPECT_THAT(std::vector<std::string>{"b.so"},
231               ::testing::ContainerEq(
232                   section.GetNamespace("foo")->GetLink("bar").GetSharedLibs()));
233   EXPECT_EQ(nullptr, section.GetNamespace("baz"));
234 }
235