blob: 7a174ef7d7d538b1495f17c9c0772fb15744a674 [file] [log] [blame]
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001// 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.
4
5#include <sys/types.h>
6#include <sys/wait.h>
7#include <unistd.h>
8
Torne (Richard Coles)58218062012-11-14 11:43:16 +00009#include "base/environment.h"
10#include "base/logging.h"
11#include "base/memory/scoped_ptr.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000012#include "base/posix/eintr_wrapper.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000013#include "base/string_number_conversions.h"
14
15#include "sandbox/linux/suid/common/sandbox.h"
16#include "sandbox/linux/suid/common/suid_unsafe_environment_variables.h"
17#include "setuid_sandbox_client.h"
18
19namespace {
20
21// Set an environment variable that reflects the API version we expect from the
22// setuid sandbox. Old versions of the sandbox will ignore this.
23void SetSandboxAPIEnvironmentVariable(base::Environment* env) {
24 env->SetVar(sandbox::kSandboxEnvironmentApiRequest,
25 base::IntToString(sandbox::kSUIDSandboxApiNumber));
26}
27
28// Wrapper around a shared C function.
29// Returns the "saved" environment variable name corresponding to |envvar|
30// in a new string or NULL.
31std::string* CreateSavedVariableName(const char* env_var) {
32 char* const saved_env_var = SandboxSavedEnvironmentVariable(env_var);
33 if (!saved_env_var)
34 return NULL;
35 std::string* saved_env_var_copy = new std::string(saved_env_var);
36 // SandboxSavedEnvironmentVariable is the C function that we wrap and uses
37 // malloc() to allocate memory.
38 free(saved_env_var);
39 return saved_env_var_copy;
40}
41
42// The ELF loader will clear many environment variables so we save them to
43// different names here so that the SUID sandbox can resolve them for the
44// renderer.
45void SaveSUIDUnsafeEnvironmentVariables(base::Environment* env) {
46 for (unsigned i = 0; kSUIDUnsafeEnvironmentVariables[i]; ++i) {
47 const char* env_var = kSUIDUnsafeEnvironmentVariables[i];
48 // Get the saved environment variable corresponding to envvar.
49 scoped_ptr<std::string> saved_env_var(CreateSavedVariableName(env_var));
50 if (saved_env_var == NULL)
51 continue;
52
53 std::string value;
54 if (env->GetVar(env_var, &value))
55 env->SetVar(saved_env_var->c_str(), value);
56 else
57 env->UnSetVar(saved_env_var->c_str());
58 }
59}
60
61int GetHelperApi(base::Environment* env) {
62 std::string api_string;
63 int api_number = 0; // Assume API version 0 if no environment was found.
64 if (env->GetVar(sandbox::kSandboxEnvironmentApiProvides, &api_string) &&
65 !base::StringToInt(api_string, &api_number)) {
66 // It's an error if we could not convert the API number.
67 api_number = -1;
68 }
69 return api_number;
70}
71
72// Convert |var_name| from the environment |env| to an int.
73// Return -1 if the variable does not exist or the value cannot be converted.
74int EnvToInt(base::Environment* env, const char* var_name) {
75 std::string var_string;
76 int var_value = -1;
77 if (env->GetVar(var_name, &var_string) &&
78 !base::StringToInt(var_string, &var_value)) {
79 var_value = -1;
80 }
81 return var_value;
82}
83
84pid_t GetHelperPID(base::Environment* env) {
85 return EnvToInt(env, sandbox::kSandboxHelperPidEnvironmentVarName);
86}
87
88// Get the IPC file descriptor used to communicate with the setuid helper.
89int GetIPCDescriptor(base::Environment* env) {
90 return EnvToInt(env, sandbox::kSandboxDescriptorEnvironmentVarName);
91}
92
93} // namespace
94
95namespace sandbox {
96
97SetuidSandboxClient* SetuidSandboxClient::Create() {
98 base::Environment* environment(base::Environment::Create());
99 SetuidSandboxClient* sandbox_client(new(SetuidSandboxClient));
100
101 CHECK(environment);
102 sandbox_client->env_ = environment;
103 return sandbox_client;
104}
105
106SetuidSandboxClient::SetuidSandboxClient()
107 : env_(NULL),
108 sandboxed_(false) {
109}
110
111SetuidSandboxClient::~SetuidSandboxClient() {
112 delete env_;
113}
114
115bool SetuidSandboxClient::ChrootMe() {
116 int ipc_fd = GetIPCDescriptor(env_);
117
118 if (ipc_fd < 0) {
119 LOG(ERROR) << "Failed to obtain the sandbox IPC descriptor";
120 return false;
121 }
122
123 if (HANDLE_EINTR(write(ipc_fd, &kMsgChrootMe, 1)) != 1) {
124 PLOG(ERROR) << "Failed to write to chroot pipe";
125 return false;
126 }
127
128 // We need to reap the chroot helper process in any event.
129 pid_t helper_pid = GetHelperPID(env_);
130 // If helper_pid is -1 we wait for any child.
131 if (waitpid(helper_pid, NULL, 0) < 0) {
132 PLOG(ERROR) << "Failed to wait for setuid helper to die";
133 return false;
134 }
135
136 char reply;
137 if (HANDLE_EINTR(read(ipc_fd, &reply, 1)) != 1) {
138 PLOG(ERROR) << "Failed to read from chroot pipe";
139 return false;
140 }
141
142 if (reply != kMsgChrootSuccessful) {
143 LOG(ERROR) << "Error code reply from chroot helper";
144 return false;
145 }
146
147 // We now consider ourselves "fully sandboxed" as far as the
148 // setuid sandbox is concerned.
149 sandboxed_ = true;
150 return true;
151}
152
153bool SetuidSandboxClient::IsSuidSandboxUpToDate() const {
154 return GetHelperApi(env_) == kSUIDSandboxApiNumber;
155}
156
157bool SetuidSandboxClient::IsSuidSandboxChild() const {
158 return GetIPCDescriptor(env_) >= 0;
159}
160
161bool SetuidSandboxClient::IsInNewPIDNamespace() const {
162 return env_->HasVar(kSandboxPIDNSEnvironmentVarName);
163}
164
165bool SetuidSandboxClient::IsInNewNETNamespace() const {
166 return env_->HasVar(kSandboxNETNSEnvironmentVarName);
167}
168
169bool SetuidSandboxClient::IsSandboxed() const {
170 return sandboxed_;
171}
172
173void SetuidSandboxClient::SetupLaunchEnvironment() {
174 SaveSUIDUnsafeEnvironmentVariables(env_);
175 SetSandboxAPIEnvironmentVariable(env_);
176}
177
178} // namespace sandbox
179