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.
9 #include "base/environment.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/posix/eintr_wrapper.h"
13 #include "base/strings/string_number_conversions.h"
15 #include "sandbox/linux/services/init_process_reaper.h"
16 #include "sandbox/linux/suid/common/sandbox.h"
17 #include "sandbox/linux/suid/common/suid_unsafe_environment_variables.h"
18 #include "setuid_sandbox_client.h"
22 // Set an environment variable that reflects the API version we expect from the
23 // setuid sandbox. Old versions of the sandbox will ignore this.
24 void SetSandboxAPIEnvironmentVariable(base::Environment
* env
) {
25 env
->SetVar(sandbox::kSandboxEnvironmentApiRequest
,
26 base::IntToString(sandbox::kSUIDSandboxApiNumber
));
29 // Wrapper around a shared C function.
30 // Returns the "saved" environment variable name corresponding to |envvar|
31 // in a new string or NULL.
32 std::string
* CreateSavedVariableName(const char* env_var
) {
33 char* const saved_env_var
= SandboxSavedEnvironmentVariable(env_var
);
36 std::string
* saved_env_var_copy
= new std::string(saved_env_var
);
37 // SandboxSavedEnvironmentVariable is the C function that we wrap and uses
38 // malloc() to allocate memory.
40 return saved_env_var_copy
;
43 // The ELF loader will clear many environment variables so we save them to
44 // different names here so that the SUID sandbox can resolve them for the
46 void SaveSUIDUnsafeEnvironmentVariables(base::Environment
* env
) {
47 for (unsigned i
= 0; kSUIDUnsafeEnvironmentVariables
[i
]; ++i
) {
48 const char* env_var
= kSUIDUnsafeEnvironmentVariables
[i
];
49 // Get the saved environment variable corresponding to envvar.
50 scoped_ptr
<std::string
> saved_env_var(CreateSavedVariableName(env_var
));
51 if (saved_env_var
== NULL
)
55 if (env
->GetVar(env_var
, &value
))
56 env
->SetVar(saved_env_var
->c_str(), value
);
58 env
->UnSetVar(saved_env_var
->c_str());
62 int GetHelperApi(base::Environment
* env
) {
63 std::string api_string
;
64 int api_number
= 0; // Assume API version 0 if no environment was found.
65 if (env
->GetVar(sandbox::kSandboxEnvironmentApiProvides
, &api_string
) &&
66 !base::StringToInt(api_string
, &api_number
)) {
67 // It's an error if we could not convert the API number.
73 // Convert |var_name| from the environment |env| to an int.
74 // Return -1 if the variable does not exist or the value cannot be converted.
75 int EnvToInt(base::Environment
* env
, const char* var_name
) {
76 std::string var_string
;
78 if (env
->GetVar(var_name
, &var_string
) &&
79 !base::StringToInt(var_string
, &var_value
)) {
85 pid_t
GetHelperPID(base::Environment
* env
) {
86 return EnvToInt(env
, sandbox::kSandboxHelperPidEnvironmentVarName
);
89 // Get the IPC file descriptor used to communicate with the setuid helper.
90 int GetIPCDescriptor(base::Environment
* env
) {
91 return EnvToInt(env
, sandbox::kSandboxDescriptorEnvironmentVarName
);
98 SetuidSandboxClient
* SetuidSandboxClient::Create() {
99 base::Environment
* environment(base::Environment::Create());
100 SetuidSandboxClient
* sandbox_client(new(SetuidSandboxClient
));
103 sandbox_client
->env_
= environment
;
104 return sandbox_client
;
107 SetuidSandboxClient::SetuidSandboxClient()
112 SetuidSandboxClient::~SetuidSandboxClient() {
116 bool SetuidSandboxClient::ChrootMe() {
117 int ipc_fd
= GetIPCDescriptor(env_
);
120 LOG(ERROR
) << "Failed to obtain the sandbox IPC descriptor";
124 if (HANDLE_EINTR(write(ipc_fd
, &kMsgChrootMe
, 1)) != 1) {
125 PLOG(ERROR
) << "Failed to write to chroot pipe";
129 // We need to reap the chroot helper process in any event.
130 pid_t helper_pid
= GetHelperPID(env_
);
131 // If helper_pid is -1 we wait for any child.
132 if (waitpid(helper_pid
, NULL
, 0) < 0) {
133 PLOG(ERROR
) << "Failed to wait for setuid helper to die";
138 if (HANDLE_EINTR(read(ipc_fd
, &reply
, 1)) != 1) {
139 PLOG(ERROR
) << "Failed to read from chroot pipe";
143 if (reply
!= kMsgChrootSuccessful
) {
144 LOG(ERROR
) << "Error code reply from chroot helper";
148 // We now consider ourselves "fully sandboxed" as far as the
149 // setuid sandbox is concerned.
154 bool SetuidSandboxClient::CreateInitProcessReaper(
155 base::Closure
* post_fork_parent_callback
) {
156 return sandbox::CreateInitProcessReaper(post_fork_parent_callback
);
159 bool SetuidSandboxClient::IsSuidSandboxUpToDate() const {
160 return GetHelperApi(env_
) == kSUIDSandboxApiNumber
;
163 bool SetuidSandboxClient::IsSuidSandboxChild() const {
164 return GetIPCDescriptor(env_
) >= 0;
167 bool SetuidSandboxClient::IsInNewPIDNamespace() const {
168 return env_
->HasVar(kSandboxPIDNSEnvironmentVarName
);
171 bool SetuidSandboxClient::IsInNewNETNamespace() const {
172 return env_
->HasVar(kSandboxNETNSEnvironmentVarName
);
175 bool SetuidSandboxClient::IsSandboxed() const {
179 void SetuidSandboxClient::SetupLaunchEnvironment() {
180 SaveSUIDUnsafeEnvironmentVariables(env_
);
181 SetSandboxAPIEnvironmentVariable(env_
);
184 } // namespace sandbox