Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / sandbox / linux / suid / client / setuid_sandbox_client.cc
blob12ef7f9f40a0b5383d67e030d5d09becda38decf
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"
7 #include <fcntl.h>
8 #include <sys/stat.h>
9 #include <sys/wait.h>
10 #include <unistd.h>
12 #include <string>
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"
21 namespace {
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.
34 api_number = -1;
36 return 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;
43 int var_value = -1;
44 if (env->GetVar(var_name, &var_string) &&
45 !base::StringToInt(var_string, &var_value)) {
46 var_value = -1;
48 return 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);
60 } // namespace
62 namespace sandbox {
64 SetuidSandboxClient* SetuidSandboxClient::Create() {
65 base::Environment* environment(base::Environment::Create());
66 CHECK(environment);
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.
85 struct stat st;
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());
95 if (ipc_fd < 0) {
96 LOG(ERROR) << "Failed to obtain the sandbox IPC descriptor";
97 return false;
100 if (HANDLE_EINTR(write(ipc_fd, &kMsgChrootMe, 1)) != 1) {
101 PLOG(ERROR) << "Failed to write to chroot pipe";
102 return false;
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";
110 return false;
113 char reply;
114 if (HANDLE_EINTR(read(ipc_fd, &reply, 1)) != 1) {
115 PLOG(ERROR) << "Failed to read from chroot pipe";
116 return false;
119 if (reply != kMsgChrootSuccessful) {
120 LOG(ERROR) << "Error code reply from chroot helper";
121 return false;
124 // We now consider ourselves "fully sandboxed" as far as the
125 // setuid sandbox is concerned.
126 CHECK(IsFileSystemAccessDenied());
127 sandboxed_ = true;
128 return true;
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 {
148 return sandboxed_;
151 } // namespace sandbox