xref: /aosp_15_r20/system/linkerconfig/modules/tests/apex_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 <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