Home | History | Annotate | Download | only in client
      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.
      4 
      5 #include <sys/types.h>
      6 #include <sys/wait.h>
      7 #include <unistd.h>
      8 
      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"
     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 
     19 namespace {
     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.
     23 void 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.
     31 std::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.
     45 void 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 
     61 int 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.
     74 int 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 
     84 pid_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.
     89 int GetIPCDescriptor(base::Environment* env) {
     90   return EnvToInt(env, sandbox::kSandboxDescriptorEnvironmentVarName);
     91 }
     92 
     93 }  // namespace
     94 
     95 namespace sandbox {
     96 
     97 SetuidSandboxClient* 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 
    106 SetuidSandboxClient::SetuidSandboxClient()
    107     : env_(NULL),
    108       sandboxed_(false) {
    109 }
    110 
    111 SetuidSandboxClient::~SetuidSandboxClient() {
    112   delete env_;
    113 }
    114 
    115 bool 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 
    153 bool SetuidSandboxClient::IsSuidSandboxUpToDate() const {
    154   return GetHelperApi(env_) == kSUIDSandboxApiNumber;
    155 }
    156 
    157 bool SetuidSandboxClient::IsSuidSandboxChild() const {
    158   return GetIPCDescriptor(env_) >= 0;
    159 }
    160 
    161 bool SetuidSandboxClient::IsInNewPIDNamespace() const {
    162   return env_->HasVar(kSandboxPIDNSEnvironmentVarName);
    163 }
    164 
    165 bool SetuidSandboxClient::IsInNewNETNamespace() const {
    166   return env_->HasVar(kSandboxNETNSEnvironmentVarName);
    167 }
    168 
    169 bool SetuidSandboxClient::IsSandboxed() const {
    170   return sandboxed_;
    171 }
    172 
    173 void SetuidSandboxClient::SetupLaunchEnvironment() {
    174   SaveSUIDUnsafeEnvironmentVariables(env_);
    175   SetSandboxAPIEnvironmentVariable(env_);
    176 }
    177 
    178 }  // namespace sandbox
    179 
    180