blob: 5689c28e223f4dc3df8706c106ae99d17a85ed99 [file] [log] [blame]
Chun-Ta Lin32b8a512019-03-25 18:53:40 +08001// Copyright 2019 The Chromium OS 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 "debugd/src/probe_tool.h"
6
Clark Chungfb2997b2019-07-10 12:21:33 +08007#include <fcntl.h>
Chun-Ta Lin32b8a512019-03-25 18:53:40 +08008
Chung-Sheng Wu0d82b442020-10-13 11:37:24 +08009#include <array>
Chun-Ta Lin32b8a512019-03-25 18:53:40 +080010#include <memory>
11#include <string>
12#include <utility>
13#include <vector>
14
Chun-Ta Lin32b8a512019-03-25 18:53:40 +080015#include <base/files/file_path.h>
Clark Chungfb2997b2019-07-10 12:21:33 +080016#include <base/files/file_util.h>
17#include <base/files/scoped_file.h>
18#include <base/files/scoped_temp_dir.h>
Chun-Ta Lin32b8a512019-03-25 18:53:40 +080019#include <base/json/json_reader.h>
Clark Chungfb2997b2019-07-10 12:21:33 +080020#include <base/logging.h>
Chun-Ta Lin32b8a512019-03-25 18:53:40 +080021#include <base/strings/string_number_conversions.h>
Chun-Ta Lin32b8a512019-03-25 18:53:40 +080022#include <base/strings/stringprintf.h>
Clark Chungfb2997b2019-07-10 12:21:33 +080023#include <base/strings/string_split.h>
24#include <base/values.h>
Chun-Ta Lin32b8a512019-03-25 18:53:40 +080025#include <brillo/errors/error_codes.h>
26#include <build/build_config.h>
27#include <build/buildflag.h>
28#include <chromeos/dbus/service_constants.h>
29#include <vboot/crossystem.h>
30
Clark Chungfb2997b2019-07-10 12:21:33 +080031#include "debugd/src/error_utils.h"
32#include "debugd/src/sandboxed_process.h"
33
Chun-Ta Lin32b8a512019-03-25 18:53:40 +080034using base::ListValue;
35
36namespace debugd {
37
38namespace {
39constexpr char kErrorPath[] = "org.chromium.debugd.RunProbeFunctionError";
40constexpr char kSandboxInfoDir[] = "/etc/runtime_probe/sandbox";
Chung-Sheng Wu0d82b442020-10-13 11:37:24 +080041constexpr std::array<const char*, 3> kBinaryAndArgs{"/usr/bin/runtime_probe",
42 "--helper", "--"};
Chun-Ta Lin32b8a512019-03-25 18:53:40 +080043constexpr char kRunAs[] = "runtime_probe";
44
Tom Hughesd6c2d392020-08-24 18:12:11 -070045bool CreateNonblockingPipe(base::ScopedFD* read_fd, base::ScopedFD* write_fd) {
Clark Chungfb2997b2019-07-10 12:21:33 +080046 int pipe_fd[2];
47 int ret = pipe2(pipe_fd, O_CLOEXEC | O_NONBLOCK);
48 if (ret != 0) {
49 PLOG(ERROR) << "Cannot create a pipe.";
50 return false;
51 }
52 read_fd->reset(pipe_fd[0]);
53 write_fd->reset(pipe_fd[1]);
54 return true;
55}
56
Chun-Ta Lin32b8a512019-03-25 18:53:40 +080057} // namespace
58
Clark Chungfb2997b2019-07-10 12:21:33 +080059bool ProbeTool::EvaluateProbeFunction(
60 brillo::ErrorPtr* error,
61 const std::string& sandbox_info,
62 const std::string& probe_statement,
Tom Hughesd6c2d392020-08-24 18:12:11 -070063 brillo::dbus_utils::FileDescriptor* outfd) {
Chun-Ta Lin32b8a512019-03-25 18:53:40 +080064 std::unique_ptr<brillo::Process> process;
65
66 // Details of sandboxing for probing should be centralized in a single
67 // directory. Sandboxing is mandatory when we don't allow debug features.
68 if (VbGetSystemPropertyInt("cros_debug") != 1) {
Clark Chungfb2997b2019-07-10 12:21:33 +080069 std::unique_ptr<SandboxedProcess> sandboxed_process{new SandboxedProcess()};
Chun-Ta Lin32b8a512019-03-25 18:53:40 +080070
71 const auto seccomp_path = base::FilePath{kSandboxInfoDir}.Append(
72 base::StringPrintf("%s-seccomp.policy", sandbox_info.c_str()));
73 const auto minijail_args_path = base::FilePath{kSandboxInfoDir}.Append(
74 base::StringPrintf("%s.args", sandbox_info.c_str()));
75
76 if (!base::PathExists(seccomp_path) ||
77 !base::PathExists(minijail_args_path)) {
78 DEBUGD_ADD_ERROR(error, kErrorPath,
79 "Sandbox info is missing for this architecture");
80 return false;
81 }
82
83 // Read and parse the arguments, use JSON to avoid quote escaping.
84 std::string minijail_args_str;
85 if (!base::ReadFileToString(base::FilePath(minijail_args_path),
86 &minijail_args_str)) {
87 DEBUGD_ADD_ERROR(error, kErrorPath, "Failed to load minijail arguments");
88 return false;
89 }
90
91 DLOG(INFO) << "minijail arguments : " << minijail_args_str;
92
93 // Parse the JSON formatted minijail arguments.
hscham7d195262020-06-17 14:13:33 +090094 auto minijail_args = base::JSONReader::Read(minijail_args_str);
Chun-Ta Lin32b8a512019-03-25 18:53:40 +080095
96 if (!minijail_args) {
97 DEBUGD_ADD_ERROR(error, kErrorPath,
98 "minijail args are not stored in list");
99 return false;
100 }
101 std::vector<std::string> parsed_args;
102
103 // The following is the general minijail set up for runtime_probe in debugd
104 // /dev/log needs to be bind mounted before any possible tmpfs mount on run
105 parsed_args.push_back("-G"); // Inherit all the supplementary groups
106
107 // Run the process inside the new VFS namespace. The root of VFS is mounted
108 // on /var/empty/
109 parsed_args.push_back("-P");
110 parsed_args.push_back("/mnt/empty");
111
112 parsed_args.push_back("-b"); // Bind mount rootfs
113 parsed_args.push_back("/"); // Bind mount rootfs
114 parsed_args.push_back("-b"); // Bind mount /proc
115 parsed_args.push_back("/proc"); // Bind mount /proc
116 parsed_args.push_back("-b"); // Enable logging in minijail
117 parsed_args.push_back("/dev/log"); // Enable logging in minijail
118 parsed_args.push_back("-t"); // Bind mount /tmp
119 parsed_args.push_back("-r"); // Remount /proc read-only
120 parsed_args.push_back("-d"); // Mount a new /dev with minimum nodes
121
hscham7d195262020-06-17 14:13:33 +0900122 for (const auto& arg : minijail_args->GetList()) {
123 if (!arg.is_string()) {
Chun-Ta Lin32b8a512019-03-25 18:53:40 +0800124 DEBUGD_ADD_ERROR(error, kErrorPath,
125 "Failed to parse minijail arguments");
126 return false;
127 }
hscham7d195262020-06-17 14:13:33 +0900128 parsed_args.push_back(arg.GetString());
Chun-Ta Lin32b8a512019-03-25 18:53:40 +0800129 }
130
131 sandboxed_process->SandboxAs(kRunAs, kRunAs);
132 sandboxed_process->SetSeccompFilterPolicyFile(seccomp_path.MaybeAsASCII());
133 DLOG(INFO) << "Sandbox for " << sandbox_info << " is ready";
134 if (!sandboxed_process->Init(parsed_args)) {
135 DEBUGD_ADD_ERROR(error, kErrorPath, "Process initialization failure.");
136 return false;
137 }
138 process = std::move(sandboxed_process);
139 } else {
140 process = std::make_unique<brillo::ProcessImpl>();
141 // Explicitly running it without sandboxing.
142 LOG(ERROR) << "Running " << sandbox_info << " without sandbox";
143 }
Clark Chungfb2997b2019-07-10 12:21:33 +0800144 base::ScopedFD read_fd, write_fd;
145 if (!CreateNonblockingPipe(&read_fd, &write_fd)) {
146 DEBUGD_ADD_ERROR(error, kErrorPath, "Cannot create a pipe.");
147 return false;
148 }
Chun-Ta Lin32b8a512019-03-25 18:53:40 +0800149
Chung-Sheng Wu0d82b442020-10-13 11:37:24 +0800150 for (auto arg : kBinaryAndArgs) {
151 process->AddArg(arg);
152 }
Chun-Ta Lin32b8a512019-03-25 18:53:40 +0800153 process->AddArg(probe_statement);
Clark Chungfb2997b2019-07-10 12:21:33 +0800154 process->BindFd(write_fd.get(), STDOUT_FILENO);
155 process->Start();
156 process->Release();
157 *outfd = std::move(read_fd);
Chun-Ta Lin32b8a512019-03-25 18:53:40 +0800158 return true;
159}
160
161} // namespace debugd