1 // Copyright (c) 2012 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "brillo/process.h" 6 7 #include <unistd.h> 8 9 #include <base/files/file_path.h> 10 #include <base/files/file_util.h> 11 #include <base/files/scoped_temp_dir.h> 12 #include <gtest/gtest.h> 13 14 #include "brillo/process_mock.h" 15 #include "brillo/unittest_utils.h" 16 #include "brillo/test_helpers.h" 17 18 using base::FilePath; 19 20 // This test assumes the following standard binaries are installed. 21 #if defined(__ANDROID__) 22 # define SYSTEM_PREFIX "/system" 23 static const char kBinStat[] = SYSTEM_PREFIX "/bin/stat"; 24 #else 25 # define SYSTEM_PREFIX "" 26 static const char kBinStat[] = "/usr/bin/stat"; 27 #endif 28 29 static const char kBinSh[] = SYSTEM_PREFIX "/bin/sh"; 30 static const char kBinCat[] = SYSTEM_PREFIX "/bin/cat"; 31 static const char kBinEcho[] = SYSTEM_PREFIX "/bin/echo"; 32 static const char kBinFalse[] = SYSTEM_PREFIX "/bin/false"; 33 static const char kBinSleep[] = SYSTEM_PREFIX "/bin/sleep"; 34 static const char kBinTrue[] = SYSTEM_PREFIX "/bin/true"; 35 36 namespace brillo { 37 38 // Test that the mock has all the functions of the interface by 39 // instantiating it. This variable is not used elsewhere. 40 struct CompileMocks { 41 ProcessMock process_mock; 42 }; 43 44 TEST(SimpleProcess, Basic) { 45 // Log must be cleared before running this test, just as ProcessTest::SetUp. 46 ClearLog(); 47 ProcessImpl process; 48 process.AddArg(kBinEcho); 49 EXPECT_EQ(0, process.Run()); 50 EXPECT_EQ("", GetLog()); 51 } 52 53 TEST(SimpleProcess, NoSearchPath) { 54 ProcessImpl process; 55 process.AddArg("echo"); 56 EXPECT_EQ(127, process.Run()); 57 } 58 59 TEST(SimpleProcess, SearchPath) { 60 ProcessImpl process; 61 process.AddArg("echo"); 62 process.SetSearchPath(true); 63 EXPECT_EQ(EXIT_SUCCESS, process.Run()); 64 } 65 66 TEST(SimpleProcess, BindFd) { 67 int fds[2]; 68 char buf[16]; 69 static const char* kMsg = "hello, world!"; 70 ProcessImpl process; 71 EXPECT_EQ(0, pipe(fds)); 72 process.AddArg(kBinEcho); 73 process.AddArg(kMsg); 74 process.BindFd(fds[1], 1); 75 process.Run(); 76 memset(buf, 0, sizeof(buf)); 77 EXPECT_EQ(read(fds[0], buf, sizeof(buf) - 1), strlen(kMsg) + 1); 78 EXPECT_EQ(std::string(kMsg) + "\n", std::string(buf)); 79 } 80 81 // The test framework uses the device's dash shell as "sh", which doesn't 82 // support redirecting stdout to arbitrary large file descriptor numbers 83 // directly, nor has /proc mounted to open /proc/self/fd/NN. This test would 84 // fail if pipe.writer is big enough. 85 // TODO(deymo): Write a helper program that writes "hello_world" to the passed 86 // file descriptor and re-enabled this test. 87 TEST(DISABLED_SimpleProcess, BindFdToSameFd) { 88 static const char* kMsg = "hello_world"; 89 ScopedPipe pipe; 90 ProcessImpl process; 91 process.AddArg(kBinSh); 92 process.AddArg("-c"); 93 process.AddArg(base::StringPrintf("echo %s >&%d", kMsg, pipe.writer)); 94 process.BindFd(pipe.writer, pipe.writer); 95 process.Run(); 96 close(pipe.writer); 97 pipe.writer = -1; 98 99 char buf[16]; 100 memset(buf, 0, sizeof(buf)); 101 EXPECT_EQ(read(pipe.reader, buf, sizeof(buf) - 1), strlen(kMsg) + 1); 102 EXPECT_EQ(std::string(kMsg) + "\n", std::string(buf)); 103 } 104 105 class ProcessTest : public ::testing::Test { 106 public: 107 void SetUp() { 108 CHECK(temp_dir_.CreateUniqueTempDir()); 109 output_file_ = temp_dir_.GetPath().Append("fork_out").value(); 110 process_.RedirectOutput(output_file_); 111 ClearLog(); 112 } 113 114 static void SetUpTestCase() { 115 base::CommandLine::Init(0, nullptr); 116 ::brillo::InitLog(brillo::kLogToStderr); 117 ::brillo::LogToString(true); 118 } 119 120 protected: 121 void CheckStderrCaptured(); 122 FilePath GetFdPath(int fd); 123 124 ProcessImpl process_; 125 std::vector<const char*> args_; 126 std::string output_file_; 127 base::ScopedTempDir temp_dir_; 128 }; 129 130 TEST_F(ProcessTest, Basic) { 131 process_.AddArg(kBinEcho); 132 process_.AddArg("hello world"); 133 EXPECT_EQ(0, process_.Run()); 134 ExpectFileEquals("hello world\n", output_file_.c_str()); 135 EXPECT_EQ("", GetLog()); 136 } 137 138 TEST_F(ProcessTest, AddStringOption) { 139 process_.AddArg(kBinEcho); 140 process_.AddStringOption("--hello", "world"); 141 EXPECT_EQ(0, process_.Run()); 142 ExpectFileEquals("--hello world\n", output_file_.c_str()); 143 } 144 145 TEST_F(ProcessTest, AddIntValue) { 146 process_.AddArg(kBinEcho); 147 process_.AddIntOption("--answer", 42); 148 EXPECT_EQ(0, process_.Run()); 149 ExpectFileEquals("--answer 42\n", output_file_.c_str()); 150 } 151 152 TEST_F(ProcessTest, NonZeroReturnValue) { 153 process_.AddArg(kBinFalse); 154 EXPECT_EQ(1, process_.Run()); 155 ExpectFileEquals("", output_file_.c_str()); 156 EXPECT_EQ("", GetLog()); 157 } 158 159 TEST_F(ProcessTest, RedirectInputDevNull) { 160 process_.AddArg(kBinCat); 161 process_.RedirectInput("/dev/null"); 162 EXPECT_EQ(0, process_.Run()); 163 } 164 165 TEST_F(ProcessTest, BadInputFile) { 166 process_.AddArg(kBinCat); 167 process_.RedirectInput("/bad/path"); 168 EXPECT_EQ(static_cast<pid_t>(Process::kErrorExitStatus), process_.Run()); 169 } 170 171 TEST_F(ProcessTest, BadOutputFile) { 172 process_.AddArg(kBinEcho); 173 process_.RedirectOutput("/bad/path"); 174 EXPECT_EQ(static_cast<pid_t>(Process::kErrorExitStatus), process_.Run()); 175 } 176 177 TEST_F(ProcessTest, BadExecutable) { 178 process_.AddArg("false"); 179 EXPECT_EQ(static_cast<pid_t>(Process::kErrorExitStatus), process_.Run()); 180 } 181 182 void ProcessTest::CheckStderrCaptured() { 183 process_.AddArg(kBinSh); 184 process_.AddArg("-c"); 185 process_.AddArg("echo errormessage 1>&2 && exit 1"); 186 EXPECT_EQ(1, process_.Run()); 187 std::string contents; 188 EXPECT_TRUE(base::ReadFileToString(FilePath(output_file_), &contents)); 189 EXPECT_NE(std::string::npos, contents.find("errormessage")); 190 EXPECT_EQ("", GetLog()); 191 } 192 193 TEST_F(ProcessTest, StderrCaptured) { 194 CheckStderrCaptured(); 195 } 196 197 TEST_F(ProcessTest, StderrCapturedWhenPreviouslyClosed) { 198 int saved_stderr = dup(STDERR_FILENO); 199 close(STDERR_FILENO); 200 CheckStderrCaptured(); 201 dup2(saved_stderr, STDERR_FILENO); 202 } 203 204 FilePath ProcessTest::GetFdPath(int fd) { 205 return FilePath(base::StringPrintf("/proc/self/fd/%d", fd)); 206 } 207 208 TEST_F(ProcessTest, RedirectStderrUsingPipe) { 209 process_.RedirectOutput(""); 210 process_.AddArg(kBinSh); 211 process_.AddArg("-c"); 212 process_.AddArg("echo errormessage >&2 && exit 1"); 213 process_.RedirectUsingPipe(STDERR_FILENO, false); 214 EXPECT_EQ(-1, process_.GetPipe(STDERR_FILENO)); 215 EXPECT_EQ(1, process_.Run()); 216 int pipe_fd = process_.GetPipe(STDERR_FILENO); 217 EXPECT_GE(pipe_fd, 0); 218 EXPECT_EQ(-1, process_.GetPipe(STDOUT_FILENO)); 219 EXPECT_EQ(-1, process_.GetPipe(STDIN_FILENO)); 220 std::string contents; 221 EXPECT_TRUE(base::ReadFileToString(GetFdPath(pipe_fd), &contents)); 222 EXPECT_NE(std::string::npos, contents.find("errormessage")); 223 EXPECT_EQ("", GetLog()); 224 } 225 226 TEST_F(ProcessTest, RedirectStderrUsingPipeWhenPreviouslyClosed) { 227 int saved_stderr = dup(STDERR_FILENO); 228 close(STDERR_FILENO); 229 process_.RedirectOutput(""); 230 process_.AddArg(kBinSh); 231 process_.AddArg("-c"); 232 process_.AddArg("echo errormessage >&2 && exit 1"); 233 process_.RedirectUsingPipe(STDERR_FILENO, false); 234 EXPECT_EQ(1, process_.Run()); 235 int pipe_fd = process_.GetPipe(STDERR_FILENO); 236 EXPECT_GE(pipe_fd, 0); 237 EXPECT_EQ(-1, process_.GetPipe(STDOUT_FILENO)); 238 EXPECT_EQ(-1, process_.GetPipe(STDIN_FILENO)); 239 std::string contents; 240 EXPECT_TRUE(base::ReadFileToString(GetFdPath(pipe_fd), &contents)); 241 EXPECT_NE(std::string::npos, contents.find("errormessage")); 242 EXPECT_EQ("", GetLog()); 243 dup2(saved_stderr, STDERR_FILENO); 244 } 245 246 TEST_F(ProcessTest, RedirectStdoutUsingPipe) { 247 process_.RedirectOutput(""); 248 process_.AddArg(kBinEcho); 249 process_.AddArg("hello world\n"); 250 process_.RedirectUsingPipe(STDOUT_FILENO, false); 251 EXPECT_EQ(-1, process_.GetPipe(STDOUT_FILENO)); 252 EXPECT_EQ(0, process_.Run()); 253 int pipe_fd = process_.GetPipe(STDOUT_FILENO); 254 EXPECT_GE(pipe_fd, 0); 255 EXPECT_EQ(-1, process_.GetPipe(STDERR_FILENO)); 256 EXPECT_EQ(-1, process_.GetPipe(STDIN_FILENO)); 257 std::string contents; 258 EXPECT_TRUE(base::ReadFileToString(GetFdPath(pipe_fd), &contents)); 259 EXPECT_NE(std::string::npos, contents.find("hello world\n")); 260 EXPECT_EQ("", GetLog()); 261 } 262 263 TEST_F(ProcessTest, RedirectStdinUsingPipe) { 264 const char kMessage[] = "made it!\n"; 265 process_.AddArg(kBinCat); 266 process_.RedirectUsingPipe(STDIN_FILENO, true); 267 process_.RedirectOutput(output_file_); 268 EXPECT_TRUE(process_.Start()); 269 int write_fd = process_.GetPipe(STDIN_FILENO); 270 EXPECT_EQ(-1, process_.GetPipe(STDERR_FILENO)); 271 EXPECT_TRUE(base::WriteFile(GetFdPath(write_fd), kMessage, strlen(kMessage))); 272 close(write_fd); 273 EXPECT_EQ(0, process_.Wait()); 274 ExpectFileEquals(kMessage, output_file_.c_str()); 275 } 276 277 TEST_F(ProcessTest, WithSameUid) { 278 gid_t uid = geteuid(); 279 process_.AddArg(kBinEcho); 280 process_.SetUid(uid); 281 EXPECT_EQ(0, process_.Run()); 282 } 283 284 TEST_F(ProcessTest, WithSameGid) { 285 gid_t gid = getegid(); 286 process_.AddArg(kBinEcho); 287 process_.SetGid(gid); 288 EXPECT_EQ(0, process_.Run()); 289 } 290 291 TEST_F(ProcessTest, WithIllegalUid) { 292 ASSERT_NE(0, geteuid()); 293 process_.AddArg(kBinEcho); 294 process_.SetUid(0); 295 EXPECT_EQ(static_cast<pid_t>(Process::kErrorExitStatus), process_.Run()); 296 std::string contents; 297 EXPECT_TRUE(base::ReadFileToString(FilePath(output_file_), &contents)); 298 EXPECT_NE(std::string::npos, contents.find("Unable to set UID to 0: 1\n")); 299 } 300 301 TEST_F(ProcessTest, WithIllegalGid) { 302 ASSERT_NE(0, getegid()); 303 process_.AddArg(kBinEcho); 304 process_.SetGid(0); 305 EXPECT_EQ(static_cast<pid_t>(Process::kErrorExitStatus), process_.Run()); 306 std::string contents; 307 EXPECT_TRUE(base::ReadFileToString(FilePath(output_file_), &contents)); 308 EXPECT_NE(std::string::npos, contents.find("Unable to set GID to 0: 1\n")); 309 } 310 311 TEST_F(ProcessTest, NoParams) { 312 EXPECT_EQ(-1, process_.Run()); 313 } 314 315 #if !defined(__BIONIC__) // Bionic intercepts the segfault on Android. 316 TEST_F(ProcessTest, SegFaultHandling) { 317 process_.AddArg(kBinSh); 318 process_.AddArg("-c"); 319 process_.AddArg("kill -SEGV $$"); 320 EXPECT_EQ(-1, process_.Run()); 321 EXPECT_TRUE(FindLog("did not exit normally: 11")); 322 } 323 #endif 324 325 TEST_F(ProcessTest, KillHandling) { 326 process_.AddArg(kBinSh); 327 process_.AddArg("-c"); 328 process_.AddArg("kill -KILL $$"); 329 EXPECT_EQ(-1, process_.Run()); 330 EXPECT_TRUE(FindLog("did not exit normally: 9")); 331 } 332 333 334 TEST_F(ProcessTest, KillNoPid) { 335 process_.Kill(SIGTERM, 0); 336 EXPECT_TRUE(FindLog("Process not running")); 337 } 338 339 TEST_F(ProcessTest, ProcessExists) { 340 EXPECT_FALSE(Process::ProcessExists(0)); 341 EXPECT_TRUE(Process::ProcessExists(1)); 342 EXPECT_TRUE(Process::ProcessExists(getpid())); 343 } 344 345 TEST_F(ProcessTest, ResetPidByFile) { 346 FilePath pid_path = temp_dir_.GetPath().Append("pid"); 347 EXPECT_FALSE(process_.ResetPidByFile(pid_path.value())); 348 EXPECT_TRUE(base::WriteFile(pid_path, "456\n", 4)); 349 EXPECT_TRUE(process_.ResetPidByFile(pid_path.value())); 350 EXPECT_EQ(456, process_.pid()); 351 // The purpose of this unit test is to check if Process::ResetPidByFile() can 352 // properly read a pid from a file. We don't really want to kill the process 353 // with pid 456, so update the pid to 0 to prevent the Process destructor from 354 // killing any innocent process. 355 process_.UpdatePid(0); 356 } 357 358 TEST_F(ProcessTest, KillSleeper) { 359 process_.AddArg(kBinSleep); 360 process_.AddArg("10000"); 361 ASSERT_TRUE(process_.Start()); 362 pid_t pid = process_.pid(); 363 ASSERT_GT(pid, 1); 364 EXPECT_TRUE(process_.Kill(SIGTERM, 1)); 365 EXPECT_EQ(0, process_.pid()); 366 } 367 368 TEST_F(ProcessTest, Reset) { 369 process_.AddArg(kBinFalse); 370 process_.Reset(0); 371 process_.AddArg(kBinEcho); 372 EXPECT_EQ(0, process_.Run()); 373 } 374 375 bool ReturnFalse() { return false; } 376 377 TEST_F(ProcessTest, PreExecCallback) { 378 process_.AddArg(kBinTrue); 379 process_.SetPreExecCallback(base::Bind(&ReturnFalse)); 380 ASSERT_NE(0, process_.Run()); 381 } 382 383 TEST_F(ProcessTest, LeakUnusedFileDescriptors) { 384 ScopedPipe pipe; 385 process_.AddArg(kBinStat); 386 process_.AddArg(GetFdPath(pipe.reader).value()); 387 process_.AddArg(GetFdPath(pipe.writer).value()); 388 process_.SetCloseUnusedFileDescriptors(false); 389 EXPECT_EQ(0, process_.Run()); 390 } 391 392 TEST_F(ProcessTest, CloseUnusedFileDescriptors) { 393 ScopedPipe pipe; 394 process_.AddArg(kBinStat); 395 process_.AddArg(GetFdPath(pipe.reader).value()); 396 process_.AddArg(GetFdPath(pipe.writer).value()); 397 process_.SetCloseUnusedFileDescriptors(true); 398 // Stat should fail when running on these file descriptor because the files 399 // should not be there. 400 EXPECT_EQ(1, process_.Run()); 401 } 402 403 } // namespace brillo 404