1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2021 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker *
4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker *
8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker *
10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker */
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker #include <sys/capability.h>
18*795d594fSAndroid Build Coastguard Worker #include <sys/resource.h>
19*795d594fSAndroid Build Coastguard Worker #include <sys/types.h>
20*795d594fSAndroid Build Coastguard Worker
21*795d594fSAndroid Build Coastguard Worker #include <string>
22*795d594fSAndroid Build Coastguard Worker
23*795d594fSAndroid Build Coastguard Worker #include "android-base/file.h"
24*795d594fSAndroid Build Coastguard Worker #include "android-base/logging.h"
25*795d594fSAndroid Build Coastguard Worker #include "android-base/strings.h"
26*795d594fSAndroid Build Coastguard Worker #include "base/common_art_test.h"
27*795d594fSAndroid Build Coastguard Worker #include "base/globals.h"
28*795d594fSAndroid Build Coastguard Worker #include "base/macros.h"
29*795d594fSAndroid Build Coastguard Worker #include "base/os.h"
30*795d594fSAndroid Build Coastguard Worker #include "base/scoped_cap.h"
31*795d594fSAndroid Build Coastguard Worker #include "exec_utils.h"
32*795d594fSAndroid Build Coastguard Worker #include "gmock/gmock.h"
33*795d594fSAndroid Build Coastguard Worker #include "gtest/gtest.h"
34*795d594fSAndroid Build Coastguard Worker #include "system/thread_defs.h"
35*795d594fSAndroid Build Coastguard Worker #include "tools/testing.h"
36*795d594fSAndroid Build Coastguard Worker
37*795d594fSAndroid Build Coastguard Worker #ifdef ART_TARGET_ANDROID
38*795d594fSAndroid Build Coastguard Worker #include "android-modules-utils/sdk_level.h"
39*795d594fSAndroid Build Coastguard Worker #endif
40*795d594fSAndroid Build Coastguard Worker
41*795d594fSAndroid Build Coastguard Worker namespace art {
42*795d594fSAndroid Build Coastguard Worker namespace tools {
43*795d594fSAndroid Build Coastguard Worker namespace {
44*795d594fSAndroid Build Coastguard Worker
45*795d594fSAndroid Build Coastguard Worker using ::android::base::Split;
46*795d594fSAndroid Build Coastguard Worker using ::testing::Contains;
47*795d594fSAndroid Build Coastguard Worker using ::testing::ElementsAre;
48*795d594fSAndroid Build Coastguard Worker using ::testing::HasSubstr;
49*795d594fSAndroid Build Coastguard Worker using ::testing::Not;
50*795d594fSAndroid Build Coastguard Worker
51*795d594fSAndroid Build Coastguard Worker constexpr uid_t kRoot = 0;
52*795d594fSAndroid Build Coastguard Worker constexpr uid_t kNobody = 9999;
53*795d594fSAndroid Build Coastguard Worker
54*795d594fSAndroid Build Coastguard Worker // Grants the current process the given root capability.
SetCap(cap_flag_t flag,cap_value_t value)55*795d594fSAndroid Build Coastguard Worker void SetCap(cap_flag_t flag, cap_value_t value) {
56*795d594fSAndroid Build Coastguard Worker ScopedCap cap(cap_get_proc());
57*795d594fSAndroid Build Coastguard Worker CHECK_NE(cap.Get(), nullptr);
58*795d594fSAndroid Build Coastguard Worker cap_value_t caps[]{value};
59*795d594fSAndroid Build Coastguard Worker CHECK_EQ(cap_set_flag(cap.Get(), flag, /*ncap=*/1, caps, CAP_SET), 0);
60*795d594fSAndroid Build Coastguard Worker CHECK_EQ(cap_set_proc(cap.Get()), 0);
61*795d594fSAndroid Build Coastguard Worker }
62*795d594fSAndroid Build Coastguard Worker
63*795d594fSAndroid Build Coastguard Worker // Returns true if the given process has the given root capability.
GetCap(pid_t pid,cap_flag_t flag,cap_value_t value)64*795d594fSAndroid Build Coastguard Worker bool GetCap(pid_t pid, cap_flag_t flag, cap_value_t value) {
65*795d594fSAndroid Build Coastguard Worker ScopedCap cap(cap_get_pid(pid));
66*795d594fSAndroid Build Coastguard Worker CHECK_NE(cap.Get(), nullptr);
67*795d594fSAndroid Build Coastguard Worker cap_flag_value_t flag_value;
68*795d594fSAndroid Build Coastguard Worker CHECK_EQ(cap_get_flag(cap.Get(), value, flag, &flag_value), 0);
69*795d594fSAndroid Build Coastguard Worker return flag_value == CAP_SET;
70*795d594fSAndroid Build Coastguard Worker }
71*795d594fSAndroid Build Coastguard Worker
72*795d594fSAndroid Build Coastguard Worker class ArtExecTest : public testing::Test {
73*795d594fSAndroid Build Coastguard Worker protected:
SetUp()74*795d594fSAndroid Build Coastguard Worker void SetUp() override {
75*795d594fSAndroid Build Coastguard Worker testing::Test::SetUp();
76*795d594fSAndroid Build Coastguard Worker if (!kIsTargetAndroid) {
77*795d594fSAndroid Build Coastguard Worker GTEST_SKIP() << "art_exec is for device only";
78*795d594fSAndroid Build Coastguard Worker }
79*795d594fSAndroid Build Coastguard Worker if (getuid() != kRoot) {
80*795d594fSAndroid Build Coastguard Worker GTEST_SKIP() << "art_exec requires root";
81*795d594fSAndroid Build Coastguard Worker }
82*795d594fSAndroid Build Coastguard Worker art_exec_bin_ = GetArtBin("art_exec");
83*795d594fSAndroid Build Coastguard Worker }
84*795d594fSAndroid Build Coastguard Worker
85*795d594fSAndroid Build Coastguard Worker std::string art_exec_bin_;
86*795d594fSAndroid Build Coastguard Worker };
87*795d594fSAndroid Build Coastguard Worker
TEST_F(ArtExecTest,Command)88*795d594fSAndroid Build Coastguard Worker TEST_F(ArtExecTest, Command) {
89*795d594fSAndroid Build Coastguard Worker std::string error_msg;
90*795d594fSAndroid Build Coastguard Worker int ret = ExecAndReturnCode({art_exec_bin_, "--", GetBin("sh"), "-c", "exit 123"}, &error_msg);
91*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(ret, 123) << error_msg;
92*795d594fSAndroid Build Coastguard Worker }
93*795d594fSAndroid Build Coastguard Worker
TEST_F(ArtExecTest,SetTaskProfiles)94*795d594fSAndroid Build Coastguard Worker TEST_F(ArtExecTest, SetTaskProfiles) {
95*795d594fSAndroid Build Coastguard Worker // The condition is always true because ArtExecTest is run on device only.
96*795d594fSAndroid Build Coastguard Worker #ifdef ART_TARGET_ANDROID
97*795d594fSAndroid Build Coastguard Worker if (!android::modules::sdklevel::IsAtLeastU()) {
98*795d594fSAndroid Build Coastguard Worker GTEST_SKIP() << "This test depends on a libartpalette API that is only available on U+";
99*795d594fSAndroid Build Coastguard Worker }
100*795d594fSAndroid Build Coastguard Worker #endif
101*795d594fSAndroid Build Coastguard Worker
102*795d594fSAndroid Build Coastguard Worker std::string filename = "/data/local/tmp/art-exec-test-XXXXXX";
103*795d594fSAndroid Build Coastguard Worker ScratchFile scratch_file(new File(mkstemp(filename.data()), filename, /*check_usage=*/false));
104*795d594fSAndroid Build Coastguard Worker ASSERT_GE(scratch_file.GetFd(), 0);
105*795d594fSAndroid Build Coastguard Worker
106*795d594fSAndroid Build Coastguard Worker std::vector<std::string> args{art_exec_bin_,
107*795d594fSAndroid Build Coastguard Worker "--set-task-profile=ProcessCapacityHigh",
108*795d594fSAndroid Build Coastguard Worker "--",
109*795d594fSAndroid Build Coastguard Worker GetBin("sh"),
110*795d594fSAndroid Build Coastguard Worker "-c",
111*795d594fSAndroid Build Coastguard Worker "cat /proc/self/cgroup > " + filename};
112*795d594fSAndroid Build Coastguard Worker auto [pid, scope_guard] = ScopedExec(args, /*wait=*/true);
113*795d594fSAndroid Build Coastguard Worker std::string cgroup;
114*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(android::base::ReadFileToString(filename, &cgroup));
115*795d594fSAndroid Build Coastguard Worker EXPECT_THAT(cgroup, HasSubstr(":cpuset:/foreground\n"));
116*795d594fSAndroid Build Coastguard Worker }
117*795d594fSAndroid Build Coastguard Worker
TEST_F(ArtExecTest,SetPriority)118*795d594fSAndroid Build Coastguard Worker TEST_F(ArtExecTest, SetPriority) {
119*795d594fSAndroid Build Coastguard Worker std::vector<std::string> args{art_exec_bin_, "--set-priority=background", "--", GetBin("true")};
120*795d594fSAndroid Build Coastguard Worker auto [pid, scope_guard] = ScopedExec(args, /*wait=*/true);
121*795d594fSAndroid Build Coastguard Worker EXPECT_EQ(getpriority(PRIO_PROCESS, pid), ANDROID_PRIORITY_BACKGROUND);
122*795d594fSAndroid Build Coastguard Worker }
123*795d594fSAndroid Build Coastguard Worker
TEST_F(ArtExecTest,DropCapabilities)124*795d594fSAndroid Build Coastguard Worker TEST_F(ArtExecTest, DropCapabilities) {
125*795d594fSAndroid Build Coastguard Worker // Switch to a non-root user, but still keep the CAP_FOWNER capability available and inheritable.
126*795d594fSAndroid Build Coastguard Worker // The order of the following calls matters.
127*795d594fSAndroid Build Coastguard Worker CHECK_EQ(cap_setuid(kNobody), 0);
128*795d594fSAndroid Build Coastguard Worker SetCap(CAP_INHERITABLE, CAP_FOWNER);
129*795d594fSAndroid Build Coastguard Worker SetCap(CAP_EFFECTIVE, CAP_FOWNER);
130*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(cap_set_ambient(CAP_FOWNER, CAP_SET), 0);
131*795d594fSAndroid Build Coastguard Worker
132*795d594fSAndroid Build Coastguard Worker // Make sure the test is set up correctly (i.e., the child process should normally have the
133*795d594fSAndroid Build Coastguard Worker // inherited root capability: CAP_FOWNER).
134*795d594fSAndroid Build Coastguard Worker {
135*795d594fSAndroid Build Coastguard Worker std::vector<std::string> args{art_exec_bin_, "--", GetBin("true")};
136*795d594fSAndroid Build Coastguard Worker auto [pid, scope_guard] = ScopedExec(args, /*wait=*/true);
137*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(GetCap(pid, CAP_EFFECTIVE, CAP_FOWNER));
138*795d594fSAndroid Build Coastguard Worker }
139*795d594fSAndroid Build Coastguard Worker
140*795d594fSAndroid Build Coastguard Worker {
141*795d594fSAndroid Build Coastguard Worker std::vector<std::string> args{art_exec_bin_, "--drop-capabilities", "--", GetBin("true")};
142*795d594fSAndroid Build Coastguard Worker auto [pid, scope_guard] = ScopedExec(args, /*wait=*/true);
143*795d594fSAndroid Build Coastguard Worker EXPECT_FALSE(GetCap(pid, CAP_EFFECTIVE, CAP_FOWNER));
144*795d594fSAndroid Build Coastguard Worker }
145*795d594fSAndroid Build Coastguard Worker }
146*795d594fSAndroid Build Coastguard Worker
TEST_F(ArtExecTest,CloseFds)147*795d594fSAndroid Build Coastguard Worker TEST_F(ArtExecTest, CloseFds) {
148*795d594fSAndroid Build Coastguard Worker std::unique_ptr<File> file1(OS::OpenFileForReading("/dev/zero"));
149*795d594fSAndroid Build Coastguard Worker std::unique_ptr<File> file2(OS::OpenFileForReading("/dev/zero"));
150*795d594fSAndroid Build Coastguard Worker std::unique_ptr<File> file3(OS::OpenFileForReading("/dev/zero"));
151*795d594fSAndroid Build Coastguard Worker ASSERT_NE(file1, nullptr);
152*795d594fSAndroid Build Coastguard Worker ASSERT_NE(file2, nullptr);
153*795d594fSAndroid Build Coastguard Worker ASSERT_NE(file3, nullptr);
154*795d594fSAndroid Build Coastguard Worker
155*795d594fSAndroid Build Coastguard Worker std::string filename = "/data/local/tmp/art-exec-test-XXXXXX";
156*795d594fSAndroid Build Coastguard Worker ScratchFile scratch_file(new File(mkstemp(filename.data()), filename, /*check_usage=*/false));
157*795d594fSAndroid Build Coastguard Worker ASSERT_GE(scratch_file.GetFd(), 0);
158*795d594fSAndroid Build Coastguard Worker
159*795d594fSAndroid Build Coastguard Worker std::vector<std::string> args{art_exec_bin_,
160*795d594fSAndroid Build Coastguard Worker ART_FORMAT("--keep-fds={}:{}", file3->Fd(), file2->Fd()),
161*795d594fSAndroid Build Coastguard Worker "--",
162*795d594fSAndroid Build Coastguard Worker GetBin("sh"),
163*795d594fSAndroid Build Coastguard Worker "-c",
164*795d594fSAndroid Build Coastguard Worker ART_FORMAT("("
165*795d594fSAndroid Build Coastguard Worker "readlink /proc/self/fd/{} || echo;"
166*795d594fSAndroid Build Coastguard Worker "readlink /proc/self/fd/{} || echo;"
167*795d594fSAndroid Build Coastguard Worker "readlink /proc/self/fd/{} || echo;"
168*795d594fSAndroid Build Coastguard Worker ") > {}",
169*795d594fSAndroid Build Coastguard Worker file1->Fd(),
170*795d594fSAndroid Build Coastguard Worker file2->Fd(),
171*795d594fSAndroid Build Coastguard Worker file3->Fd(),
172*795d594fSAndroid Build Coastguard Worker filename)};
173*795d594fSAndroid Build Coastguard Worker
174*795d594fSAndroid Build Coastguard Worker ScopedExec(args, /*wait=*/true);
175*795d594fSAndroid Build Coastguard Worker
176*795d594fSAndroid Build Coastguard Worker std::string open_fds;
177*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(android::base::ReadFileToString(filename, &open_fds));
178*795d594fSAndroid Build Coastguard Worker
179*795d594fSAndroid Build Coastguard Worker // `file1` should be closed, while the other two should be open. There's a blank line at the end.
180*795d594fSAndroid Build Coastguard Worker EXPECT_THAT(Split(open_fds, "\n"), ElementsAre(Not("/dev/zero"), "/dev/zero", "/dev/zero", ""));
181*795d594fSAndroid Build Coastguard Worker }
182*795d594fSAndroid Build Coastguard Worker
TEST_F(ArtExecTest,Env)183*795d594fSAndroid Build Coastguard Worker TEST_F(ArtExecTest, Env) {
184*795d594fSAndroid Build Coastguard Worker std::string filename = "/data/local/tmp/art-exec-test-XXXXXX";
185*795d594fSAndroid Build Coastguard Worker ScratchFile scratch_file(new File(mkstemp(filename.data()), filename, /*check_usage=*/false));
186*795d594fSAndroid Build Coastguard Worker ASSERT_GE(scratch_file.GetFd(), 0);
187*795d594fSAndroid Build Coastguard Worker
188*795d594fSAndroid Build Coastguard Worker std::vector<std::string> args{
189*795d594fSAndroid Build Coastguard Worker art_exec_bin_, "--env=FOO=BAR", "--", GetBin("sh"), "-c", "env > " + filename};
190*795d594fSAndroid Build Coastguard Worker
191*795d594fSAndroid Build Coastguard Worker ScopedExec(args, /*wait=*/true);
192*795d594fSAndroid Build Coastguard Worker
193*795d594fSAndroid Build Coastguard Worker std::string envs;
194*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(android::base::ReadFileToString(filename, &envs));
195*795d594fSAndroid Build Coastguard Worker
196*795d594fSAndroid Build Coastguard Worker EXPECT_THAT(Split(envs, "\n"), Contains("FOO=BAR"));
197*795d594fSAndroid Build Coastguard Worker }
198*795d594fSAndroid Build Coastguard Worker
TEST_F(ArtExecTest,ProcessNameSuffix)199*795d594fSAndroid Build Coastguard Worker TEST_F(ArtExecTest, ProcessNameSuffix) {
200*795d594fSAndroid Build Coastguard Worker std::string filename = "/data/local/tmp/art-exec-test-XXXXXX";
201*795d594fSAndroid Build Coastguard Worker ScratchFile scratch_file(new File(mkstemp(filename.data()), filename, /*check_usage=*/false));
202*795d594fSAndroid Build Coastguard Worker ASSERT_GE(scratch_file.GetFd(), 0);
203*795d594fSAndroid Build Coastguard Worker
204*795d594fSAndroid Build Coastguard Worker std::vector<std::string> args{art_exec_bin_,
205*795d594fSAndroid Build Coastguard Worker "--process-name-suffix=my suffix",
206*795d594fSAndroid Build Coastguard Worker "--",
207*795d594fSAndroid Build Coastguard Worker GetBin("toybox"),
208*795d594fSAndroid Build Coastguard Worker "cp",
209*795d594fSAndroid Build Coastguard Worker "/proc/self/cmdline",
210*795d594fSAndroid Build Coastguard Worker filename};
211*795d594fSAndroid Build Coastguard Worker
212*795d594fSAndroid Build Coastguard Worker ScopedExec(args, /*wait=*/true);
213*795d594fSAndroid Build Coastguard Worker
214*795d594fSAndroid Build Coastguard Worker std::string cmdline;
215*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(android::base::ReadFileToString(filename, &cmdline));
216*795d594fSAndroid Build Coastguard Worker
217*795d594fSAndroid Build Coastguard Worker EXPECT_THAT(cmdline, HasSubstr("toybox (my suffix)\0"));
218*795d594fSAndroid Build Coastguard Worker }
219*795d594fSAndroid Build Coastguard Worker
220*795d594fSAndroid Build Coastguard Worker } // namespace
221*795d594fSAndroid Build Coastguard Worker } // namespace tools
222*795d594fSAndroid Build Coastguard Worker } // namespace art
223