File: proc_util.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (136 lines) | stat: -rw-r--r-- 3,547 bytes parent folder | download | duplicates (6)
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
136
// 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.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/390223051): Remove C-library calls to fix the errors.
#pragma allow_unsafe_libc_calls
#endif

#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/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 (strcmp(de->d_name, ".") == 0 || 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) {
  DCHECK_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 (strcmp(de->d_name, ".") == 0 || 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 (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