1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "sandbox/linux/suid/client/setuid_sandbox_client.h"
14 #include "base/environment.h"
15 #include "base/files/scoped_file.h"
16 #include "base/logging.h"
17 #include "base/posix/eintr_wrapper.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "sandbox/linux/suid/common/sandbox.h"
23 bool IsFileSystemAccessDenied() {
24 base::ScopedFD
root_dir(HANDLE_EINTR(open("/", O_RDONLY
)));
25 return !root_dir
.is_valid();
28 int GetHelperApi(base::Environment
* env
) {
29 std::string api_string
;
30 int api_number
= 0; // Assume API version 0 if no environment was found.
31 if (env
->GetVar(sandbox::kSandboxEnvironmentApiProvides
, &api_string
) &&
32 !base::StringToInt(api_string
, &api_number
)) {
33 // It's an error if we could not convert the API number.
39 // Convert |var_name| from the environment |env| to an int.
40 // Return -1 if the variable does not exist or the value cannot be converted.
41 int EnvToInt(base::Environment
* env
, const char* var_name
) {
42 std::string var_string
;
44 if (env
->GetVar(var_name
, &var_string
) &&
45 !base::StringToInt(var_string
, &var_value
)) {
51 pid_t
GetHelperPID(base::Environment
* env
) {
52 return EnvToInt(env
, sandbox::kSandboxHelperPidEnvironmentVarName
);
55 // Get the IPC file descriptor used to communicate with the setuid helper.
56 int GetIPCDescriptor(base::Environment
* env
) {
57 return EnvToInt(env
, sandbox::kSandboxDescriptorEnvironmentVarName
);
64 SetuidSandboxClient
* SetuidSandboxClient::Create() {
65 base::Environment
* environment(base::Environment::Create());
67 return new SetuidSandboxClient(environment
);
70 SetuidSandboxClient::SetuidSandboxClient(base::Environment
* env
)
71 : env_(env
), sandboxed_(false) {
74 SetuidSandboxClient::~SetuidSandboxClient() {
77 void SetuidSandboxClient::CloseDummyFile() {
78 // When we're launched through the setuid sandbox, SetupLaunchOptions
79 // arranges for kZygoteIdFd to be a dummy file descriptor to satisfy an
80 // ancient setuid sandbox ABI requirement. However, the descriptor is no
81 // longer needed, so we can simply close it right away now.
82 CHECK(IsSuidSandboxChild());
84 // Sanity check that kZygoteIdFd refers to a pipe.
86 PCHECK(0 == fstat(kZygoteIdFd
, &st
));
87 CHECK(S_ISFIFO(st
.st_mode
));
89 PCHECK(0 == IGNORE_EINTR(close(kZygoteIdFd
)));
92 bool SetuidSandboxClient::ChrootMe() {
93 int ipc_fd
= GetIPCDescriptor(env_
.get());
96 LOG(ERROR
) << "Failed to obtain the sandbox IPC descriptor";
100 if (HANDLE_EINTR(write(ipc_fd
, &kMsgChrootMe
, 1)) != 1) {
101 PLOG(ERROR
) << "Failed to write to chroot pipe";
105 // We need to reap the chroot helper process in any event.
106 pid_t helper_pid
= GetHelperPID(env_
.get());
107 // If helper_pid is -1 we wait for any child.
108 if (HANDLE_EINTR(waitpid(helper_pid
, NULL
, 0)) < 0) {
109 PLOG(ERROR
) << "Failed to wait for setuid helper to die";
114 if (HANDLE_EINTR(read(ipc_fd
, &reply
, 1)) != 1) {
115 PLOG(ERROR
) << "Failed to read from chroot pipe";
119 if (reply
!= kMsgChrootSuccessful
) {
120 LOG(ERROR
) << "Error code reply from chroot helper";
124 // We now consider ourselves "fully sandboxed" as far as the
125 // setuid sandbox is concerned.
126 CHECK(IsFileSystemAccessDenied());
131 bool SetuidSandboxClient::IsSuidSandboxUpToDate() const {
132 return GetHelperApi(env_
.get()) == kSUIDSandboxApiNumber
;
135 bool SetuidSandboxClient::IsSuidSandboxChild() const {
136 return GetIPCDescriptor(env_
.get()) >= 0;
139 bool SetuidSandboxClient::IsInNewPIDNamespace() const {
140 return env_
->HasVar(kSandboxPIDNSEnvironmentVarName
);
143 bool SetuidSandboxClient::IsInNewNETNamespace() const {
144 return env_
->HasVar(kSandboxNETNSEnvironmentVarName
);
147 bool SetuidSandboxClient::IsSandboxed() const {
151 } // namespace sandbox