Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1427)

Side by Side Diff: sandbox/linux/services/credentials.cc

Issue 2578483002: Namespace sandbox: add check for unprivileged use of CLONE_NEWUSER (Closed)
Patch Set: getuid -> geteuid Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 <limits.h> 8 #include <limits.h>
9 #include <signal.h> 9 #include <signal.h>
10 #include <stddef.h> 10 #include <stddef.h>
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
143 case Credentials::Capability::SYS_CHROOT: 143 case Credentials::Capability::SYS_CHROOT:
144 return CAP_SYS_CHROOT; 144 return CAP_SYS_CHROOT;
145 case Credentials::Capability::SYS_ADMIN: 145 case Credentials::Capability::SYS_ADMIN:
146 return CAP_SYS_ADMIN; 146 return CAP_SYS_ADMIN;
147 } 147 }
148 148
149 LOG(FATAL) << "Invalid Capability: " << static_cast<int>(cap); 149 LOG(FATAL) << "Invalid Capability: " << static_cast<int>(cap);
150 return 0; 150 return 0;
151 } 151 }
152 152
153 void SetGidAndUidMaps(gid_t gid, uid_t uid) {
154 if (NamespaceUtils::KernelSupportsDenySetgroups()) {
155 PCHECK(NamespaceUtils::DenySetgroups());
156 }
157 DCHECK(GetRESIds(NULL, NULL));
158 const char kGidMapFile[] = "/proc/self/gid_map";
159 const char kUidMapFile[] = "/proc/self/uid_map";
160 PCHECK(NamespaceUtils::WriteToIdMapFile(kGidMapFile, gid));
161 PCHECK(NamespaceUtils::WriteToIdMapFile(kUidMapFile, uid));
162 DCHECK(GetRESIds(NULL, NULL));
163 }
164
153 } // namespace. 165 } // namespace.
154 166
155 // static 167 // static
156 bool Credentials::DropAllCapabilities(int proc_fd) { 168 bool Credentials::DropAllCapabilities(int proc_fd) {
157 if (!SetCapabilities(proc_fd, std::vector<Capability>())) { 169 if (!SetCapabilities(proc_fd, std::vector<Capability>())) {
158 return false; 170 return false;
159 } 171 }
160 172
161 CHECK(!HasAnyCapability()); 173 CHECK(!HasAnyCapability());
162 return true; 174 return true;
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
246 if (IsRunningOnValgrind()) { 258 if (IsRunningOnValgrind()) {
247 return false; 259 return false;
248 } 260 }
249 261
250 #if defined(THREAD_SANITIZER) 262 #if defined(THREAD_SANITIZER)
251 // With TSAN, processes will always have threads running and can never 263 // With TSAN, processes will always have threads running and can never
252 // enter a new user namespace with MoveToNewUserNS(). 264 // enter a new user namespace with MoveToNewUserNS().
253 return false; 265 return false;
254 #endif 266 #endif
255 267
256 // This is roughly a fork(). 268 uid_t uid;
257 const pid_t pid = sys_clone(CLONE_NEWUSER | SIGCHLD, 0, 0, 0, 0); 269 gid_t gid;
270 if (!GetRESIds(&uid, &gid)) {
271 return false;
272 }
273
274 const pid_t pid =
275 base::ForkWithFlags(CLONE_NEWUSER | SIGCHLD, nullptr, nullptr);
258 276
259 if (pid == -1) { 277 if (pid == -1) {
260 CheckCloneNewUserErrno(errno); 278 CheckCloneNewUserErrno(errno);
261 return false; 279 return false;
262 } 280 }
263 281
264 // The parent process could have had threads. In the child, these threads 282 // The parent process could have had threads. In the child, these threads
265 // have disappeared. Make sure to not do anything in the child, as this is a 283 // have disappeared.
266 // fragile execution environment.
267 if (pid == 0) { 284 if (pid == 0) {
285 // unshare() requires the effective uid and gid to have a mapping in the
286 // parent namespace.
287 SetGidAndUidMaps(gid, uid);
288
289 // Make sure we drop CAP_SYS_ADMIN.
290 auto proc_fd = sandbox::ProcUtil::OpenProc();
291 CHECK(sandbox::Credentials::DropAllCapabilities(proc_fd.get()));
mdempsky 2017/01/10 22:48:23 nit: You can just use DropAllCapabilities(), which
Tom (Use chromium acct) 2017/01/10 23:32:03 Done.
292
293 // Ensure we have unprivileged use of CLONE_NEWUSER. Debian
294 // Jessie explicitly forbids this case. See:
295 // add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by-default.patch
296 PCHECK(0 == sys_unshare(CLONE_NEWUSER));
268 _exit(kExitSuccess); 297 _exit(kExitSuccess);
269 } 298 }
270 299
271 // Always reap the child. 300 // Always reap the child.
272 int status = -1; 301 int status = -1;
273 PCHECK(HANDLE_EINTR(waitpid(pid, &status, 0)) == pid); 302 PCHECK(HANDLE_EINTR(waitpid(pid, &status, 0)) == pid);
274 CHECK(WIFEXITED(status));
275 CHECK_EQ(kExitSuccess, WEXITSTATUS(status));
276 303
277 // clone(2) succeeded, we can use CLONE_NEWUSER. 304 // clone(2) succeeded. Now return true only if the system grants
278 return true; 305 // unprivileged use of CLONE_NEWUSER as well.
306 return WIFEXITED(status) && WEXITSTATUS(status) == kExitSuccess;
279 } 307 }
280 308
281 bool Credentials::MoveToNewUserNS() { 309 bool Credentials::MoveToNewUserNS() {
282 uid_t uid; 310 uid_t uid;
283 gid_t gid; 311 gid_t gid;
284 if (!GetRESIds(&uid, &gid)) { 312 if (!GetRESIds(&uid, &gid)) {
285 // If all the uids (or gids) are not equal to each other, the security 313 // If all the uids (or gids) are not equal to each other, the security
286 // model will most likely confuse the caller, abort. 314 // model will most likely confuse the caller, abort.
287 DVLOG(1) << "uids or gids differ!"; 315 DVLOG(1) << "uids or gids differ!";
288 return false; 316 return false;
289 } 317 }
290 int ret = sys_unshare(CLONE_NEWUSER); 318 int ret = sys_unshare(CLONE_NEWUSER);
291 if (ret) { 319 if (ret) {
292 const int unshare_errno = errno; 320 const int unshare_errno = errno;
293 VLOG(1) << "Looks like unprivileged CLONE_NEWUSER may not be available " 321 VLOG(1) << "Looks like unprivileged CLONE_NEWUSER may not be available "
294 << "on this kernel."; 322 << "on this kernel.";
295 CheckCloneNewUserErrno(unshare_errno); 323 CheckCloneNewUserErrno(unshare_errno);
296 return false; 324 return false;
297 } 325 }
298 326
299 if (NamespaceUtils::KernelSupportsDenySetgroups()) {
300 PCHECK(NamespaceUtils::DenySetgroups());
301 }
302
303 // The current {r,e,s}{u,g}id is now an overflow id (c.f. 327 // The current {r,e,s}{u,g}id is now an overflow id (c.f.
304 // /proc/sys/kernel/overflowuid). Setup the uid and gid maps. 328 // /proc/sys/kernel/overflowuid). Setup the uid and gid maps.
305 DCHECK(GetRESIds(NULL, NULL)); 329 SetGidAndUidMaps(gid, uid);
306 const char kGidMapFile[] = "/proc/self/gid_map";
307 const char kUidMapFile[] = "/proc/self/uid_map";
308 PCHECK(NamespaceUtils::WriteToIdMapFile(kGidMapFile, gid));
309 PCHECK(NamespaceUtils::WriteToIdMapFile(kUidMapFile, uid));
310 DCHECK(GetRESIds(NULL, NULL));
311 return true; 330 return true;
312 } 331 }
313 332
314 bool Credentials::DropFileSystemAccess(int proc_fd) { 333 bool Credentials::DropFileSystemAccess(int proc_fd) {
315 CHECK_LE(0, proc_fd); 334 CHECK_LE(0, proc_fd);
316 335
317 CHECK(ChrootToSafeEmptyDir()); 336 CHECK(ChrootToSafeEmptyDir());
318 CHECK(!HasFileSystemAccess()); 337 CHECK(!HasFileSystemAccess());
319 CHECK(!ProcUtil::HasOpenDirectory(proc_fd)); 338 CHECK(!ProcUtil::HasOpenDirectory(proc_fd));
320 // We never let this function fail. 339 // We never let this function fail.
321 return true; 340 return true;
322 } 341 }
323 342
324 bool Credentials::HasFileSystemAccess() { 343 bool Credentials::HasFileSystemAccess() {
325 return base::DirectoryExists(base::FilePath("/proc")); 344 return base::DirectoryExists(base::FilePath("/proc"));
326 } 345 }
327 346
328 pid_t Credentials::ForkAndDropCapabilitiesInChild() { 347 pid_t Credentials::ForkAndDropCapabilitiesInChild() {
329 pid_t pid = fork(); 348 pid_t pid = fork();
330 if (pid != 0) { 349 if (pid != 0) {
331 return pid; 350 return pid;
332 } 351 }
333 352
334 // Since we just forked, we are single threaded. 353 // Since we just forked, we are single threaded.
335 PCHECK(DropAllCapabilitiesOnCurrentThread()); 354 PCHECK(DropAllCapabilitiesOnCurrentThread());
336 return 0; 355 return 0;
337 } 356 }
338 357
339 } // namespace sandbox. 358 } // namespace sandbox.
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698