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