• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "sandbox/linux/services/namespace_utils.h"
6 
7 #include <fcntl.h>
8 #include <sched.h>
9 #include <stddef.h>
10 #include <sys/stat.h>
11 #include <sys/types.h>
12 #include <unistd.h>
13 
14 #include <string>
15 
16 #include "base/files/file_path.h"
17 #include "base/files/file_util.h"
18 #include "base/files/scoped_file.h"
19 #include "base/logging.h"
20 #include "base/posix/eintr_wrapper.h"
21 #include "base/process/launch.h"
22 #include "base/strings/safe_sprintf.h"
23 #include "base/third_party/valgrind/valgrind.h"
24 
25 namespace sandbox {
26 
27 namespace {
IsRunningOnValgrind()28 bool IsRunningOnValgrind() {
29   return RUNNING_ON_VALGRIND;
30 }
31 
32 const char kProcSelfSetgroups[] = "/proc/self/setgroups";
33 }  // namespace
34 
35 // static
WriteToIdMapFile(const char * map_file,generic_id_t id)36 bool NamespaceUtils::WriteToIdMapFile(const char* map_file, generic_id_t id) {
37   // This function needs to be async-signal-safe, as it may be called in between
38   // fork and exec.
39 
40   int fd = HANDLE_EINTR(open(map_file, O_WRONLY));
41   if (fd == -1) {
42     return false;
43   }
44 
45   const generic_id_t inside_id = id;
46   const generic_id_t outside_id = id;
47 
48   char mapping[64];
49   const ssize_t len =
50       base::strings::SafeSPrintf(mapping, "%d %d 1\n", inside_id, outside_id);
51   const ssize_t rc = HANDLE_EINTR(write(fd, mapping, len));
52   RAW_CHECK(IGNORE_EINTR(close(fd)) == 0);
53   return rc == len;
54 }
55 
56 // static
KernelSupportsUnprivilegedNamespace(int type)57 bool NamespaceUtils::KernelSupportsUnprivilegedNamespace(int type) {
58   // Valgrind will let clone(2) pass-through, but doesn't support unshare(),
59   // so always consider namespaces unsupported there.
60   if (IsRunningOnValgrind()) {
61     return false;
62   }
63 
64   // As of Linux 3.8, /proc/self/ns/* files exist for all namespace types. Since
65   // user namespaces were added in 3.8, it is OK to rely on the existence of
66   // /proc/self/ns/*.
67   if (!base::PathExists(base::FilePath("/proc/self/ns/user"))) {
68     return false;
69   }
70 
71   const char* path;
72   switch (type) {
73     case CLONE_NEWUSER:
74       return true;
75     case CLONE_NEWIPC:
76       path = "/proc/self/ns/ipc";
77       break;
78     case CLONE_NEWNET:
79       path = "/proc/self/ns/net";
80       break;
81     case CLONE_NEWNS:
82       path = "/proc/self/ns/mnt";
83       break;
84     case CLONE_NEWPID:
85       path = "/proc/self/ns/pid";
86       break;
87     case CLONE_NEWUTS:
88       path = "/proc/self/ns/uts";
89       break;
90     default:
91       NOTREACHED();
92       return false;
93   }
94 
95   return base::PathExists(base::FilePath(path));
96 }
97 
98 // static
KernelSupportsDenySetgroups()99 bool NamespaceUtils::KernelSupportsDenySetgroups() {
100   return base::PathExists(base::FilePath(kProcSelfSetgroups));
101 }
102 
103 // static
DenySetgroups()104 bool NamespaceUtils::DenySetgroups() {
105   // This function needs to be async-signal-safe.
106   int fd = HANDLE_EINTR(open(kProcSelfSetgroups, O_WRONLY));
107   if (fd == -1) {
108     return false;
109   }
110 
111   static const char kDeny[] = "deny";
112   const ssize_t len = sizeof(kDeny) - 1;
113   const ssize_t rc = HANDLE_EINTR(write(fd, kDeny, len));
114   RAW_CHECK(IGNORE_EINTR(close(fd)) == 0);
115   return rc == len;
116 }
117 
118 }  // namespace sandbox
119