File: proc_util.cc

package info (click to toggle)
chromium 145.0.7632.159-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 5,976,224 kB
  • sloc: cpp: 36,198,469; ansic: 7,634,080; javascript: 3,564,060; python: 1,649,622; xml: 838,470; asm: 717,087; pascal: 185,708; sh: 88,786; perl: 88,718; objc: 79,984; sql: 59,811; cs: 42,452; fortran: 24,101; makefile: 21,144; tcl: 15,277; php: 14,022; yacc: 9,066; ruby: 7,553; awk: 3,720; lisp: 3,233; lex: 1,328; ada: 727; jsp: 228; sed: 36
file content (135 lines) | stat: -rw-r--r-- 3,553 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "sandbox/linux/services/proc_util.h"

#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include <memory>

#include "base/check_op.h"
#include "base/compiler_specific.h"
#include "base/posix/eintr_wrapper.h"
#include "base/strings/string_number_conversions.h"

namespace sandbox {
namespace {

struct DIRCloser {
  void operator()(DIR* d) const {
    DCHECK(d);
    PCHECK(0 == closedir(d));
  }
};

typedef std::unique_ptr<DIR, DIRCloser> ScopedDIR;

base::ScopedFD OpenDirectory(const char* path) {
  DCHECK(path);
  base::ScopedFD directory_fd(
      HANDLE_EINTR(open(path, O_RDONLY | O_DIRECTORY | O_CLOEXEC)));
  PCHECK(directory_fd.is_valid());
  return directory_fd;
}

}  // namespace

int ProcUtil::CountOpenFds(int proc_fd) {
  DCHECK_LE(0, proc_fd);
  int proc_self_fd = HANDLE_EINTR(
      openat(proc_fd, "self/fd/", O_DIRECTORY | O_RDONLY | O_CLOEXEC));
  PCHECK(0 <= proc_self_fd);

  // Ownership of proc_self_fd is transferred here, it must not be closed
  // or modified afterwards except via dir.
  ScopedDIR dir(fdopendir(proc_self_fd));
  CHECK(dir);

  int count = 0;
  struct dirent* de;
  while ((de = readdir(dir.get()))) {
    if (UNSAFE_TODO(strcmp(de->d_name, ".")) == 0 ||
        UNSAFE_TODO(strcmp(de->d_name, "..")) == 0) {
      continue;
    }

    int fd_num;
    CHECK(base::StringToInt(de->d_name, &fd_num));
    if (fd_num == proc_fd || fd_num == proc_self_fd) {
      continue;
    }

    ++count;
  }
  return count;
}

bool ProcUtil::HasOpenDirectory(int proc_fd) {
  CHECK_LE(0, proc_fd);
  int proc_self_fd =
      openat(proc_fd, "self/fd/", O_DIRECTORY | O_RDONLY | O_CLOEXEC);

  PCHECK(0 <= proc_self_fd);

  // Ownership of proc_self_fd is transferred here, it must not be closed
  // or modified afterwards except via dir.
  ScopedDIR dir(fdopendir(proc_self_fd));
  CHECK(dir);

  struct dirent* de;
  while ((de = readdir(dir.get()))) {
    if (UNSAFE_TODO(strcmp(de->d_name, ".")) == 0 ||
        UNSAFE_TODO(strcmp(de->d_name, "..")) == 0) {
      continue;
    }

    int fd_num;
    CHECK(base::StringToInt(de->d_name, &fd_num));
    if (fd_num == proc_fd || fd_num == proc_self_fd) {
      continue;
    }

    struct stat s;
    // It's OK to use proc_self_fd here, fstatat won't modify it.
    int stat_res = fstatat(proc_self_fd, de->d_name, &s, 0);
    // Check for stale symlinks and skip them if they meet certain criteria.
    // See crbug.com/362595425
    char filename[PATH_MAX] = {};  // Initialize for robustness
    if (stat_res == -1 && errno == ESTALE && de->d_type == DT_LNK &&
        readlinkat(proc_self_fd, de->d_name, filename, sizeof(filename)) !=
            -1) {
      static constexpr std::string_view kStalePrefix = "/google/cog/";
      if (UNSAFE_TODO(strncmp(filename, kStalePrefix.data(),
                              kStalePrefix.size())) == 0) {
        continue;
      }
    }
    PCHECK(stat_res == 0);
    if (S_ISDIR(s.st_mode)) {
      return true;
    }
  }

  // No open unmanaged directories found.
  return false;
}

bool ProcUtil::HasOpenDirectory() {
  base::ScopedFD proc_fd(
      HANDLE_EINTR(open("/proc/", O_DIRECTORY | O_RDONLY | O_CLOEXEC)));
  return HasOpenDirectory(proc_fd.get());
}

// static
base::ScopedFD ProcUtil::OpenProc() {
  return OpenDirectory("/proc/");
}

}  // namespace sandbox