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 <string>
18 #include <vector>
19
20 #include <android-base/file.h>
21 #include <apex_manifest.pb.h>
22 #include <gmock/gmock.h>
23 #include <gtest/gtest.h>
24 #include <linker_config.pb.h>
25
26 #include "apex_testbase.h"
27 #include "linkerconfig/apex.h"
28 #include "linkerconfig/basecontext.h"
29 #include "linkerconfig/configwriter.h"
30 #include "linkerconfig/namespace.h"
31 #include "linkerconfig/section.h"
32
33 using ::android::base::WriteStringToFile;
34 using ::android::linkerconfig::modules::ApexInfo;
35 using ::android::linkerconfig::modules::BaseContext;
36 using ::android::linkerconfig::modules::ConfigWriter;
37 using ::android::linkerconfig::modules::InitializeWithApex;
38 using ::android::linkerconfig::modules::Namespace;
39 using ::android::linkerconfig::modules::ScanActiveApexes;
40 using ::android::linkerconfig::modules::Section;
41 using ::apex::proto::ApexManifest;
42 using ::testing::Contains;
43
TEST(apex_namespace,build_namespace)44 TEST(apex_namespace, build_namespace) {
45 Namespace ns("foo");
46 InitializeWithApex(ns,
47 ApexInfo("com.android.foo",
48 "/apex/com.android.foo",
49 /*provide_libs=*/{},
50 /*require_libs=*/{},
51 /*jni_libs=*/{},
52 /*permitted_paths=*/{},
53 /*has_bin=*/false,
54 /*has_lib=*/true,
55 /*visible=*/false,
56 /*has_shared_lib=*/false));
57
58 ConfigWriter writer;
59 ns.WriteConfig(writer);
60 ASSERT_EQ(
61 "namespace.foo.isolated = false\n"
62 "namespace.foo.search.paths = /apex/com.android.foo/${LIB}\n"
63 "namespace.foo.permitted.paths = /apex/com.android.foo/${LIB}\n"
64 "namespace.foo.permitted.paths += /system/${LIB}\n"
65 "namespace.foo.permitted.paths += /system_ext/${LIB}\n"
66 "namespace.foo.asan.search.paths = /apex/com.android.foo/${LIB}\n"
67 "namespace.foo.asan.permitted.paths = /apex/com.android.foo/${LIB}\n"
68 "namespace.foo.asan.permitted.paths += /data/asan/system/${LIB}\n"
69 "namespace.foo.asan.permitted.paths += /system/${LIB}\n"
70 "namespace.foo.asan.permitted.paths += /data/asan/system_ext/${LIB}\n"
71 "namespace.foo.asan.permitted.paths += /system_ext/${LIB}\n"
72 "namespace.foo.hwasan.search.paths = /apex/com.android.foo/${LIB}/hwasan\n"
73 "namespace.foo.hwasan.search.paths += /apex/com.android.foo/${LIB}\n"
74 "namespace.foo.hwasan.permitted.paths = /apex/com.android.foo/${LIB}/hwasan\n"
75 "namespace.foo.hwasan.permitted.paths += /apex/com.android.foo/${LIB}\n"
76 "namespace.foo.hwasan.permitted.paths += /system/${LIB}/hwasan\n"
77 "namespace.foo.hwasan.permitted.paths += /system/${LIB}\n"
78 "namespace.foo.hwasan.permitted.paths += /system_ext/${LIB}/hwasan\n"
79 "namespace.foo.hwasan.permitted.paths += /system_ext/${LIB}\n",
80 writer.ToString());
81 }
82
TEST(apex_namespace,resolve_between_apex_namespaces)83 TEST(apex_namespace, resolve_between_apex_namespaces) {
84 BaseContext ctx;
85 Namespace foo("foo"), bar("bar");
86 InitializeWithApex(foo,
87 ApexInfo("com.android.foo",
88 "/apex/com.android.foo",
89 /*provide_libs=*/{"foo.so"},
90 /*require_libs=*/{"bar.so"},
91 /*jni_libs=*/{},
92 /*permitted_paths=*/{},
93 /*has_bin=*/false,
94 /*has_lib=*/true,
95 /*visible=*/false,
96 /*has_shared_lib=*/false));
97 InitializeWithApex(bar,
98 ApexInfo("com.android.bar",
99 "/apex/com.android.bar",
100 /*provide_libs=*/{"bar.so"},
101 /*require_libs=*/{},
102 /*jni_libs=*/{},
103 /*permitted_paths=*/{},
104 /*has_bin=*/false,
105 /*has_lib=*/true,
106 /*visible=*/false,
107 /*has_shared_lib=*/false));
108
109 std::vector<Namespace> namespaces;
110 namespaces.push_back(std::move(foo));
111 namespaces.push_back(std::move(bar));
112 Section section("section", std::move(namespaces));
113
114 section.Resolve(ctx);
115
116 // See if two namespaces are linked correctly
117 ASSERT_THAT(section.GetNamespace("foo")->GetLink("bar").GetSharedLibs(),
118 Contains("bar.so"));
119 }
120
TEST(apex_namespace,extra_permitted_paths)121 TEST(apex_namespace, extra_permitted_paths) {
122 Namespace ns("foo");
123 InitializeWithApex(ns,
124 ApexInfo("com.android.foo",
125 "/apex/com.android.foo",
126 /*provide_libs=*/{},
127 /*require_libs=*/{},
128 /*jni_libs=*/{},
129 /*permitted_paths=*/{"/a", "/b/c"},
130 /*has_bin=*/false,
131 /*has_lib=*/true,
132 /*visible=*/false,
133 /*has_shared_lib=*/false));
134
135 ConfigWriter writer;
136 ns.WriteConfig(writer);
137 ASSERT_EQ(
138 "namespace.foo.isolated = false\n"
139 "namespace.foo.search.paths = /apex/com.android.foo/${LIB}\n"
140 "namespace.foo.permitted.paths = /apex/com.android.foo/${LIB}\n"
141 "namespace.foo.permitted.paths += /system/${LIB}\n"
142 "namespace.foo.permitted.paths += /system_ext/${LIB}\n"
143 "namespace.foo.permitted.paths += /a\n"
144 "namespace.foo.permitted.paths += /b/c\n"
145 "namespace.foo.asan.search.paths = /apex/com.android.foo/${LIB}\n"
146 "namespace.foo.asan.permitted.paths = /apex/com.android.foo/${LIB}\n"
147 "namespace.foo.asan.permitted.paths += /data/asan/system/${LIB}\n"
148 "namespace.foo.asan.permitted.paths += /system/${LIB}\n"
149 "namespace.foo.asan.permitted.paths += /data/asan/system_ext/${LIB}\n"
150 "namespace.foo.asan.permitted.paths += /system_ext/${LIB}\n"
151 "namespace.foo.asan.permitted.paths += /data/asan/a\n"
152 "namespace.foo.asan.permitted.paths += /a\n"
153 "namespace.foo.asan.permitted.paths += /data/asan/b/c\n"
154 "namespace.foo.asan.permitted.paths += /b/c\n"
155 "namespace.foo.hwasan.search.paths = /apex/com.android.foo/${LIB}/hwasan\n"
156 "namespace.foo.hwasan.search.paths += /apex/com.android.foo/${LIB}\n"
157 "namespace.foo.hwasan.permitted.paths = /apex/com.android.foo/${LIB}/hwasan\n"
158 "namespace.foo.hwasan.permitted.paths += /apex/com.android.foo/${LIB}\n"
159 "namespace.foo.hwasan.permitted.paths += /system/${LIB}/hwasan\n"
160 "namespace.foo.hwasan.permitted.paths += /system/${LIB}\n"
161 "namespace.foo.hwasan.permitted.paths += /system_ext/${LIB}/hwasan\n"
162 "namespace.foo.hwasan.permitted.paths += /system_ext/${LIB}\n"
163 "namespace.foo.hwasan.permitted.paths += /a/hwasan\n"
164 "namespace.foo.hwasan.permitted.paths += /a\n"
165 "namespace.foo.hwasan.permitted.paths += /b/c/hwasan\n"
166 "namespace.foo.hwasan.permitted.paths += /b/c\n",
167 writer.ToString());
168 }
169
TEST_F(ApexTest,scan_apex_dir)170 TEST_F(ApexTest, scan_apex_dir) {
171 PrepareApex("foo", {}, {"bar.so"}, {});
172 WriteFile("/apex/foo/bin/foo", "");
173 PrepareApex("bar", {"bar.so"}, {}, {});
174 WriteFile("/apex/bar/lib64/bar.so", "");
175 PrepareApex("baz", {}, {}, {"baz.so"});
176 WriteFile("/apex/baz/lib64/baz.so", "");
177 CreateApexInfoList();
178 CreatePublicLibrariesTxt();
179
180 auto apexes = ScanActiveApexes(root);
181 ASSERT_TRUE(apexes.ok()) << "Failed to scan active APEXes : "
182 << apexes.error();
183 ASSERT_EQ(3U, apexes->size());
184
185 ASSERT_THAT((*apexes)["foo"].require_libs, Contains("bar.so"));
186 ASSERT_TRUE((*apexes)["foo"].has_bin);
187 ASSERT_FALSE((*apexes)["foo"].has_lib);
188
189 ASSERT_THAT((*apexes)["bar"].provide_libs, Contains("bar.so"));
190 ASSERT_FALSE((*apexes)["bar"].has_bin);
191 ASSERT_TRUE((*apexes)["bar"].has_lib);
192
193 ASSERT_THAT((*apexes)["baz"].jni_libs, Contains("baz.so"));
194 ASSERT_FALSE((*apexes)["baz"].has_bin);
195 ASSERT_TRUE((*apexes)["baz"].has_lib);
196 }
197
TEST_F(ApexTest,validate_path)198 TEST_F(ApexTest, validate_path) {
199 PrepareApex("foo", {}, {}, {});
200 CreateApexInfoList();
201 CreatePublicLibrariesTxt();
202
203 ::android::linkerconfig::proto::LinkerConfig two_slash;
204 two_slash.add_permittedpaths("/two//slash");
205
206 WriteFile("/apex/foo/etc/linker.config.pb", two_slash.SerializeAsString());
207 auto apexes = ScanActiveApexes(root);
208 ASSERT_FALSE(apexes.ok()) << "Two slash is not allowed from path string";
209
210 ::android::linkerconfig::proto::LinkerConfig invalid_char;
211 invalid_char.add_permittedpaths("/path/with*/invalid/char");
212
213 WriteFile("/apex/foo/etc/linker.config.pb", invalid_char.SerializeAsString());
214 apexes = ScanActiveApexes(root);
215 ASSERT_FALSE(apexes.ok()) << "* is invalid char for path.";
216
217 ::android::linkerconfig::proto::LinkerConfig end_with_lib;
218 end_with_lib.add_permittedpaths("/somewhere/${LIB}");
219
220 WriteFile("/apex/foo/etc/linker.config.pb", end_with_lib.SerializeAsString());
221 apexes = ScanActiveApexes(root);
222 ASSERT_TRUE(apexes.ok()) << "Path ends with ${LIB} should be accepted. : "
223 << apexes.error();
224
225 ::android::linkerconfig::proto::LinkerConfig lib_plus_char;
226 lib_plus_char.add_permittedpaths("/somewhere/${LIB}x/hw");
227
228 WriteFile("/apex/foo/etc/linker.config.pb", lib_plus_char.SerializeAsString());
229 apexes = ScanActiveApexes(root);
230 ASSERT_FALSE(apexes.ok())
231 << "There should be no extra char after ${LIB} in path.";
232
233 ::android::linkerconfig::proto::LinkerConfig char_plus_lib;
234 char_plus_lib.add_permittedpaths("/somewhere/x${LIB}/hw");
235
236 WriteFile("/apex/foo/etc/linker.config.pb", char_plus_lib.SerializeAsString());
237 apexes = ScanActiveApexes(root);
238 ASSERT_FALSE(apexes.ok())
239 << "There should be no extra char before ${LIB} in path.";
240
241 ::android::linkerconfig::proto::LinkerConfig lib_and_lib64;
242 lib_and_lib64.add_permittedpaths("/somewhere/${LIB}/hw");
243
244 WriteFile("/apex/foo/etc/linker.config.pb", lib_and_lib64.SerializeAsString());
245 apexes = ScanActiveApexes(root);
246 ASSERT_TRUE(apexes.ok()) << "Valid path with ${LIB} should be accepted. : "
247 << apexes.error();
248 }
249
TEST_F(ApexTest,skip_sharedlibs_apex)250 TEST_F(ApexTest, skip_sharedlibs_apex) {
251 PrepareApex("foo", {}, {}, {});
252 WriteFile("/apex/apex-info-list.xml", R"(<apex-info-list>
253 <apex-info moduleName="foo"
254 partition="SYSTEM"
255 modulePath="/data/apex/active/foo.apex"
256 isActive="true" />
257 <apex-info moduleName="sharedlibs"
258 partition="SYSTEM"
259 modulePath="/data/apex/active/sharedlibs.apex"
260 provideSharedApexLibs="true"
261 isActive="true" />
262 </apex-info-list>)");
263 auto apexes = ScanActiveApexes(root);
264 ASSERT_TRUE(apexes.ok()) << apexes.error();
265 ASSERT_EQ(apexes->find("sharedlibs"), apexes->end());
266 }
267
TEST_F(ApexTest,public_libraries_txt_malformed_line)268 TEST_F(ApexTest, public_libraries_txt_malformed_line) {
269 PrepareApex("foo", {}, {}, {});
270 CreateApexInfoList();
271 WriteFile("/system/etc/public.libraries.txt", "foo.so blah blah blah");
272 auto apexes = ScanActiveApexes(root);
273 ASSERT_FALSE(apexes.ok());
274 ASSERT_THAT(apexes.error().message(), testing::HasSubstr("Malformed line"));
275 }
276
TEST_F(ApexTest,public_libs_with_public_libraries_txt)277 TEST_F(ApexTest, public_libs_with_public_libraries_txt) {
278 PrepareApex("foo", /*provide_libs=*/{"libfoo.so"}, {}, {});
279 WriteFile("/apex/apex-info-list.xml", R"(<apex-info-list>
280 <apex-info moduleName="foo"
281 partition="SYSTEM"
282 modulePath="/data/apex/active/foo.apex"
283 isActive="true" />
284 </apex-info-list>)");
285 WriteFile("/system/etc/public.libraries.txt", "libfoo.so");
286 auto apexes = ScanActiveApexes(root);
287 ASSERT_TRUE(apexes.ok()) << apexes.error();
288 ASSERT_EQ(apexes->at("foo").public_libs,
289 std::vector<std::string>{"libfoo.so"});
290 }
291
TEST_F(ApexTest,public_libs_should_be_system_apex)292 TEST_F(ApexTest, public_libs_should_be_system_apex) {
293 PrepareApex("foo", /*provide_libs=*/{"libfoo.so"}, {}, {});
294 WriteFile("/apex/apex-info-list.xml", R"(<apex-info-list>
295 <apex-info moduleName="foo"
296 partition="VENDOR"
297 modulePath="/data/apex/active/foo.apex"
298 isActive="true" />
299 </apex-info-list>)");
300 WriteFile("/system/etc/public.libraries.txt", "libfoo.so");
301 auto apexes = ScanActiveApexes(root);
302 ASSERT_TRUE(apexes.ok()) << apexes.error();
303 ASSERT_EQ(apexes->at("foo").public_libs, std::vector<std::string>{});
304 }
305
TEST_F(ApexTest,system_ext_can_be_linked_to_system_system_ext)306 TEST_F(ApexTest, system_ext_can_be_linked_to_system_system_ext) {
307 PrepareApex("foo", /*provide_libs=*/{"libfoo.so"}, {}, {});
308 WriteFile("/apex/apex-info-list.xml", R"(<apex-info-list>
309 <apex-info moduleName="foo"
310 partition="SYSTEM_EXT"
311 modulePath="/data/apex/active/foo.apex"
312 isActive="true" />
313 </apex-info-list>)");
314 WriteFile("/system/etc/public.libraries.txt", "libfoo.so");
315 auto apexes = ScanActiveApexes(root);
316 ASSERT_TRUE(apexes.ok()) << apexes.error();
317 ASSERT_EQ(apexes->at("foo").public_libs,
318 std::vector<std::string>{"libfoo.so"});
319 }
320