1 // Copyright 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "sandboxed_api/sandbox2/forkserver.h"
16
17 #include <fcntl.h>
18 #include <sys/socket.h>
19 #include <sys/wait.h>
20 #include <unistd.h>
21
22 #include <string>
23
24 #include "gtest/gtest.h"
25 #include "absl/log/check.h"
26 #include "absl/log/log.h"
27 #include "absl/strings/str_cat.h"
28 #include "sandboxed_api/sandbox2/forkserver.pb.h"
29 #include "sandboxed_api/sandbox2/global_forkclient.h"
30 #include "sandboxed_api/sandbox2/ipc.h"
31 #include "sandboxed_api/testing.h"
32
33 namespace sandbox2 {
34
35 using ::sapi::GetTestSourcePath;
36
37 class IpcPeer {
38 public:
IpcPeer(IPC * ipc)39 explicit IpcPeer(IPC* ipc) : ipc_(ipc) {}
40
SetUpServerSideComms(int fd)41 void SetUpServerSideComms(int fd) { ipc_->SetUpServerSideComms(fd); }
42
43 private:
44 IPC* ipc_;
45 };
46
GetMinimalTestcaseFd()47 int GetMinimalTestcaseFd() {
48 const std::string path = GetTestSourcePath("sandbox2/testcases/minimal");
49 return open(path.c_str(), O_RDONLY);
50 }
51
TestSingleRequest(Mode mode,int exec_fd)52 pid_t TestSingleRequest(Mode mode, int exec_fd) {
53 ForkRequest fork_req;
54 IPC ipc;
55 int sv[2];
56 // Setup IPC
57 PCHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) != -1);
58 IpcPeer{&ipc}.SetUpServerSideComms(sv[1]);
59 // Setup fork_req
60 fork_req.set_mode(mode);
61 fork_req.add_args("/binary");
62 fork_req.add_envs("FOO=1");
63
64 SandboxeeProcess process =
65 GlobalForkClient::SendRequest(fork_req, exec_fd, sv[0]);
66 if (process.main_pid != -1) {
67 VLOG(1) << "TestSingleRequest: Waiting for pid=" << process.main_pid;
68 waitpid(process.main_pid, nullptr, 0);
69 }
70
71 close(sv[0]);
72 return process.main_pid;
73 }
74
TEST(ForkserverTest,SimpleFork)75 TEST(ForkserverTest, SimpleFork) {
76 // Make sure that the regular fork request works.
77 ASSERT_NE(TestSingleRequest(FORKSERVER_FORK, -1), -1);
78 }
79
TEST(ForkserverTest,SimpleForkNoZombie)80 TEST(ForkserverTest, SimpleForkNoZombie) {
81 // Make sure that we don't create zombies.
82 pid_t child = TestSingleRequest(FORKSERVER_FORK, -1);
83 ASSERT_NE(child, -1);
84 std::string proc = absl::StrCat("/proc/", child, "/cmdline");
85
86 // Give the kernel some time to clean up.
87 // Poll every 10ms up to 500 times (5s)
88 bool process_reaped = false;
89 for (int i = 0; i < 500; i++) {
90 if (access(proc.c_str(), F_OK) == -1) {
91 process_reaped = true;
92 break;
93 }
94 usleep(10 * 1000); // 10 ms
95 }
96 EXPECT_TRUE(process_reaped);
97 }
98
TEST(ForkserverTest,ForkExecveWorks)99 TEST(ForkserverTest, ForkExecveWorks) {
100 // Run a test binary through the FORK_EXECVE request.
101 int exec_fd = GetMinimalTestcaseFd();
102 PCHECK(exec_fd != -1) << "Could not open test binary";
103 ASSERT_NE(TestSingleRequest(FORKSERVER_FORK_EXECVE, exec_fd), -1);
104 }
105
TEST(ForkserverTest,ForkExecveSandboxWithoutPolicy)106 TEST(ForkserverTest, ForkExecveSandboxWithoutPolicy) {
107 // Run a test binary through the FORKSERVER_FORK_EXECVE_SANDBOX request.
108 int exec_fd = GetMinimalTestcaseFd();
109 PCHECK(exec_fd != -1) << "Could not open test binary";
110 }
111
112 } // namespace sandbox2
113