Home | History | Annotate | Download | only in services
      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 {
     28 bool IsRunningOnValgrind() {
     29   return RUNNING_ON_VALGRIND;
     30 }
     31 
     32 const char kProcSelfSetgroups[] = "/proc/self/setgroups";
     33 }  // namespace
     34 
     35 // static
     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
     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
     99 bool NamespaceUtils::KernelSupportsDenySetgroups() {
    100   return base::PathExists(base::FilePath(kProcSelfSetgroups));
    101 }
    102 
    103 // static
    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