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.asan.search.paths = /apex/com.android.foo/${LIB}\n"
66       "namespace.foo.asan.permitted.paths = /apex/com.android.foo/${LIB}\n"
67       "namespace.foo.asan.permitted.paths += /data/asan/system/${LIB}\n"
68       "namespace.foo.asan.permitted.paths += /system/${LIB}\n",
69       writer.ToString());
70 }
71 
TEST(apex_namespace,resolve_between_apex_namespaces)72 TEST(apex_namespace, resolve_between_apex_namespaces) {
73   BaseContext ctx;
74   Namespace foo("foo"), bar("bar");
75   InitializeWithApex(foo,
76                      ApexInfo("com.android.foo",
77                               "/apex/com.android.foo",
78                               /*provide_libs=*/{"foo.so"},
79                               /*require_libs=*/{"bar.so"},
80                               /*jni_libs=*/{},
81                               /*permitted_paths=*/{},
82                               /*has_bin=*/false,
83                               /*has_lib=*/true,
84                               /*visible=*/false,
85                               /*has_shared_lib=*/false));
86   InitializeWithApex(bar,
87                      ApexInfo("com.android.bar",
88                               "/apex/com.android.bar",
89                               /*provide_libs=*/{"bar.so"},
90                               /*require_libs=*/{},
91                               /*jni_libs=*/{},
92                               /*permitted_paths=*/{},
93                               /*has_bin=*/false,
94                               /*has_lib=*/true,
95                               /*visible=*/false,
96                               /*has_shared_lib=*/false));
97 
98   std::vector<Namespace> namespaces;
99   namespaces.push_back(std::move(foo));
100   namespaces.push_back(std::move(bar));
101   Section section("section", std::move(namespaces));
102 
103   auto result = section.Resolve(ctx);
104   ASSERT_RESULT_OK(result);
105 
106   // See if two namespaces are linked correctly
107   ASSERT_THAT(section.GetNamespace("foo")->GetLink("bar").GetSharedLibs(),
108               Contains("bar.so"));
109 }
110 
TEST(apex_namespace,extra_permitted_paths)111 TEST(apex_namespace, extra_permitted_paths) {
112   Namespace ns("foo");
113   InitializeWithApex(ns,
114                      ApexInfo("com.android.foo",
115                               "/apex/com.android.foo",
116                               /*provide_libs=*/{},
117                               /*require_libs=*/{},
118                               /*jni_libs=*/{},
119                               /*permitted_paths=*/{"/a", "/b/c"},
120                               /*has_bin=*/false,
121                               /*has_lib=*/true,
122                               /*visible=*/false,
123                               /*has_shared_lib=*/false));
124 
125   ConfigWriter writer;
126   ns.WriteConfig(writer);
127   ASSERT_EQ(
128       "namespace.foo.isolated = false\n"
129       "namespace.foo.search.paths = /apex/com.android.foo/${LIB}\n"
130       "namespace.foo.permitted.paths = /apex/com.android.foo/${LIB}\n"
131       "namespace.foo.permitted.paths += /system/${LIB}\n"
132       "namespace.foo.permitted.paths += /a\n"
133       "namespace.foo.permitted.paths += /b/c\n"
134       "namespace.foo.asan.search.paths = /apex/com.android.foo/${LIB}\n"
135       "namespace.foo.asan.permitted.paths = /apex/com.android.foo/${LIB}\n"
136       "namespace.foo.asan.permitted.paths += /data/asan/system/${LIB}\n"
137       "namespace.foo.asan.permitted.paths += /system/${LIB}\n"
138       "namespace.foo.asan.permitted.paths += /data/asan/a\n"
139       "namespace.foo.asan.permitted.paths += /a\n"
140       "namespace.foo.asan.permitted.paths += /data/asan/b/c\n"
141       "namespace.foo.asan.permitted.paths += /b/c\n",
142       writer.ToString());
143 }
144 
TEST_F(ApexTest,scan_apex_dir)145 TEST_F(ApexTest, scan_apex_dir) {
146   PrepareApex("foo", {}, {"bar.so"}, {});
147   WriteFile("/apex/foo/bin/foo", "");
148   PrepareApex("bar", {"bar.so"}, {}, {});
149   WriteFile("/apex/bar/lib64/bar.so", "");
150   PrepareApex("baz", {}, {}, {"baz.so"});
151   WriteFile("/apex/baz/lib64/baz.so", "");
152   CreateApexInfoList();
153   CreatePublicLibrariesTxt();
154 
155   auto apexes = ScanActiveApexes(root);
156   ASSERT_TRUE(apexes.ok()) << "Failed to scan active APEXes : "
157                            << apexes.error();
158   ASSERT_EQ(3U, apexes->size());
159 
160   ASSERT_THAT((*apexes)["foo"].require_libs, Contains("bar.so"));
161   ASSERT_TRUE((*apexes)["foo"].has_bin);
162   ASSERT_FALSE((*apexes)["foo"].has_lib);
163 
164   ASSERT_THAT((*apexes)["bar"].provide_libs, Contains("bar.so"));
165   ASSERT_FALSE((*apexes)["bar"].has_bin);
166   ASSERT_TRUE((*apexes)["bar"].has_lib);
167 
168   ASSERT_THAT((*apexes)["baz"].jni_libs, Contains("baz.so"));
169   ASSERT_FALSE((*apexes)["baz"].has_bin);
170   ASSERT_TRUE((*apexes)["baz"].has_lib);
171 }
172 
TEST_F(ApexTest,validate_path)173 TEST_F(ApexTest, validate_path) {
174   PrepareApex("foo", {}, {}, {});
175   CreateApexInfoList();
176   CreatePublicLibrariesTxt();
177 
178   ::android::linkerconfig::proto::LinkerConfig two_slash;
179   two_slash.add_permittedpaths("/two//slash");
180 
181   WriteFile("/apex/foo/etc/linker.config.pb", two_slash.SerializeAsString());
182   auto apexes = ScanActiveApexes(root);
183   ASSERT_FALSE(apexes.ok()) << "Two slash is not allowed from path string";
184 
185   ::android::linkerconfig::proto::LinkerConfig invalid_char;
186   invalid_char.add_permittedpaths("/path/with*/invalid/char");
187 
188   WriteFile("/apex/foo/etc/linker.config.pb", invalid_char.SerializeAsString());
189   apexes = ScanActiveApexes(root);
190   ASSERT_FALSE(apexes.ok()) << "* is invalid char for path.";
191 
192   ::android::linkerconfig::proto::LinkerConfig end_with_lib;
193   end_with_lib.add_permittedpaths("/somewhere/${LIB}");
194 
195   WriteFile("/apex/foo/etc/linker.config.pb", end_with_lib.SerializeAsString());
196   apexes = ScanActiveApexes(root);
197   ASSERT_TRUE(apexes.ok()) << "Path ends with ${LIB} should be accepted. : "
198                            << apexes.error();
199 
200   ::android::linkerconfig::proto::LinkerConfig lib_plus_char;
201   lib_plus_char.add_permittedpaths("/somewhere/${LIB}x/hw");
202 
203   WriteFile("/apex/foo/etc/linker.config.pb", lib_plus_char.SerializeAsString());
204   apexes = ScanActiveApexes(root);
205   ASSERT_FALSE(apexes.ok())
206       << "There should be no extra char after ${LIB} in path.";
207 
208   ::android::linkerconfig::proto::LinkerConfig char_plus_lib;
209   char_plus_lib.add_permittedpaths("/somewhere/x${LIB}/hw");
210 
211   WriteFile("/apex/foo/etc/linker.config.pb", char_plus_lib.SerializeAsString());
212   apexes = ScanActiveApexes(root);
213   ASSERT_FALSE(apexes.ok())
214       << "There should be no extra char before ${LIB} in path.";
215 
216   ::android::linkerconfig::proto::LinkerConfig lib_and_lib64;
217   lib_and_lib64.add_permittedpaths("/somewhere/${LIB}/hw");
218 
219   WriteFile("/apex/foo/etc/linker.config.pb", lib_and_lib64.SerializeAsString());
220   apexes = ScanActiveApexes(root);
221   ASSERT_TRUE(apexes.ok()) << "Valid path with ${LIB} should be accepted. : "
222                            << apexes.error();
223 }