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