Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <fcntl.h> | 5 #include <fcntl.h> |
| 6 #include <sys/stat.h> | 6 #include <sys/stat.h> |
| 7 #include <sys/types.h> | 7 #include <sys/types.h> |
| 8 | 8 |
| 9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
| 10 #include "base/eintr_wrapper.h" | 10 #include "base/eintr_wrapper.h" |
| 11 #include "base/file_util.h" | |
| 11 #include "base/logging.h" | 12 #include "base/logging.h" |
| 12 #include "base/memory/singleton.h" | 13 #include "base/memory/singleton.h" |
| 14 #include "base/time.h" | |
| 13 #include "content/common/sandbox_linux.h" | 15 #include "content/common/sandbox_linux.h" |
| 14 #include "content/common/seccomp_sandbox.h" | 16 #include "content/common/seccomp_sandbox.h" |
| 17 #include "content/common/sandbox_seccomp_bpf_linux.h" | |
| 15 #include "content/public/common/content_switches.h" | 18 #include "content/public/common/content_switches.h" |
| 16 #include "content/public/common/sandbox_linux.h" | 19 #include "content/public/common/sandbox_linux.h" |
| 17 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" | |
| 18 #include "sandbox/linux/suid/client/setuid_sandbox_client.h" | 20 #include "sandbox/linux/suid/client/setuid_sandbox_client.h" |
| 19 | 21 |
| 20 namespace { | 22 namespace { |
| 21 | 23 |
| 24 void LogSandboxStarted(const std::string& sandbox_name) { | |
| 25 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); | |
| 26 const std::string process_type = | |
| 27 command_line.GetSwitchValueASCII(switches::kProcessType); | |
| 28 const std::string activated_sandbox = | |
| 29 "Activated " + sandbox_name + " sandbox for process type: " + | |
| 30 process_type + "."; | |
| 31 #if defined(OS_CHROMEOS) | |
| 32 LOG(WARNING) << activated_sandbox; | |
| 33 #else | |
| 34 VLOG(1) << activated_sandbox; | |
| 35 #endif | |
| 36 } | |
| 37 | |
| 22 // Implement the command line enabling logic for seccomp-legacy. | 38 // Implement the command line enabling logic for seccomp-legacy. |
| 23 bool IsSeccompLegacyDesired() { | 39 bool IsSeccompLegacyDesired() { |
| 24 #if defined(SECCOMP_SANDBOX) | 40 #if defined(SECCOMP_SANDBOX) |
| 25 #if defined(NDEBUG) | 41 #if defined(NDEBUG) |
| 26 // Off by default; allow turning on with a switch. | 42 // Off by default; allow turning on with a switch. |
| 27 return CommandLine::ForCurrentProcess()->HasSwitch( | 43 return CommandLine::ForCurrentProcess()->HasSwitch( |
| 28 switches::kEnableSeccompSandbox); | 44 switches::kEnableSeccompSandbox); |
| 29 #else | 45 #else |
| 30 // On by default; allow turning off with a switch. | 46 // On by default; allow turning off with a switch. |
| 31 return !CommandLine::ForCurrentProcess()->HasSwitch( | 47 return !CommandLine::ForCurrentProcess()->HasSwitch( |
| 32 switches::kDisableSeccompSandbox); | 48 switches::kDisableSeccompSandbox); |
| 33 #endif // NDEBUG | 49 #endif // NDEBUG |
| 34 #endif // SECCOMP_SANDBOX | 50 #endif // SECCOMP_SANDBOX |
| 35 return false; | 51 return false; |
| 36 } | 52 } |
| 37 | 53 |
| 54 // Our "policy" on whether or not to enable seccomp-legacy. Only renderers are | |
| 55 // supported. | |
| 56 bool ShouldEnableSeccompLegacy(const std::string& process_type) { | |
| 57 if (IsSeccompLegacyDesired() && | |
| 58 process_type == switches::kRendererProcess) { | |
| 59 return true; | |
| 60 } else { | |
| 61 return false; | |
| 62 } | |
| 63 } | |
| 64 | |
| 38 } // namespace | 65 } // namespace |
| 39 | 66 |
| 40 namespace content { | 67 namespace content { |
| 41 | 68 |
| 42 LinuxSandbox::LinuxSandbox() | 69 LinuxSandbox::LinuxSandbox() |
| 43 : proc_fd_(-1), | 70 : proc_fd_(-1), |
| 44 pre_initialized_(false), | 71 pre_initialized_(false), |
| 45 seccomp_legacy_supported_(false), | 72 seccomp_legacy_supported_(false), |
| 73 seccomp_bpf_supported_(false), | |
| 46 setuid_sandbox_client_(sandbox::SetuidSandboxClient::Create()) { | 74 setuid_sandbox_client_(sandbox::SetuidSandboxClient::Create()) { |
| 47 if (setuid_sandbox_client_ == NULL) { | 75 if (setuid_sandbox_client_ == NULL) { |
| 48 LOG(FATAL) << "Failed to instantiate the setuid sandbox client."; | 76 LOG(FATAL) << "Failed to instantiate the setuid sandbox client."; |
| 49 } | 77 } |
| 50 } | 78 } |
| 51 | 79 |
| 52 LinuxSandbox::~LinuxSandbox() { | 80 LinuxSandbox::~LinuxSandbox() { |
| 53 } | 81 } |
| 54 | 82 |
| 55 LinuxSandbox* LinuxSandbox::GetInstance() { | 83 LinuxSandbox* LinuxSandbox::GetInstance() { |
| 56 LinuxSandbox* instance = Singleton<LinuxSandbox>::get(); | 84 LinuxSandbox* instance = Singleton<LinuxSandbox>::get(); |
| 57 CHECK(instance); | 85 CHECK(instance); |
| 58 return instance; | 86 return instance; |
| 59 } | 87 } |
| 60 | 88 |
| 61 void LinuxSandbox::PreinitializeSandboxBegin() { | 89 void LinuxSandbox::PreinitializeSandboxBegin() { |
| 62 CHECK(!pre_initialized_); | 90 CHECK(!pre_initialized_); |
| 63 seccomp_legacy_supported_ = false; | 91 seccomp_legacy_supported_ = false; |
| 92 seccomp_bpf_supported_ = false; | |
| 64 #if defined(SECCOMP_SANDBOX) | 93 #if defined(SECCOMP_SANDBOX) |
| 65 if (IsSeccompLegacyDesired()) { | 94 if (IsSeccompLegacyDesired()) { |
| 66 proc_fd_ = open("/proc", O_DIRECTORY | O_RDONLY); | 95 proc_fd_ = open("/proc", O_DIRECTORY | O_RDONLY); |
| 67 if (proc_fd_ < 0) { | 96 if (proc_fd_ < 0) { |
| 68 LOG(ERROR) << "Cannot access \"/proc\". Disabling seccomp-legacy " | 97 LOG(ERROR) << "Cannot access \"/proc\". Disabling seccomp-legacy " |
| 69 "sandboxing."; | 98 "sandboxing."; |
| 70 // Now is a good time to figure out if we can support seccomp sandboxing | 99 // Now is a good time to figure out if we can support seccomp sandboxing |
| 71 // at all. We will call SupportsSeccompSandbox again later, when actually | 100 // at all. We will call SupportsSeccompSandbox again later, when actually |
| 72 // enabling it, but we allow the implementation to cache some information. | 101 // enabling it, but we allow the implementation to cache some information. |
| 73 // This is the only place where we will log full lack of seccomp-legacy | 102 // This is the only place where we will log full lack of seccomp-legacy |
| 74 // support. | 103 // support. |
| 75 } else if (!SupportsSeccompSandbox(proc_fd_)) { | 104 } else if (!SupportsSeccompSandbox(proc_fd_)) { |
| 76 VLOG(1) << "Lacking support for seccomp-legacy sandbox."; | 105 VLOG(1) << "Lacking support for seccomp-legacy sandbox."; |
| 77 CHECK_EQ(HANDLE_EINTR(close(proc_fd_)), 0); | 106 CHECK_EQ(HANDLE_EINTR(close(proc_fd_)), 0); |
| 78 proc_fd_ = -1; | 107 proc_fd_ = -1; |
| 79 } else { | 108 } else { |
| 80 seccomp_legacy_supported_ = true; | 109 seccomp_legacy_supported_ = true; |
| 81 } | 110 } |
| 82 } | 111 } |
| 83 #endif // SECCOMP_SANDBOX | 112 #endif // SECCOMP_SANDBOX |
| 84 #if defined(SECCOMP_BPF_SANDBOX) | |
| 85 // Similarly, we "pre-warm" the code that detects supports for seccomp BPF. | 113 // Similarly, we "pre-warm" the code that detects supports for seccomp BPF. |
| 86 // TODO(jln): Use proc_fd_ here too once we're comfortable it does not create | 114 // TODO(jln): Use proc_fd_ here too once we're comfortable it does not create |
| 87 // an additional security risk. | 115 // an additional security risk. |
| 88 if (playground2::Sandbox::supportsSeccompSandbox(-1) != | 116 if (SandboxSeccompBpf::IsSeccompBpfDesired()) { |
| 89 playground2::Sandbox::STATUS_AVAILABLE) { | 117 if (!SandboxSeccompBpf::SupportsSandbox()) { |
| 90 VLOG(1) << "Lacking support for seccomp-bpf sandbox."; | 118 VLOG(1) << "Lacking support for seccomp-bpf sandbox."; |
| 119 } else { | |
| 120 seccomp_bpf_supported_ = true; | |
| 121 } | |
| 91 } | 122 } |
| 92 #endif // SECCOMP_BPF_SANDBOX | |
| 93 pre_initialized_ = true; | 123 pre_initialized_ = true; |
| 94 } | 124 } |
| 95 | 125 |
| 96 // Once we finally know our process type, we can cleanup proc_fd_ | 126 // Once we finally know our process type, we can cleanup proc_fd_ |
| 97 // or pass it to seccomp-legacy. | 127 // or pass it to seccomp-legacy. |
| 98 void LinuxSandbox::PreinitializeSandboxFinish( | 128 void LinuxSandbox::PreinitializeSandboxFinish( |
| 99 const std::string& process_type) { | 129 const std::string& process_type) { |
| 100 CHECK(pre_initialized_); | 130 CHECK(pre_initialized_); |
| 101 if (proc_fd_ >= 0) { | 131 if (proc_fd_ >= 0) { |
| 102 if (ShouldEnableSeccompLegacy(process_type)) { | 132 if (ShouldEnableSeccompLegacy(process_type)) { |
| 103 #if defined(SECCOMP_SANDBOX) | 133 #if defined(SECCOMP_SANDBOX) |
| 104 SeccompSandboxSetProcFd(proc_fd_); | 134 SeccompSandboxSetProcFd(proc_fd_); |
| 105 #endif | 135 #endif |
| 106 } else { | 136 } else { |
| 107 DCHECK_GE(proc_fd_, 0); | 137 DCHECK_GE(proc_fd_, 0); |
| 108 CHECK_EQ(HANDLE_EINTR(close(proc_fd_)), 0); | 138 CHECK_EQ(HANDLE_EINTR(close(proc_fd_)), 0); |
| 109 } | 139 } |
| 110 proc_fd_ = -1; | 140 proc_fd_ = -1; |
| 111 } | 141 } |
| 112 } | 142 } |
| 113 | 143 |
| 114 void LinuxSandbox::PreinitializeSandbox(const std::string& process_type) { | 144 void LinuxSandbox::PreinitializeSandbox(const std::string& process_type) { |
| 115 PreinitializeSandboxBegin(); | 145 PreinitializeSandboxBegin(); |
| 116 PreinitializeSandboxFinish(process_type); | 146 PreinitializeSandboxFinish(process_type); |
| 117 } | 147 } |
| 118 | 148 |
| 119 int LinuxSandbox::GetStatus() { | 149 int LinuxSandbox::GetStatus() const { |
| 120 CHECK(pre_initialized_); | 150 CHECK(pre_initialized_); |
| 121 int sandbox_flags = 0; | 151 int sandbox_flags = 0; |
| 122 if (setuid_sandbox_client_->IsSandboxed()) { | 152 if (setuid_sandbox_client_->IsSandboxed()) { |
| 123 sandbox_flags |= kSandboxLinuxSUID; | 153 sandbox_flags |= kSandboxLinuxSUID; |
| 124 if (setuid_sandbox_client_->IsInNewPIDNamespace()) | 154 if (setuid_sandbox_client_->IsInNewPIDNamespace()) |
| 125 sandbox_flags |= kSandboxLinuxPIDNS; | 155 sandbox_flags |= kSandboxLinuxPIDNS; |
| 126 if (setuid_sandbox_client_->IsInNewNETNamespace()) | 156 if (setuid_sandbox_client_->IsInNewNETNamespace()) |
| 127 sandbox_flags |= kSandboxLinuxNetNS; | 157 sandbox_flags |= kSandboxLinuxNetNS; |
| 128 } | 158 } |
| 129 if (seccomp_legacy_supported_) { | 159 if (seccomp_legacy_supported()) { |
| 160 // Note: The current mechanism does not report if the sandbox is activated | |
| 161 // but only if it can be attempted. | |
| 130 sandbox_flags |= kSandboxLinuxSeccomp; | 162 sandbox_flags |= kSandboxLinuxSeccomp; |
| 131 } | 163 } |
| 132 return sandbox_flags; | 164 return sandbox_flags; |
| 133 } | 165 } |
| 134 | 166 |
| 167 bool LinuxSandbox::IsSingleThreaded() const { | |
| 168 // TODO(jln): re-implement this properly and use our proc_fd_ if available. | |
| 169 // Possibly racy, but it's ok because this is more of a debug check to catch | |
| 170 // new threaded situations arising during development. | |
| 171 int num_threads = | |
| 172 file_util::CountFilesCreatedAfter(FilePath("/proc/self/task"), | |
| 173 base::Time::UnixEpoch()); | |
|
Markus (顧孟勤)
2012/08/02 20:39:13
A stat() call makes much more sense than a readdir
jln (very slow on Chromium)
2012/08/02 20:50:40
I'll touch this later and use our proc_fd_. Since
| |
| 174 | |
| 175 // We pass the test if we don't know ( == 0), because the setuid sandbox | |
| 176 // will prevent /proc access in some contexts. | |
| 177 return num_threads == 1 || num_threads == 0; | |
| 178 } | |
| 179 | |
| 135 sandbox::SetuidSandboxClient* | 180 sandbox::SetuidSandboxClient* |
| 136 LinuxSandbox::setuid_sandbox_client() const { | 181 LinuxSandbox::setuid_sandbox_client() const { |
| 137 return setuid_sandbox_client_.get(); | 182 return setuid_sandbox_client_.get(); |
| 138 } | 183 } |
| 139 | 184 |
| 140 // For seccomp-legacy, we implement the policy inline, here. | 185 // For seccomp-legacy, we implement the policy inline, here. |
| 141 bool LinuxSandbox::StartSeccompLegacy(const std::string& process_type) { | 186 bool LinuxSandbox::StartSeccompLegacy(const std::string& process_type) { |
| 142 CHECK(pre_initialized_); | 187 if (!pre_initialized_) |
| 143 if (ShouldEnableSeccompLegacy(process_type)) { | 188 PreinitializeSandbox(process_type); |
| 189 if (seccomp_legacy_supported() && ShouldEnableSeccompLegacy(process_type)) { | |
| 144 // SupportsSeccompSandbox() returns a cached result, as we already | 190 // SupportsSeccompSandbox() returns a cached result, as we already |
| 145 // called it earlier in the PreinitializeSandbox(). Thus, it is OK for us | 191 // called it earlier in the PreinitializeSandbox(). Thus, it is OK for us |
| 146 // to not pass in a file descriptor for "/proc". | 192 // to not pass in a file descriptor for "/proc". |
| 147 #if defined(SECCOMP_SANDBOX) | 193 #if defined(SECCOMP_SANDBOX) |
| 148 if (SupportsSeccompSandbox(-1)) { | 194 if (SupportsSeccompSandbox(-1)) { |
| 149 StartSeccompSandbox(); | 195 StartSeccompSandbox(); |
| 196 LogSandboxStarted("seccomp-legacy"); | |
| 150 return true; | 197 return true; |
| 151 } | 198 } |
| 152 #endif | 199 #endif |
| 153 } | 200 } |
| 154 return false; | 201 return false; |
| 155 } | 202 } |
| 156 | 203 |
| 157 // For seccomp-bpf, we will use the seccomp-bpf policy class. | 204 // For seccomp-bpf, we use the SandboxSeccompBpf class. |
| 158 // TODO(jln): implement this. | |
| 159 bool LinuxSandbox::StartSeccompBpf(const std::string& process_type) { | 205 bool LinuxSandbox::StartSeccompBpf(const std::string& process_type) { |
| 160 CHECK(pre_initialized_); | 206 if (!pre_initialized_) |
| 161 NOTREACHED(); | 207 PreinitializeSandbox(process_type); |
| 162 return false; | 208 bool started_bpf_sandbox = false; |
| 209 if (seccomp_bpf_supported()) { | |
| 210 started_bpf_sandbox = SandboxSeccompBpf::StartSandbox(process_type); | |
| 211 } | |
| 212 | |
| 213 if (started_bpf_sandbox) | |
| 214 LogSandboxStarted("seccomp-bpf"); | |
| 215 | |
| 216 return started_bpf_sandbox; | |
| 163 } | 217 } |
| 164 | 218 |
| 165 // Our "policy" on whether or not to enable seccomp-legacy. Only renderers are | 219 bool LinuxSandbox::seccomp_legacy_supported() const { |
| 166 // supported. | |
| 167 bool LinuxSandbox::ShouldEnableSeccompLegacy( | |
| 168 const std::string& process_type) { | |
| 169 CHECK(pre_initialized_); | 220 CHECK(pre_initialized_); |
| 170 if (IsSeccompLegacyDesired() && | 221 return seccomp_legacy_supported_; |
| 171 seccomp_legacy_supported_ && | 222 } |
| 172 process_type == switches::kRendererProcess) { | 223 |
| 173 return true; | 224 bool LinuxSandbox::seccomp_bpf_supported() const { |
| 174 } else { | 225 CHECK(pre_initialized_); |
| 175 return false; | 226 return seccomp_bpf_supported_; |
| 176 } | |
| 177 } | 227 } |
| 178 | 228 |
| 179 } // namespace content | 229 } // namespace content |
| 180 | 230 |
| OLD | NEW |