diff options
author | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-17 21:36:28 +0000 |
---|---|---|
committer | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-17 21:36:28 +0000 |
commit | 6322c471382ebb52b1fa47ad83ff629bff9d4672 (patch) | |
tree | 7e77aaa05c6ef360baafc2a73eb0e5d18eb39814 | |
parent | ca97a26cb1e8997126a7c94422725fc3507015fd (diff) | |
download | chromium_src-6322c471382ebb52b1fa47ad83ff629bff9d4672.zip chromium_src-6322c471382ebb52b1fa47ad83ff629bff9d4672.tar.gz chromium_src-6322c471382ebb52b1fa47ad83ff629bff9d4672.tar.bz2 |
Linux sandbox: save full list of SUID unsafe environment variables.
r20733 added code to save LD_LIBRARY_PATH when using the SUID sandbox.
That fixed a P0, show-stopper bug, however, LD_LIBRARY_PATH isn't the
only variable which is stomped when using SUID binaries. This patch
extends support to all variables that we so affected.
BUG=16815
http://codereview.chromium.org/159025
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@21009 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/zygote_host_linux.cc | 30 | ||||
-rw-r--r-- | sandbox/linux/suid/sandbox.cc | 26 | ||||
-rw-r--r-- | sandbox/linux/suid/suid_unsafe_environment_variables.h | 59 | ||||
-rw-r--r-- | sandbox/sandbox.gyp | 3 |
4 files changed, 105 insertions, 13 deletions
diff --git a/chrome/browser/zygote_host_linux.cc b/chrome/browser/zygote_host_linux.cc index dad473b..b055834 100644 --- a/chrome/browser/zygote_host_linux.cc +++ b/chrome/browser/zygote_host_linux.cc @@ -22,6 +22,29 @@ #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_switches.h" +#include "sandbox/linux/suid/suid_unsafe_environment_variables.h" + +static void SaveSUIDUnsafeEnvironmentVariables() { + // The ELF loader will clear many environment variables so we save them to + // different names here so that the SUID sandbox can resolve them for the + // renderer. + + for (unsigned i = 0; kSUIDUnsafeEnvironmentVariables[i]; ++i) { + const char* const envvar = kSUIDUnsafeEnvironmentVariables[i]; + char* const saved_envvar = SandboxSavedEnvironmentVariable(envvar); + if (!saved_envvar) + continue; + + const char* const value = getenv(envvar); + if (value) + setenv(saved_envvar, value, 1 /* overwrite */); + else + unsetenv(saved_envvar); + + free(saved_envvar); + } +} + ZygoteHost::ZygoteHost() { std::wstring chrome_path; CHECK(PathService::Get(base::FILE_EXE, &chrome_path)); @@ -64,12 +87,7 @@ ZygoteHost::ZygoteHost() { (st.st_mode & S_IXOTH)) { cmd_line.PrependWrapper(ASCIIToWide(sandbox_binary)); - // SUID binaries clear LD_LIBRARY_PATH. However, the sandbox binary needs - // to run its child processes with the correct LD_LIBRARY_PATH so we save - // a copy here: - const char* ld_library_path = getenv("LD_LIBRARY_PATH"); - if (ld_library_path) - setenv("SANDBOX_LD_LIBRARY_PATH", ld_library_path, 1 /* overwrite */); + SaveSUIDUnsafeEnvironmentVariables(); } else { LOG(FATAL) << "The SUID sandbox helper binary was found, but is not " "configured correctly. Rather than run without sandboxing " diff --git a/sandbox/linux/suid/sandbox.cc b/sandbox/linux/suid/sandbox.cc index a81ba1a..26aee65 100644 --- a/sandbox/linux/suid/sandbox.cc +++ b/sandbox/linux/suid/sandbox.cc @@ -21,6 +21,8 @@ #include <sys/types.h> #include <unistd.h> +#include "sandbox/linux/suid/suid_unsafe_environment_variables.h" + #if !defined(CLONE_NEWPID) #define CLONE_NEWPID 0x20000000 #endif @@ -228,15 +230,25 @@ static bool DropRoot() { } static bool SetupChildEnvironment() { - // ld.so will have cleared LD_LIBRARY_PATH because we are SUID. However, the - // child process might need this so zygote_host_linux.cc saved a copy in - // SANDBOX_LD_LIBRARY_PATH. This is safe because we have dropped root by this + // ld.so may have cleared several environment variables because we are SUID. + // However, the child process might need them so zygote_host_linux.cc saves a + // copy in SANDBOX_$x. This is safe because we have dropped root by this // point, so we can only exec a binary with the permissions of the user who // ran us in the first place. - const char* sandbox_ld_library_path = getenv("SANDBOX_LD_LIBRARY_PATH"); - if (sandbox_ld_library_path) { - setenv("LD_LIBRARY_PATH", sandbox_ld_library_path, 1 /* overwrite */); - unsetenv("SANDBOX_LD_LIBRARY_PATH"); + + for (unsigned i = 0; kSUIDUnsafeEnvironmentVariables[i]; ++i) { + const char* const envvar = kSUIDUnsafeEnvironmentVariables[i]; + char* const saved_envvar = SandboxSavedEnvironmentVariable(envvar); + if (!saved_envvar) + return false; + + const char* const value = getenv(saved_envvar); + if (value) { + setenv(envvar, value, 1 /* overwrite */); + unsetenv(saved_envvar); + } + + free(saved_envvar); } return true; diff --git a/sandbox/linux/suid/suid_unsafe_environment_variables.h b/sandbox/linux/suid/suid_unsafe_environment_variables.h new file mode 100644 index 0000000..5862010 --- /dev/null +++ b/sandbox/linux/suid/suid_unsafe_environment_variables.h @@ -0,0 +1,59 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This is a list of environment variables which the ELF loader unsets when +// loading a SUID binary. Because they are unset rather than just ignored, they +// aren't passed to child processes of SUID processes either. +// +// We need to save these environment variables before running a SUID sandbox +// and restore them before running child processes (but after dropping root). +// +// List gathered from glibc sources (00ebd7ed58df389a78e41dece058048725cb585e): +// sysdeps/unix/sysv/linux/i386/dl-librecon.h +// sysdeps/generic/unsecvars.h + +static const char* kSUIDUnsafeEnvironmentVariables[] = { + "LD_AOUT_LIBRARY_PATH", + "LD_AOUT_PRELOAD", + "GCONV_PATH", + "GETCONF_DIR", + "HOSTALIASES", + "LD_AUDIT", + "LD_DEBUG", + "LD_DEBUG_OUTPUT", + "LD_DYNAMIC_WEAK", + "LD_LIBRARY_PATH", + "LD_ORIGIN_PATH", + "LD_PRELOAD", + "LD_PROFILE", + "LD_SHOW_AUXV", + "LD_USE_LOAD_BIAS", + "LOCALDOMAIN", + "LOCPATH", + "MALLOC_TRACE", + "NIS_PATH", + "NLSPATH", + "RESOLV_HOST_CONF", + "RES_OPTIONS", + "TMPDIR", + "TZDIR", + NULL, +}; + +// Return a malloc allocated string containing the 'saved' environment variable +// name for a given environment variable. +static inline char* SandboxSavedEnvironmentVariable(const char* envvar) { + const size_t envvar_len = strlen(envvar); + const size_t saved_envvarlen = envvar_len + 1 /* NUL terminator */ + + 8 /* strlen("SANDBOX_") */; + char* const saved_envvar = (char*) malloc(saved_envvarlen); + if (!saved_envvar) + return NULL; + + memcpy(saved_envvar, "SANDBOX_", 8); + memcpy(saved_envvar + 8, envvar, envvar_len); + saved_envvar[8 + envvar_len] = 0; + + return saved_envvar; +} diff --git a/sandbox/sandbox.gyp b/sandbox/sandbox.gyp index 6ca2cef..d711f83 100644 --- a/sandbox/sandbox.gyp +++ b/sandbox/sandbox.gyp @@ -25,6 +25,9 @@ 'sources': [ 'linux/suid/sandbox.cc', ], + 'include_dirs': [ + '..', + ], } ], }], |