|
18 | 18 | #include <sys/prctl.h> |
19 | 19 | #include <sys/socket.h> |
20 | 20 | #include <sys/wait.h> |
| 21 | +#include <unistd.h> |
21 | 22 |
|
22 | 23 | #include <cstddef> |
23 | 24 | #include <cstdint> |
|
39 | 40 | #include "sandboxed_api/sandbox2/comms.h" |
40 | 41 | #include "sandboxed_api/testing.h" |
41 | 42 | #include "sandboxed_api/util/fileops.h" |
| 43 | +#include "sandboxed_api/util/raw_logging.h" |
42 | 44 | #include "sandboxed_api/util/thread.h" |
43 | 45 |
|
44 | 46 | namespace sandbox2 { |
@@ -82,19 +84,41 @@ class TestHelper { |
82 | 84 | explicit TestHelper() {} |
83 | 85 |
|
84 | 86 | void StartAsync(int memfd, size_t data_size) { |
85 | | - int pipe_fds[2]; |
86 | | - pipe(pipe_fds); |
| 87 | + int socket_fds[2]; |
| 88 | + CHECK_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, socket_fds), 0); |
| 89 | + |
| 90 | + SAPI_ASSERT_OK_AND_ASSIGN( |
| 91 | + auto buffer_client, |
| 92 | + sandbox2::Buffer::CreateFromFd( |
| 93 | + sapi::file_util::fileops::FDCloser(dup(memfd)), data_size)); |
| 94 | + SAPI_ASSERT_OK_AND_ASSIGN( |
| 95 | + auto transport_client, |
| 96 | + sandbox2::AsynchronousByteTransport::CreateSandboxeeSide( |
| 97 | + std::move(buffer_client))); |
| 98 | + |
| 99 | + std::vector<uint8_t> data_buf(data_size * 4); |
| 100 | + std::vector<uint8_t> data_to_send_buf(data_size * 4); |
| 101 | + std::vector<uint8_t> data_to_recv_buf(data_size * 4); |
| 102 | + std::vector<uint8_t> recv_data_buf(data_size * 4); |
| 103 | + |
| 104 | + sandbox2::Comms comms_child(socket_fds[0], "test_comms_sandboxee"); |
| 105 | + |
87 | 106 | pid_ = fork(); |
88 | 107 | CHECK_NE(pid_, -1); |
89 | 108 | if (pid_ == 0) { |
90 | | - CHECK_EQ(prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0), 0); |
91 | | - close(pipe_fds[1]); |
92 | | - Communicate(pipe_fds[0], memfd, data_size); |
93 | | - close(pipe_fds[0]); |
| 109 | + // At this point, we should avoid any heap allocations to prevent |
| 110 | + // potential deadlocks in TCMalloc. |
| 111 | + SAPI_RAW_CHECK(prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0) == 0, |
| 112 | + "Failed to set PR_SET_PDEATHSIG"); |
| 113 | + close(socket_fds[1]); |
| 114 | + Communicate(&comms_child, transport_client.get(), |
| 115 | + absl::MakeSpan(data_buf), absl::MakeSpan(data_to_send_buf), |
| 116 | + absl::MakeSpan(data_to_recv_buf), |
| 117 | + absl::MakeSpan(recv_data_buf)); |
| 118 | + close(socket_fds[0]); |
94 | 119 | _exit(0); |
95 | 120 | } |
96 | | - close(pipe_fds[0]); |
97 | | - comms_ = std::make_unique<sandbox2::Comms>(pipe_fds[1], "test_comms"); |
| 121 | + comms_ = std::make_unique<sandbox2::Comms>(socket_fds[1], "test_comms"); |
98 | 122 | } |
99 | 123 |
|
100 | 124 | void Stop() { |
@@ -129,39 +153,55 @@ class TestHelper { |
129 | 153 | } |
130 | 154 |
|
131 | 155 | private: |
132 | | - void Communicate(int socket_fd, int memfd_fd, size_t data_size) { |
133 | | - SAPI_ASSERT_OK_AND_ASSIGN( |
134 | | - auto buffer_client, |
135 | | - sandbox2::Buffer::CreateFromFd( |
136 | | - sapi::file_util::fileops::FDCloser(memfd_fd), data_size)); |
137 | | - SAPI_ASSERT_OK_AND_ASSIGN( |
138 | | - auto transport_client, |
139 | | - sandbox2::AsynchronousByteTransport::CreateSandboxeeSide( |
140 | | - std::move(buffer_client))); |
141 | | - sandbox2::Comms comms(socket_fd, "test_comms_sandboxee"); |
| 156 | + void Communicate(sandbox2::Comms* comms, |
| 157 | + sandbox2::AsynchronousByteTransport* transport_client, |
| 158 | + absl::Span<uint8_t> data_buf, |
| 159 | + absl::Span<uint8_t> data_to_send_buf, |
| 160 | + absl::Span<uint8_t> data_to_recv_buf, |
| 161 | + absl::Span<uint8_t> recv_data_buf) { |
| 162 | + // This function should avoid allocations to avoid any potential deadlocks |
| 163 | + // in TCMalloc. This is why we use fixed-size buffers and raw logging. |
142 | 164 | ActionType action_type; |
143 | | - while (comms.RecvInt32(reinterpret_cast<int32_t*>(&action_type))) { |
| 165 | + uint32_t tag; |
| 166 | + size_t len; |
| 167 | + while (comms->RecvInt32(reinterpret_cast<int32_t*>(&action_type))) { |
144 | 168 | if (action_type == ActionType::kSend) { |
145 | | - std::vector<uint8_t> data; |
146 | | - CHECK_EQ(comms.RecvBytes(&data), true); |
147 | | - CHECK_OK(transport_client->Send(data)); |
| 169 | + SAPI_RAW_CHECK( |
| 170 | + comms->RecvTLV(&tag, &len, data_buf.data(), data_buf.size(), |
| 171 | + sandbox2::Comms::kTagBytes), |
| 172 | + "RecvTLV failed"); |
| 173 | + SAPI_RAW_CHECK(transport_client->Send(data_buf.subspan(0, len)).ok(), |
| 174 | + "Send failed"); |
148 | 175 | } else if (action_type == ActionType::kExchange) { |
149 | | - std::vector<uint8_t> data_to_send; |
150 | | - CHECK_EQ(comms.RecvBytes(&data_to_send), true); |
151 | | - std::vector<uint8_t> data_to_recv; |
152 | | - CHECK_EQ(comms.RecvBytes(&data_to_recv), true); |
153 | | - std::vector<uint8_t> recv_data(data_to_recv.size()); |
154 | | - CHECK_OK(transport_client->Exchange( |
155 | | - data_to_send, |
156 | | - absl::Span<uint8_t>(recv_data.data(), recv_data.size()))); |
157 | | - ASSERT_EQ(recv_data, data_to_recv); |
| 176 | + SAPI_RAW_CHECK( |
| 177 | + comms->RecvTLV(&tag, &len, data_to_send_buf.data(), |
| 178 | + data_to_send_buf.size(), sandbox2::Comms::kTagBytes), |
| 179 | + "RecvTLV send_data failed"); |
| 180 | + size_t send_len = len; |
| 181 | + SAPI_RAW_CHECK( |
| 182 | + comms->RecvTLV(&tag, &len, data_to_recv_buf.data(), |
| 183 | + data_to_recv_buf.size(), sandbox2::Comms::kTagBytes), |
| 184 | + "RecvTLV recv_data failed"); |
| 185 | + size_t recv_len = len; |
| 186 | + SAPI_RAW_CHECK(transport_client |
| 187 | + ->Exchange(data_to_send_buf.subspan(0, send_len), |
| 188 | + recv_data_buf.subspan(0, recv_len)) |
| 189 | + .ok(), |
| 190 | + "Exchange failed"); |
| 191 | + SAPI_RAW_CHECK(recv_data_buf.subspan(0, recv_len) == |
| 192 | + data_to_recv_buf.subspan(0, recv_len), |
| 193 | + "Exchange data mismatch"); |
158 | 194 | } else if (action_type == ActionType::kRecv) { |
159 | | - std::vector<uint8_t> data; |
160 | | - CHECK_EQ(comms.RecvBytes(&data), true); |
161 | | - std::vector<uint8_t> data_recv(data.size()); |
162 | | - CHECK_OK(transport_client->Recv( |
163 | | - absl::Span<uint8_t>(data_recv.data(), data_recv.size()))); |
164 | | - CHECK_EQ(data, data_recv); |
| 195 | + SAPI_RAW_CHECK( |
| 196 | + comms->RecvTLV(&tag, &len, data_buf.data(), data_buf.size(), |
| 197 | + sandbox2::Comms::kTagBytes), |
| 198 | + "RecvTLV failed"); |
| 199 | + SAPI_RAW_CHECK( |
| 200 | + transport_client->Recv(recv_data_buf.subspan(0, len)).ok(), |
| 201 | + "Recv failed"); |
| 202 | + SAPI_RAW_CHECK( |
| 203 | + recv_data_buf.subspan(0, len) == data_buf.subspan(0, len), |
| 204 | + "Recv data mismatch"); |
165 | 205 | } else if (action_type == ActionType::kTerminate) { |
166 | 206 | transport_client->Terminate(); |
167 | 207 | } |
|
0 commit comments