1 //
2 // Copyright (C) 2012 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 "update_engine/common/subprocess.h"
18 
19 #include <fcntl.h>
20 #include <poll.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23 
24 #include <set>
25 #include <string>
26 #include <vector>
27 
28 #include <base/bind.h>
29 #include <base/files/scoped_temp_dir.h>
30 #include <base/location.h>
31 #include <base/message_loop/message_loop.h>
32 #include <base/strings/string_util.h>
33 #include <base/strings/stringprintf.h>
34 #include <base/time/time.h>
35 #include <brillo/bind_lambda.h>
36 #include <brillo/message_loops/base_message_loop.h>
37 #include <brillo/message_loops/message_loop.h>
38 #include <brillo/message_loops/message_loop_utils.h>
39 #include <brillo/strings/string_utils.h>
40 #include <brillo/unittest_utils.h>
41 #include <gtest/gtest.h>
42 
43 #include "update_engine/common/test_utils.h"
44 #include "update_engine/common/utils.h"
45 
46 using base::TimeDelta;
47 using brillo::MessageLoop;
48 using std::string;
49 using std::vector;
50 
51 namespace {
52 
53 #ifdef __ANDROID__
54 #define kBinPath "/system/bin"
55 #define kUsrBinPath "/system/bin"
56 #else
57 #define kBinPath "/bin"
58 #define kUsrBinPath "/usr/bin"
59 #endif  // __ANDROID__
60 
61 }  // namespace
62 
63 namespace chromeos_update_engine {
64 
65 class SubprocessTest : public ::testing::Test {
66  protected:
SetUp()67   void SetUp() override {
68     loop_.SetAsCurrent();
69     async_signal_handler_.Init();
70     subprocess_.Init(&async_signal_handler_);
71   }
72 
73   base::MessageLoopForIO base_loop_;
74   brillo::BaseMessageLoop loop_{&base_loop_};
75   brillo::AsynchronousSignalHandler async_signal_handler_;
76   Subprocess subprocess_;
77 };
78 
79 namespace {
80 
ExpectedResults(int expected_return_code,const string & expected_output,int return_code,const string & output)81 void ExpectedResults(int expected_return_code, const string& expected_output,
82                      int return_code, const string& output) {
83   EXPECT_EQ(expected_return_code, return_code);
84   EXPECT_EQ(expected_output, output);
85   MessageLoop::current()->BreakLoop();
86 }
87 
ExpectedEnvVars(int return_code,const string & output)88 void ExpectedEnvVars(int return_code, const string& output) {
89   EXPECT_EQ(0, return_code);
90   const std::set<string> allowed_envs = {"LD_LIBRARY_PATH", "PATH"};
91   for (const string& key_value : brillo::string_utils::Split(output, "\n")) {
92     auto key_value_pair = brillo::string_utils::SplitAtFirst(
93         key_value, "=", true);
94     EXPECT_NE(allowed_envs.end(), allowed_envs.find(key_value_pair.first));
95   }
96   MessageLoop::current()->BreakLoop();
97 }
98 
ExpectedDataOnPipe(const Subprocess * subprocess,pid_t * pid,int child_fd,const string & child_fd_data,int expected_return_code,int return_code,const string &)99 void ExpectedDataOnPipe(const Subprocess* subprocess,
100                         pid_t* pid,
101                         int child_fd,
102                         const string& child_fd_data,
103                         int expected_return_code,
104                         int return_code,
105                         const string& /* output */) {
106   EXPECT_EQ(expected_return_code, return_code);
107 
108   // Verify that we can read the data from our end of |child_fd|.
109   int fd = subprocess->GetPipeFd(*pid, child_fd);
110   EXPECT_NE(-1, fd);
111   vector<char> buf(child_fd_data.size() + 1);
112   EXPECT_EQ(static_cast<ssize_t>(child_fd_data.size()),
113             HANDLE_EINTR(read(fd, buf.data(), buf.size())));
114   EXPECT_EQ(child_fd_data,
115             string(buf.begin(), buf.begin() + child_fd_data.size()));
116 
117   MessageLoop::current()->BreakLoop();
118 }
119 
120 }  // namespace
121 
TEST_F(SubprocessTest,IsASingleton)122 TEST_F(SubprocessTest, IsASingleton) {
123   EXPECT_EQ(&subprocess_, &Subprocess::Get());
124 }
125 
TEST_F(SubprocessTest,InactiveInstancesDontChangeTheSingleton)126 TEST_F(SubprocessTest, InactiveInstancesDontChangeTheSingleton) {
127   std::unique_ptr<Subprocess> another_subprocess(new Subprocess());
128   EXPECT_EQ(&subprocess_, &Subprocess::Get());
129   another_subprocess.reset();
130   EXPECT_EQ(&subprocess_, &Subprocess::Get());
131 }
132 
TEST_F(SubprocessTest,SimpleTest)133 TEST_F(SubprocessTest, SimpleTest) {
134   EXPECT_TRUE(subprocess_.Exec({kBinPath "/false"},
135                                base::Bind(&ExpectedResults, 1, "")));
136   loop_.Run();
137 }
138 
TEST_F(SubprocessTest,EchoTest)139 TEST_F(SubprocessTest, EchoTest) {
140   EXPECT_TRUE(subprocess_.Exec(
141       {kBinPath "/sh", "-c", "echo this is stdout; echo this is stderr >&2"},
142       base::Bind(&ExpectedResults, 0, "this is stdout\nthis is stderr\n")));
143   loop_.Run();
144 }
145 
TEST_F(SubprocessTest,StderrNotIncludedInOutputTest)146 TEST_F(SubprocessTest, StderrNotIncludedInOutputTest) {
147   EXPECT_TRUE(subprocess_.ExecFlags(
148       {kBinPath "/sh", "-c", "echo on stdout; echo on stderr >&2"},
149       0,
150       {},
151       base::Bind(&ExpectedResults, 0, "on stdout\n")));
152   loop_.Run();
153 }
154 
TEST_F(SubprocessTest,PipeRedirectFdTest)155 TEST_F(SubprocessTest, PipeRedirectFdTest) {
156   pid_t pid;
157   pid = subprocess_.ExecFlags(
158       {kBinPath "/sh", "-c", "echo on pipe >&3"},
159       0,
160       {3},
161       base::Bind(&ExpectedDataOnPipe, &subprocess_, &pid, 3, "on pipe\n", 0));
162   EXPECT_NE(0, pid);
163 
164   // Wrong file descriptor values should return -1.
165   EXPECT_EQ(-1, subprocess_.GetPipeFd(pid, 123));
166   loop_.Run();
167   // Calling GetPipeFd() after the callback runs is invalid.
168   EXPECT_EQ(-1, subprocess_.GetPipeFd(pid, 3));
169 }
170 
171 // Test that a pipe file descriptor open in the parent is not open in the child.
TEST_F(SubprocessTest,PipeClosedWhenNotRedirectedTest)172 TEST_F(SubprocessTest, PipeClosedWhenNotRedirectedTest) {
173   brillo::ScopedPipe pipe;
174 
175   // test_subprocess will return with the errno of fstat, which should be EBADF
176   // if the passed file descriptor is closed in the child.
177   const vector<string> cmd = {
178       test_utils::GetBuildArtifactsPath("test_subprocess"),
179       "fstat",
180       std::to_string(pipe.writer)};
181   EXPECT_TRUE(subprocess_.ExecFlags(
182       cmd, 0, {}, base::Bind(&ExpectedResults, EBADF, "")));
183   loop_.Run();
184 }
185 
TEST_F(SubprocessTest,EnvVarsAreFiltered)186 TEST_F(SubprocessTest, EnvVarsAreFiltered) {
187   EXPECT_TRUE(
188       subprocess_.Exec({kUsrBinPath "/env"}, base::Bind(&ExpectedEnvVars)));
189   loop_.Run();
190 }
191 
TEST_F(SubprocessTest,SynchronousTrueSearchsOnPath)192 TEST_F(SubprocessTest, SynchronousTrueSearchsOnPath) {
193   int rc = -1;
194   EXPECT_TRUE(Subprocess::SynchronousExecFlags(
195       {"true"}, Subprocess::kSearchPath, &rc, nullptr));
196   EXPECT_EQ(0, rc);
197 }
198 
TEST_F(SubprocessTest,SynchronousEchoTest)199 TEST_F(SubprocessTest, SynchronousEchoTest) {
200   vector<string> cmd = {
201       kBinPath "/sh",
202       "-c",
203       "echo -n stdout-here; echo -n stderr-there >&2"};
204   int rc = -1;
205   string stdout;
206   ASSERT_TRUE(Subprocess::SynchronousExec(cmd, &rc, &stdout));
207   EXPECT_EQ(0, rc);
208   EXPECT_EQ("stdout-herestderr-there", stdout);
209 }
210 
TEST_F(SubprocessTest,SynchronousEchoNoOutputTest)211 TEST_F(SubprocessTest, SynchronousEchoNoOutputTest) {
212   int rc = -1;
213   ASSERT_TRUE(Subprocess::SynchronousExec(
214       {kBinPath "/sh", "-c", "echo test"}, &rc, nullptr));
215   EXPECT_EQ(0, rc);
216 }
217 
218 namespace {
CallbackBad(int return_code,const string & output)219 void CallbackBad(int return_code, const string& output) {
220   ADD_FAILURE() << "should never be called.";
221 }
222 }  // namespace
223 
224 // Test that you can cancel a program that's already running.
TEST_F(SubprocessTest,CancelTest)225 TEST_F(SubprocessTest, CancelTest) {
226   base::ScopedTempDir tempdir;
227   ASSERT_TRUE(tempdir.CreateUniqueTempDir());
228   string fifo_path = tempdir.path().Append("fifo").value();
229   EXPECT_EQ(0, mkfifo(fifo_path.c_str(), 0666));
230 
231   // Start a process, make sure it is running and try to cancel it. We write
232   // two bytes to the fifo, the first one marks that the program is running and
233   // the second one marks that the process waited for a timeout and was not
234   // killed. We should read the first byte but not the second one.
235   vector<string> cmd = {
236       kBinPath "/sh",
237       "-c",
238       base::StringPrintf(
239           "echo -n  X >\"%s\"; sleep 60; echo -n  Y >\"%s\"; exit 1",
240           fifo_path.c_str(),
241           fifo_path.c_str())};
242   uint32_t tag = Subprocess::Get().Exec(cmd, base::Bind(&CallbackBad));
243   EXPECT_NE(0U, tag);
244 
245   int fifo_fd = HANDLE_EINTR(open(fifo_path.c_str(), O_RDONLY));
246   EXPECT_GE(fifo_fd, 0);
247 
248   loop_.WatchFileDescriptor(FROM_HERE,
249                             fifo_fd,
250                             MessageLoop::WatchMode::kWatchRead,
251                             false,
252                             base::Bind([](int fifo_fd, uint32_t tag) {
253                               char c;
254                               EXPECT_EQ(1, HANDLE_EINTR(read(fifo_fd, &c, 1)));
255                               EXPECT_EQ('X', c);
256                               LOG(INFO) << "Killing tag " << tag;
257                               Subprocess::Get().KillExec(tag);
258                             }, fifo_fd, tag));
259 
260   // This test would leak a callback that runs when the child process exits
261   // unless we wait for it to run.
262   brillo::MessageLoopRunUntil(
263       &loop_,
264       TimeDelta::FromSeconds(120),
265       base::Bind([] { return Subprocess::Get().subprocess_records_.empty(); }));
266   EXPECT_TRUE(Subprocess::Get().subprocess_records_.empty());
267   // Check that there isn't anything else to read from the pipe.
268   char c;
269   EXPECT_EQ(0, HANDLE_EINTR(read(fifo_fd, &c, 1)));
270   IGNORE_EINTR(close(fifo_fd));
271 }
272 
273 }  // namespace chromeos_update_engine
274