5050#include " absl/strings/string_view.h"
5151#include " sandboxed_api/config.h"
5252#include " sandboxed_api/sandbox2/buffer.h"
53- #include " sandboxed_api/sandbox2/client.pb.h"
5453#include " sandboxed_api/sandbox2/comms.h"
5554#include " sandboxed_api/sandbox2/logsink.h"
5655#include " sandboxed_api/sandbox2/network_proxy/client.h"
@@ -190,7 +189,6 @@ std::string Client::GetFdMapEnvVar() const {
190189}
191190
192191void Client::PrepareEnvironment (int * preserved_fd) {
193- ReceiveClientConfig ();
194192 SetUpIPC (preserved_fd);
195193 SetUpCwd ();
196194}
@@ -206,19 +204,41 @@ void Client::SandboxMeHere() {
206204}
207205
208206void Client::SetUpCwd () {
209- // Receive the user-supplied current working directory and change into it.
210- if (client_config_.cwd ().empty ()) {
211- return ;
207+ {
208+ // Get the current working directory to check if we are in a mount
209+ // namespace.
210+ // Note: glibc 2.27 no longer returns a relative path in that case, but
211+ // fails with ENOENT and returns a nullptr instead. The code still
212+ // needs to run on lower version for the time being.
213+ char cwd_buf[PATH_MAX + 1 ] = {0 };
214+ char * cwd = getcwd (cwd_buf, ABSL_ARRAYSIZE (cwd_buf));
215+ SAPI_RAW_PCHECK (cwd != nullptr || errno == ENOENT,
216+ " no current working directory" );
217+
218+ // Outside of the mount namespace, the path is of the form
219+ // '(unreachable)/...'. Only check for the slash, since Linux might make up
220+ // other prefixes in the future.
221+ if (errno == ENOENT || cwd_buf[0 ] != ' /' ) {
222+ SAPI_RAW_VLOG (1 , " chdir into mount namespace, cwd was '%s'" , cwd_buf);
223+ // If we are in a mount namespace but fail to chdir, then it can lead to a
224+ // sandbox escape -- we need to fail with FATAL if the chdir fails.
225+ SAPI_RAW_PCHECK (chdir (" /" ) != -1 , " corrective chdir" );
226+ }
212227 }
213- std::string cwd (client_config_.cwd ());
214- // This chdir can fail without a sandbox escape. It will probably not have
215- // the intended behavior though.
216- if (chdir (cwd.c_str ()) == -1 && SAPI_RAW_VLOG_IS_ON (1 )) {
217- SAPI_RAW_PLOG (
218- INFO,
219- " chdir(%s) failed, falling back to previous cwd or / (with "
220- " namespaces). Use Executor::SetCwd() to set a working directory" ,
221- cwd.c_str ());
228+
229+ // Receive the user-supplied current working directory and change into it.
230+ std::string cwd;
231+ SAPI_RAW_CHECK (comms_->RecvString (&cwd), " receiving working directory" );
232+ if (!cwd.empty ()) {
233+ // On the other hand this chdir can fail without a sandbox escape. It will
234+ // probably not have the intended behavior though.
235+ if (chdir (cwd.c_str ()) == -1 && SAPI_RAW_VLOG_IS_ON (1 )) {
236+ SAPI_RAW_PLOG (
237+ INFO,
238+ " chdir(%s) failed, falling back to previous cwd or / (with "
239+ " namespaces). Use Executor::SetCwd() to set a working directory" ,
240+ cwd.c_str ());
241+ }
222242 }
223243}
224244
@@ -294,12 +314,9 @@ void Client::SetUpIPC(int* preserved_fd) {
294314}
295315
296316void Client::ReceivePolicy () {
297- SAPI_RAW_CHECK (comms_->RecvBytes (&policy_), " receive bytes" );
298- }
299-
300- void Client::ReceiveClientConfig () {
301- SAPI_RAW_CHECK (comms_->RecvProtoBuf (&client_config_),
302- " receive client config" );
317+ std::vector<uint8_t > bytes;
318+ SAPI_RAW_CHECK (comms_->RecvBytes (&bytes), " receive bytes" );
319+ policy_ = std::move (bytes);
303320}
304321
305322void Client::ApplyPolicyAndBecomeTracee () {
@@ -308,13 +325,18 @@ void Client::ApplyPolicyAndBecomeTracee() {
308325 // this function does nothing.
309326 sanitizer::WaitForSanitizer ();
310327
311- pid_t ptracer_tid = client_config_.ptracer_tid ();
312- if (ptracer_tid > 0 ) {
313- SAPI_RAW_CHECK (prctl (PR_SET_DUMPABLE, 1 ) == 0 ,
314- " setting PR_SET_DUMPABLE flag" );
315- if (prctl (PR_SET_PTRACER, ptracer_tid) == -1 ) {
316- SAPI_RAW_VLOG (1 , " No YAMA on this system. Continuing" );
317- }
328+ // Creds can be received w/o synchronization, once the connection is
329+ // established.
330+ pid_t cred_pid;
331+ uid_t cred_uid ABSL_ATTRIBUTE_UNUSED;
332+ gid_t cred_gid ABSL_ATTRIBUTE_UNUSED;
333+ SAPI_RAW_CHECK (comms_->GetPeerCreds (&cred_pid, &cred_uid, &cred_gid),
334+ " receiving credentials" );
335+
336+ SAPI_RAW_CHECK (prctl (PR_SET_DUMPABLE, 1 ) == 0 ,
337+ " setting PR_SET_DUMPABLE flag" );
338+ if (prctl (PR_SET_PTRACER, cred_pid) == -1 ) {
339+ SAPI_RAW_VLOG (1 , " No YAMA on this system. Continuing" );
318340 }
319341
320342 SAPI_RAW_CHECK (prctl (PR_SET_NO_NEW_PRIVS, 1 , 0 , 0 , 0 ) == 0 ,
@@ -342,9 +364,7 @@ void Client::ApplyPolicyAndBecomeTracee() {
342364 uint32_t message; // wait for confirmation
343365 SAPI_RAW_CHECK (comms_->RecvUint32 (&message),
344366 " receving confirmation from executor" );
345- SAPI_RAW_CHECK (message == kSandbox2MonitorReady ,
346- " invalid confirmation from executor" );
347- bool allow_speculation = client_config_.seccomp_allow_speculation ();
367+ bool allow_speculation = message & kAllowSpeculationBit ;
348368 if (!allow_speculation) {
349369 if constexpr (sapi::host_cpu::IsX8664 () || sapi::host_cpu::IsArm64 ()) {
350370 SAPI_RAW_PCHECK (prctl (PR_SET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS,
@@ -361,13 +381,12 @@ void Client::ApplyPolicyAndBecomeTracee() {
361381 }
362382 uint32_t seccomp_extra_flags =
363383 allow_speculation ? SECCOMP_FILTER_FLAG_SPEC_ALLOW : 0 ;
364- if (client_config_.monitor_type () == ClientConfig::CLIENT_MONITOR_UNOTIFY) {
384+ uint32_t monitor_type = message & kMonitorTypeMask ;
385+ if (monitor_type == kSandbox2ClientUnotify ) {
365386 InitSeccompUnotify (prog, comms_, seccomp_extra_flags);
366387 } else {
367- SAPI_RAW_CHECK (
368- client_config_.monitor_type () == ClientConfig::CLIENT_MONITOR_PTRACE,
369- absl::StrCat (" invalid monitor type: " , client_config_.monitor_type ())
370- .c_str ());
388+ SAPI_RAW_CHECK (monitor_type == kSandbox2ClientPtrace ,
389+ " invalid confirmation from executor" );
371390 InitSeccompRegular (prog, seccomp_extra_flags);
372391 }
373392}
0 commit comments