OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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 "sandbox/linux/services/credentials.h" | 5 #include "sandbox/linux/services/credentials.h" |
6 | 6 |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <signal.h> | 8 #include <signal.h> |
9 #include <stdio.h> | 9 #include <stdio.h> |
10 #include <sys/capability.h> | 10 #include <sys/capability.h> |
11 #include <sys/syscall.h> | 11 #include <sys/syscall.h> |
12 #include <sys/types.h> | 12 #include <sys/types.h> |
13 #include <sys/wait.h> | 13 #include <sys/wait.h> |
14 #include <unistd.h> | 14 #include <unistd.h> |
15 | 15 |
16 #include "base/basictypes.h" | 16 #include "base/basictypes.h" |
17 #include "base/bind.h" | 17 #include "base/bind.h" |
18 #include "base/files/file_path.h" | 18 #include "base/files/file_path.h" |
19 #include "base/files/file_util.h" | 19 #include "base/files/file_util.h" |
20 #include "base/logging.h" | 20 #include "base/logging.h" |
21 #include "base/posix/eintr_wrapper.h" | 21 #include "base/posix/eintr_wrapper.h" |
22 #include "base/process/launch.h" | 22 #include "base/process/launch.h" |
23 #include "base/template_util.h" | 23 #include "base/template_util.h" |
24 #include "base/third_party/valgrind/valgrind.h" | 24 #include "base/third_party/valgrind/valgrind.h" |
| 25 #include "build/build_config.h" |
25 #include "sandbox/linux/services/namespace_utils.h" | 26 #include "sandbox/linux/services/namespace_utils.h" |
| 27 #include "sandbox/linux/services/proc_util.h" |
26 #include "sandbox/linux/services/syscall_wrappers.h" | 28 #include "sandbox/linux/services/syscall_wrappers.h" |
| 29 #include "sandbox/linux/services/thread_helpers.h" |
27 | 30 |
28 namespace sandbox { | 31 namespace sandbox { |
29 | 32 |
30 namespace { | 33 namespace { |
31 | 34 |
32 bool IsRunningOnValgrind() { return RUNNING_ON_VALGRIND; } | 35 bool IsRunningOnValgrind() { return RUNNING_ON_VALGRIND; } |
33 | 36 |
34 struct CapFreeDeleter { | 37 struct CapFreeDeleter { |
35 inline void operator()(cap_t cap) const { | 38 inline void operator()(cap_t cap) const { |
36 int ret = cap_free(cap); | 39 int ret = cap_free(cap); |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
122 void CheckCloneNewUserErrno(int error) { | 125 void CheckCloneNewUserErrno(int error) { |
123 // EPERM can happen if already in a chroot. EUSERS if too many nested | 126 // EPERM can happen if already in a chroot. EUSERS if too many nested |
124 // namespaces are used. EINVAL for kernels that don't support the feature. | 127 // namespaces are used. EINVAL for kernels that don't support the feature. |
125 // Valgrind will ENOSYS unshare(). | 128 // Valgrind will ENOSYS unshare(). |
126 PCHECK(error == EPERM || error == EUSERS || error == EINVAL || | 129 PCHECK(error == EPERM || error == EUSERS || error == EINVAL || |
127 error == ENOSYS); | 130 error == ENOSYS); |
128 } | 131 } |
129 | 132 |
130 } // namespace. | 133 } // namespace. |
131 | 134 |
132 bool Credentials::DropAllCapabilities() { | 135 bool Credentials::DropAllCapabilities(int proc_fd) { |
| 136 DCHECK_LE(0, proc_fd); |
| 137 #if !defined(THREAD_SANITIZER) |
| 138 // With TSAN, accept to break the security model as it is a testing |
| 139 // configuration. |
| 140 CHECK(ThreadHelpers::IsSingleThreaded(proc_fd)); |
| 141 #endif |
| 142 |
133 ScopedCap cap(cap_init()); | 143 ScopedCap cap(cap_init()); |
134 CHECK(cap); | 144 CHECK(cap); |
135 PCHECK(0 == cap_set_proc(cap.get())); | 145 PCHECK(0 == cap_set_proc(cap.get())); |
136 CHECK(!HasAnyCapability()); | 146 CHECK(!HasAnyCapability()); |
137 // We never let this function fail. | 147 // We never let this function fail. |
138 return true; | 148 return true; |
139 } | 149 } |
140 | 150 |
| 151 bool Credentials::DropAllCapabilities() { |
| 152 base::ScopedFD proc_fd(ProcUtil::OpenProc()); |
| 153 return Credentials::DropAllCapabilities(proc_fd.get()); |
| 154 } |
| 155 |
141 bool Credentials::HasAnyCapability() { | 156 bool Credentials::HasAnyCapability() { |
142 ScopedCap current_cap(cap_get_proc()); | 157 ScopedCap current_cap(cap_get_proc()); |
143 CHECK(current_cap); | 158 CHECK(current_cap); |
144 ScopedCap empty_cap(cap_init()); | 159 ScopedCap empty_cap(cap_init()); |
145 CHECK(empty_cap); | 160 CHECK(empty_cap); |
146 return cap_compare(current_cap.get(), empty_cap.get()) != 0; | 161 return cap_compare(current_cap.get(), empty_cap.get()) != 0; |
147 } | 162 } |
148 | 163 |
149 scoped_ptr<std::string> Credentials::GetCurrentCapString() { | 164 scoped_ptr<std::string> Credentials::GetCurrentCapString() { |
150 ScopedCap current_cap(cap_get_proc()); | 165 ScopedCap current_cap(cap_get_proc()); |
151 CHECK(current_cap); | 166 CHECK(current_cap); |
152 ScopedCapText cap_text(cap_to_text(current_cap.get(), NULL)); | 167 ScopedCapText cap_text(cap_to_text(current_cap.get(), NULL)); |
153 CHECK(cap_text); | 168 CHECK(cap_text); |
154 return scoped_ptr<std::string> (new std::string(cap_text.get())); | 169 return scoped_ptr<std::string> (new std::string(cap_text.get())); |
155 } | 170 } |
156 | 171 |
157 // static | 172 // static |
158 bool Credentials::CanCreateProcessInNewUserNS() { | 173 bool Credentials::CanCreateProcessInNewUserNS() { |
159 // Valgrind will let clone(2) pass-through, but doesn't support unshare(), | 174 // Valgrind will let clone(2) pass-through, but doesn't support unshare(), |
160 // so always consider UserNS unsupported there. | 175 // so always consider UserNS unsupported there. |
161 if (IsRunningOnValgrind()) { | 176 if (IsRunningOnValgrind()) { |
162 return false; | 177 return false; |
163 } | 178 } |
164 | 179 |
| 180 #if defined(THREAD_SANITIZER) |
| 181 // With TSAN, processes will always have threads running and can never |
| 182 // enter a new user namespace with MoveToNewUserNS(). |
| 183 return false; |
| 184 #endif |
| 185 |
165 // This is roughly a fork(). | 186 // This is roughly a fork(). |
166 const pid_t pid = sys_clone(CLONE_NEWUSER | SIGCHLD, 0, 0, 0, 0); | 187 const pid_t pid = sys_clone(CLONE_NEWUSER | SIGCHLD, 0, 0, 0, 0); |
167 | 188 |
168 if (pid == -1) { | 189 if (pid == -1) { |
169 CheckCloneNewUserErrno(errno); | 190 CheckCloneNewUserErrno(errno); |
170 return false; | 191 return false; |
171 } | 192 } |
172 | 193 |
173 // The parent process could have had threads. In the child, these threads | 194 // The parent process could have had threads. In the child, these threads |
174 // have disappeared. Make sure to not do anything in the child, as this is a | 195 // have disappeared. Make sure to not do anything in the child, as this is a |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
213 // /proc/sys/kernel/overflowuid). Setup the uid and gid maps. | 234 // /proc/sys/kernel/overflowuid). Setup the uid and gid maps. |
214 DCHECK(GetRESIds(NULL, NULL)); | 235 DCHECK(GetRESIds(NULL, NULL)); |
215 const char kGidMapFile[] = "/proc/self/gid_map"; | 236 const char kGidMapFile[] = "/proc/self/gid_map"; |
216 const char kUidMapFile[] = "/proc/self/uid_map"; | 237 const char kUidMapFile[] = "/proc/self/uid_map"; |
217 PCHECK(NamespaceUtils::WriteToIdMapFile(kGidMapFile, gid)); | 238 PCHECK(NamespaceUtils::WriteToIdMapFile(kGidMapFile, gid)); |
218 PCHECK(NamespaceUtils::WriteToIdMapFile(kUidMapFile, uid)); | 239 PCHECK(NamespaceUtils::WriteToIdMapFile(kUidMapFile, uid)); |
219 DCHECK(GetRESIds(NULL, NULL)); | 240 DCHECK(GetRESIds(NULL, NULL)); |
220 return true; | 241 return true; |
221 } | 242 } |
222 | 243 |
223 bool Credentials::DropFileSystemAccess() { | 244 bool Credentials::DropFileSystemAccess(int proc_fd) { |
| 245 CHECK_LE(0, proc_fd); |
| 246 |
224 CHECK(ChrootToSafeEmptyDir()); | 247 CHECK(ChrootToSafeEmptyDir()); |
225 CHECK(!base::DirectoryExists(base::FilePath("/proc"))); | 248 CHECK(!base::DirectoryExists(base::FilePath("/proc"))); |
| 249 CHECK(!ProcUtil::HasOpenDirectory(proc_fd)); |
226 // We never let this function fail. | 250 // We never let this function fail. |
227 return true; | 251 return true; |
228 } | 252 } |
229 | 253 |
230 } // namespace sandbox. | 254 } // namespace sandbox. |
OLD | NEW |