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 
TEST(SimpleProcess,Basic)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 
TEST(SimpleProcess,NoSearchPath)54 TEST(SimpleProcess, NoSearchPath) {
55   ProcessImpl process;
56   process.AddArg("echo");
57   EXPECT_EQ(127, process.Run());
58 }
59 
TEST(SimpleProcess,SearchPath)60 TEST(SimpleProcess, SearchPath) {
61   ProcessImpl process;
62   process.AddArg("echo");
63   process.SetSearchPath(true);
64   EXPECT_EQ(EXIT_SUCCESS, process.Run());
65 }
66 
TEST(SimpleProcess,BindFd)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.
TEST(DISABLED_SimpleProcess,BindFdToSameFd)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:
SetUp()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 
SetUpTestCase()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 
TEST_F(ProcessTest,Basic)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 
TEST_F(ProcessTest,AddStringOption)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 
TEST_F(ProcessTest,AddIntValue)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 
TEST_F(ProcessTest,NonZeroReturnValue)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 
TEST_F(ProcessTest,BadOutputFile)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 
TEST_F(ProcessTest,BadExecutable)166 TEST_F(ProcessTest, BadExecutable) {
167   process_.AddArg("false");
168   EXPECT_EQ(static_cast<pid_t>(Process::kErrorExitStatus), process_.Run());
169 }
170 
CheckStderrCaptured()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 
TEST_F(ProcessTest,StderrCaptured)182 TEST_F(ProcessTest, StderrCaptured) {
183   CheckStderrCaptured();
184 }
185 
TEST_F(ProcessTest,StderrCapturedWhenPreviouslyClosed)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 
GetFdPath(int fd)193 FilePath ProcessTest::GetFdPath(int fd) {
194   return FilePath(base::StringPrintf("/proc/self/fd/%d", fd));
195 }
196 
TEST_F(ProcessTest,RedirectStderrUsingPipe)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 
TEST_F(ProcessTest,RedirectStderrUsingPipeWhenPreviouslyClosed)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 
TEST_F(ProcessTest,RedirectStdoutUsingPipe)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 
TEST_F(ProcessTest,RedirectStdinUsingPipe)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 
TEST_F(ProcessTest,WithSameUid)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 
TEST_F(ProcessTest,WithSameGid)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 
TEST_F(ProcessTest,WithIllegalUid)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 
TEST_F(ProcessTest,WithIllegalGid)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 
TEST_F(ProcessTest,NoParams)292 TEST_F(ProcessTest, NoParams) {
293   EXPECT_EQ(-1, process_.Run());
294 }
295 
296 #if !defined(__BIONIC__)  // Bionic intercepts the segfault on Android.
TEST_F(ProcessTest,SegFaultHandling)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 
TEST_F(ProcessTest,KillHandling)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 
TEST_F(ProcessTest,KillNoPid)315 TEST_F(ProcessTest, KillNoPid) {
316   process_.Kill(SIGTERM, 0);
317   EXPECT_TRUE(FindLog("Process not running"));
318 }
319 
TEST_F(ProcessTest,ProcessExists)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 
TEST_F(ProcessTest,ResetPidByFile)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 
TEST_F(ProcessTest,KillSleeper)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 
TEST_F(ProcessTest,Reset)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 
ReturnFalse()356 bool ReturnFalse() { return false; }
357 
TEST_F(ProcessTest,PreExecCallback)358 TEST_F(ProcessTest, PreExecCallback) {
359   process_.AddArg(kBinTrue);
360   process_.SetPreExecCallback(base::Bind(&ReturnFalse));
361   ASSERT_NE(0, process_.Run());
362 }
363 
TEST_F(ProcessTest,LeakUnusedFileDescriptors)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 
TEST_F(ProcessTest,CloseUnusedFileDescriptors)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