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()); |
| 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 if (!pre_initialized_) | 187 if (!pre_initialized_) |
143 PreinitializeSandbox(process_type); | 188 PreinitializeSandbox(process_type); |
144 if (ShouldEnableSeccompLegacy(process_type)) { | 189 if (seccomp_legacy_supported() && ShouldEnableSeccompLegacy(process_type)) { |
145 // SupportsSeccompSandbox() returns a cached result, as we already | 190 // SupportsSeccompSandbox() returns a cached result, as we already |
146 // 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 |
147 // to not pass in a file descriptor for "/proc". | 192 // to not pass in a file descriptor for "/proc". |
148 #if defined(SECCOMP_SANDBOX) | 193 #if defined(SECCOMP_SANDBOX) |
149 if (SupportsSeccompSandbox(-1)) { | 194 if (SupportsSeccompSandbox(-1)) { |
150 StartSeccompSandbox(); | 195 StartSeccompSandbox(); |
| 196 LogSandboxStarted("seccomp-legacy"); |
151 return true; | 197 return true; |
152 } | 198 } |
153 #endif | 199 #endif |
154 } | 200 } |
155 return false; | 201 return false; |
156 } | 202 } |
157 | 203 |
158 // For seccomp-bpf, we will use the seccomp-bpf policy class. | 204 // For seccomp-bpf, we use the SandboxSeccompBpf class. |
159 // TODO(jln): implement this. | |
160 bool LinuxSandbox::StartSeccompBpf(const std::string& process_type) { | 205 bool LinuxSandbox::StartSeccompBpf(const std::string& process_type) { |
161 CHECK(pre_initialized_); | 206 if (!pre_initialized_) |
162 NOTREACHED(); | 207 PreinitializeSandbox(process_type); |
163 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; |
164 } | 217 } |
165 | 218 |
166 // Our "policy" on whether or not to enable seccomp-legacy. Only renderers are | 219 bool LinuxSandbox::seccomp_legacy_supported() const { |
167 // supported. | |
168 bool LinuxSandbox::ShouldEnableSeccompLegacy( | |
169 const std::string& process_type) { | |
170 CHECK(pre_initialized_); | 220 CHECK(pre_initialized_); |
171 if (IsSeccompLegacyDesired() && | 221 return seccomp_legacy_supported_; |
172 seccomp_legacy_supported_ && | 222 } |
173 process_type == switches::kRendererProcess) { | 223 |
174 return true; | 224 bool LinuxSandbox::seccomp_bpf_supported() const { |
175 } else { | 225 CHECK(pre_initialized_); |
176 return false; | 226 return seccomp_bpf_supported_; |
177 } | |
178 } | 227 } |
179 | 228 |
180 } // namespace content | 229 } // namespace content |
181 | 230 |
OLD | NEW |