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

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

Issue 2578483002: Namespace sandbox: add check for unprivileged use of CLONE_NEWUSER (Closed)
Patch Set: Created 4 years 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
268 uid_t uid;
269 gid_t gid;
270 if (!GetRESIds(&uid, &gid)) {
271 return false;
272 }
273
256 // This is roughly a fork(). 274 // This is roughly a fork().
257 const pid_t pid = sys_clone(CLONE_NEWUSER | SIGCHLD, 0, 0, 0, 0); 275 const pid_t pid = sys_clone(CLONE_NEWUSER | SIGCHLD, 0, 0, 0, 0);
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. Make sure to not do anything in the child, as this is a
266 // fragile execution environment. 284 // fragile execution environment.
267 if (pid == 0) { 285 if (pid == 0) {
268 _exit(kExitSuccess); 286 // unshare() requires the effective uid and gid to have a mapping in the
287 // parent namespace.
288 SetGidAndUidMaps(gid, uid);
289
290 // Make sure we drop CAP_SYS_ADMIN.
291 auto proc_fd = sandbox::ProcUtil::OpenProc();
292 CHECK(sandbox::Credentials::DropAllCapabilities(proc_fd.get()));
293
294 // Ensure we have unprivileged use of CLONE_NEWUSER. Debian
295 // Jessie explicitly forbids this case. See:
296 // add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by-default.patch
297 int ret = sys_unshare(CLONE_NEWUSER);
mdempsky 2016/12/14 05:11:11 I would probably do: PCHECK(sys_unshare(CLONE
Tom (Use chromium acct) 2016/12/14 21:10:26 Done. But when I run this as root on Debian, I ge
298 _exit(!!ret);
269 } 299 }
270 300
271 // Always reap the child. 301 // Always reap the child.
272 int status = -1; 302 int status = -1;
273 PCHECK(HANDLE_EINTR(waitpid(pid, &status, 0)) == pid); 303 PCHECK(HANDLE_EINTR(waitpid(pid, &status, 0)) == pid);
274 CHECK(WIFEXITED(status)); 304 CHECK(WIFEXITED(status));
275 CHECK_EQ(kExitSuccess, WEXITSTATUS(status));
276 305
277 // clone(2) succeeded, we can use CLONE_NEWUSER. 306 // clone(2) succeeded. Now return true only if the system grants
278 return true; 307 // unprivileged use of CLONE_NEWUSER as well.
308 return !status;
279 } 309 }
280 310
281 bool Credentials::MoveToNewUserNS() { 311 bool Credentials::MoveToNewUserNS() {
282 uid_t uid; 312 uid_t uid;
283 gid_t gid; 313 gid_t gid;
284 if (!GetRESIds(&uid, &gid)) { 314 if (!GetRESIds(&uid, &gid)) {
285 // If all the uids (or gids) are not equal to each other, the security 315 // If all the uids (or gids) are not equal to each other, the security
286 // model will most likely confuse the caller, abort. 316 // model will most likely confuse the caller, abort.
287 DVLOG(1) << "uids or gids differ!"; 317 DVLOG(1) << "uids or gids differ!";
288 return false; 318 return false;
289 } 319 }
290 int ret = sys_unshare(CLONE_NEWUSER); 320 int ret = sys_unshare(CLONE_NEWUSER);
291 if (ret) { 321 if (ret) {
292 const int unshare_errno = errno; 322 const int unshare_errno = errno;
293 VLOG(1) << "Looks like unprivileged CLONE_NEWUSER may not be available " 323 VLOG(1) << "Looks like unprivileged CLONE_NEWUSER may not be available "
294 << "on this kernel."; 324 << "on this kernel.";
295 CheckCloneNewUserErrno(unshare_errno); 325 CheckCloneNewUserErrno(unshare_errno);
296 return false; 326 return false;
297 } 327 }
298 328
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. 329 // 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. 330 // /proc/sys/kernel/overflowuid). Setup the uid and gid maps.
305 DCHECK(GetRESIds(NULL, NULL)); 331 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; 332 return true;
312 } 333 }
313 334
314 bool Credentials::DropFileSystemAccess(int proc_fd) { 335 bool Credentials::DropFileSystemAccess(int proc_fd) {
315 CHECK_LE(0, proc_fd); 336 CHECK_LE(0, proc_fd);
316 337
317 CHECK(ChrootToSafeEmptyDir()); 338 CHECK(ChrootToSafeEmptyDir());
318 CHECK(!HasFileSystemAccess()); 339 CHECK(!HasFileSystemAccess());
319 CHECK(!ProcUtil::HasOpenDirectory(proc_fd)); 340 CHECK(!ProcUtil::HasOpenDirectory(proc_fd));
320 // We never let this function fail. 341 // We never let this function fail.
321 return true; 342 return true;
322 } 343 }
323 344
324 bool Credentials::HasFileSystemAccess() { 345 bool Credentials::HasFileSystemAccess() {
325 return base::DirectoryExists(base::FilePath("/proc")); 346 return base::DirectoryExists(base::FilePath("/proc"));
326 } 347 }
327 348
328 pid_t Credentials::ForkAndDropCapabilitiesInChild() { 349 pid_t Credentials::ForkAndDropCapabilitiesInChild() {
329 pid_t pid = fork(); 350 pid_t pid = fork();
330 if (pid != 0) { 351 if (pid != 0) {
331 return pid; 352 return pid;
332 } 353 }
333 354
334 // Since we just forked, we are single threaded. 355 // Since we just forked, we are single threaded.
335 PCHECK(DropAllCapabilitiesOnCurrentThread()); 356 PCHECK(DropAllCapabilitiesOnCurrentThread());
336 return 0; 357 return 0;
337 } 358 }
338 359
339 } // namespace sandbox. 360 } // namespace sandbox.
OLDNEW
« no previous file with comments | « no previous file | sandbox/linux/suid/client/setuid_sandbox_client.cc » ('j') | sandbox/linux/suid/client/setuid_sandbox_client.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698