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