1/*
2 * Copyright (C) 2017 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 "subcontext.h"
18
19#include <unistd.h>
20
21#include <chrono>
22
23#include <android-base/properties.h>
24#include <android-base/strings.h>
25#include <gtest/gtest.h>
26#include <selinux/selinux.h>
27
28#include "builtin_arguments.h"
29#include "test_function_map.h"
30
31using namespace std::literals;
32
33using android::base::GetProperty;
34using android::base::Join;
35using android::base::SetProperty;
36using android::base::Split;
37using android::base::WaitForProperty;
38
39namespace android {
40namespace init {
41
42// I would use test fixtures, but I cannot skip the test if not root with them, so instead we have
43// this test runner.
44template <typename F>
45void RunTest(F&& test_function) {
46    if (getuid() != 0) {
47        GTEST_LOG_(INFO) << "Skipping test, must be run as root.";
48        return;
49    }
50
51    char* context;
52    ASSERT_EQ(0, getcon(&context));
53    auto context_string = std::string(context);
54    free(context);
55
56    auto subcontext = Subcontext("dummy_path", context_string);
57    ASSERT_NE(0, subcontext.pid());
58
59    test_function(subcontext, context_string);
60
61    if (subcontext.pid() > 0) {
62        kill(subcontext.pid(), SIGTERM);
63        kill(subcontext.pid(), SIGKILL);
64    }
65}
66
67TEST(subcontext, CheckDifferentPid) {
68    RunTest([](auto& subcontext, auto& context_string) {
69        auto result = subcontext.Execute(std::vector<std::string>{"return_pids_as_error"});
70        ASSERT_FALSE(result);
71
72        auto pids = Split(result.error_string(), " ");
73        ASSERT_EQ(2U, pids.size());
74        auto our_pid = std::to_string(getpid());
75        EXPECT_NE(our_pid, pids[0]);
76        EXPECT_EQ(our_pid, pids[1]);
77    });
78}
79
80TEST(subcontext, SetProp) {
81    RunTest([](auto& subcontext, auto& context_string) {
82        SetProperty("init.test.subcontext", "fail");
83        WaitForProperty("init.test.subcontext", "fail");
84
85        auto args = std::vector<std::string>{
86            "setprop",
87            "init.test.subcontext",
88            "success",
89        };
90        auto result = subcontext.Execute(args);
91        ASSERT_TRUE(result) << result.error();
92
93        EXPECT_TRUE(WaitForProperty("init.test.subcontext", "success", 10s));
94    });
95}
96
97TEST(subcontext, MultipleCommands) {
98    RunTest([](auto& subcontext, auto& context_string) {
99        auto first_pid = subcontext.pid();
100
101        auto expected_words = std::vector<std::string>{
102            "this",
103            "is",
104            "a",
105            "test",
106        };
107
108        for (const auto& word : expected_words) {
109            auto args = std::vector<std::string>{
110                "add_word",
111                word,
112            };
113            auto result = subcontext.Execute(args);
114            ASSERT_TRUE(result) << result.error();
115        }
116
117        auto result = subcontext.Execute(std::vector<std::string>{"return_words_as_error"});
118        ASSERT_FALSE(result);
119        EXPECT_EQ(Join(expected_words, " "), result.error_string());
120        EXPECT_EQ(first_pid, subcontext.pid());
121    });
122}
123
124TEST(subcontext, RecoverAfterAbort) {
125    RunTest([](auto& subcontext, auto& context_string) {
126        auto first_pid = subcontext.pid();
127
128        auto result = subcontext.Execute(std::vector<std::string>{"cause_log_fatal"});
129        ASSERT_FALSE(result);
130
131        auto result2 = subcontext.Execute(std::vector<std::string>{"generate_sane_error"});
132        ASSERT_FALSE(result2);
133        EXPECT_EQ("Sane error!", result2.error_string());
134        EXPECT_NE(subcontext.pid(), first_pid);
135    });
136}
137
138TEST(subcontext, ContextString) {
139    RunTest([](auto& subcontext, auto& context_string) {
140        auto result = subcontext.Execute(std::vector<std::string>{"return_context_as_error"});
141        ASSERT_FALSE(result);
142        ASSERT_EQ(context_string, result.error_string());
143    });
144}
145
146TEST(subcontext, ExpandArgs) {
147    RunTest([](auto& subcontext, auto& context_string) {
148        auto args = std::vector<std::string>{
149            "first",
150            "${ro.hardware}",
151            "$$third",
152        };
153        auto result = subcontext.ExpandArgs(args);
154        ASSERT_TRUE(result) << result.error();
155        ASSERT_EQ(3U, result->size());
156        EXPECT_EQ(args[0], result->at(0));
157        EXPECT_EQ(GetProperty("ro.hardware", ""), result->at(1));
158        EXPECT_EQ("$third", result->at(2));
159    });
160}
161
162TEST(subcontext, ExpandArgsFailure) {
163    RunTest([](auto& subcontext, auto& context_string) {
164        auto args = std::vector<std::string>{
165            "first",
166            "${",
167        };
168        auto result = subcontext.ExpandArgs(args);
169        ASSERT_FALSE(result);
170        EXPECT_EQ("Failed to expand '" + args[1] + "'", result.error_string());
171    });
172}
173
174TestFunctionMap BuildTestFunctionMap() {
175    TestFunctionMap test_function_map;
176    // For CheckDifferentPid
177    test_function_map.Add("return_pids_as_error", 0, 0, true,
178                          [](const BuiltinArguments& args) -> Result<Success> {
179                              return Error() << getpid() << " " << getppid();
180                          });
181
182    // For SetProp
183    test_function_map.Add("setprop", 2, 2, true, [](const BuiltinArguments& args) {
184        android::base::SetProperty(args[1], args[2]);
185        return Success();
186    });
187
188    // For MultipleCommands
189    // Using a shared_ptr to extend lifetime of words to both lambdas
190    auto words = std::make_shared<std::vector<std::string>>();
191    test_function_map.Add("add_word", 1, 1, true, [words](const BuiltinArguments& args) {
192        words->emplace_back(args[1]);
193        return Success();
194    });
195    test_function_map.Add("return_words_as_error", 0, 0, true,
196                          [words](const BuiltinArguments& args) -> Result<Success> {
197                              return Error() << Join(*words, " ");
198                          });
199
200    // For RecoverAfterAbort
201    test_function_map.Add("cause_log_fatal", 0, 0, true,
202                          [](const BuiltinArguments& args) -> Result<Success> {
203                              return Error() << std::string(4097, 'f');
204                          });
205    test_function_map.Add(
206        "generate_sane_error", 0, 0, true,
207        [](const BuiltinArguments& args) -> Result<Success> { return Error() << "Sane error!"; });
208
209    // For ContextString
210    test_function_map.Add(
211        "return_context_as_error", 0, 0, true,
212        [](const BuiltinArguments& args) -> Result<Success> { return Error() << args.context; });
213
214    return test_function_map;
215}
216
217}  // namespace init
218}  // namespace android
219
220int main(int argc, char** argv) {
221    if (argc > 1 && !strcmp(basename(argv[1]), "subcontext")) {
222        auto test_function_map = android::init::BuildTestFunctionMap();
223        return android::init::SubcontextMain(argc, argv, &test_function_map);
224    }
225
226    testing::InitGoogleTest(&argc, argv);
227    return RUN_ALL_TESTS();
228}
229