File: landlock_gpu_policy_android.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 (117 lines) | stat: -rw-r--r-- 3,886 bytes parent folder | download | duplicates (3)
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
// Copyright 2025 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/policy/linux/landlock_gpu_policy_android.h"

#include <string>
#include <vector>

#include "base/logging.h"
#include "base/files/scoped_file.h"
#include "base/threading/thread_id_name_manager.h"
#include "build/build_config.h"
#include "sandbox/linux/services/thread_helpers.h"

#if BUILDFLAG(IS_ANDROID)
#include <fcntl.h>
#include <sys/prctl.h>
#include <unistd.h>

namespace sandbox::landlock {

bool AddRulesToPolicy(int ruleset_fd,
                      const std::vector<std::string>& paths,
                      uint64_t allowed_access) {
  bool success = true;
  for (const auto& path : paths) {
    base::ScopedFD parent_fd(open(path.c_str(), O_PATH | O_CLOEXEC));
    if (!parent_fd.is_valid()) {
      PLOG(ERROR) << "open failed for " << path;
      continue;
    }
    struct landlock_path_beneath_attr path_beneath = {
        .allowed_access = allowed_access,
        .parent_fd = static_cast<uint32_t>(parent_fd.get()),
    };

    if (landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, &path_beneath,
                          0)) {
      PLOG(ERROR) << "landlock_add_rule() failed for " << path;
      success = false;
    }
  }
  return success;
}
#endif

bool ApplyLandlock(sandbox::mojom::Sandbox sandbox_type) {
#if BUILDFLAG(IS_ANDROID)
  if (sandbox_type != sandbox::mojom::Sandbox::kGpu) {
    LOG(ERROR) << "Sandbox type not GPU, skipping Landlock";
    return false;
  }

  if (!sandbox::ThreadHelpers::IsSingleThreaded()) {
    LOG(ERROR) << "Not single threaded, skipping Landlock";
    for (const auto& id : base::ThreadIdNameManager::GetInstance()->GetIds()) {
      LOG(ERROR) << "ThreadId=" << id << " name:"
                 << base::ThreadIdNameManager::GetInstance()->GetName(id);
    }
    return false;
  }

  struct landlock_ruleset_attr ruleset_attr = {
      .handled_access_fs = LANDLOCK_HANDLED_ACCESS_TYPES};
  base::ScopedFD ruleset_fd(
      landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0));
  if (!ruleset_fd.is_valid()) {
    PLOG(ERROR) << "Ruleset creation failed";
    return false;
  }

  std::vector<std::string> allowed_ro_paths = {
      // RO access to /data/app because there may be sub-directories that don't
      // exist yet at policy creation.
      "/data/app",
      // Allow read-only access to /proc/self. This is needed for the process
      // to introspect its own state.
      "/proc/self", "/sys"};
  uint64_t ro_access =
      LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_READ_DIR;
  if (!AddRulesToPolicy(ruleset_fd.get(), allowed_ro_paths, ro_access)) {
    LOG(ERROR) << "Adding Landlock RO rules failed";
  }

  std::vector<std::string> allowed_rw_paths = {
      "/data/cache/com.android.chrome",
      // We need to allowlist /dev, because ashmem creates dynamically named
      // directories, such as /dev/ashmemc4072f6e-da0f-447e-98d4-b6497e5f57af.
      // TODO(crbug.com/40215931): Move away from ashmem and remove this.
      "/dev",
  };
  uint64_t rw_access =
      LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_READ_DIR |
      LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_REMOVE_FILE;
  if (!AddRulesToPolicy(ruleset_fd.get(), allowed_rw_paths, rw_access)) {
    LOG(ERROR) << "Adding Landlock RW rules failed";
  }
  // Landlock requires no_new_privs.
  if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
    PLOG(ERROR) << "SET_NO_NEW_PRIVS failed";
    return false;
  }
  int result = landlock_restrict_self(ruleset_fd.get(), 0);
  if (result != 0) {
    PLOG(ERROR) << "landlock_restrict_self() failed";
    return false;
  }

  return true;
#else  // !BUILDFLAG(IS_ANDROID)
  // Landlock is not applicable on non-Android platforms.
  return false;
#endif
}

}  // namespace sandbox::landlock