Don't preload rarely seen large images
[chromium-blink-merge.git] / sandbox / linux / services / credentials_unittest.cc
blob6b93c86c3ecbc2104282b50da80e32f3d9ad06d3
1 // Copyright (c) 2012 The Chromium 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.
5 #include "sandbox/linux/services/credentials.h"
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <stdio.h>
10 #include <sys/capability.h>
11 #include <sys/stat.h>
12 #include <sys/types.h>
13 #include <unistd.h>
15 #include <vector>
17 #include "base/files/file_path.h"
18 #include "base/files/file_util.h"
19 #include "base/files/scoped_file.h"
20 #include "base/logging.h"
21 #include "base/memory/scoped_ptr.h"
22 #include "sandbox/linux/services/proc_util.h"
23 #include "sandbox/linux/services/syscall_wrappers.h"
24 #include "sandbox/linux/system_headers/capability.h"
25 #include "sandbox/linux/tests/unit_tests.h"
26 #include "testing/gtest/include/gtest/gtest.h"
28 namespace sandbox {
30 namespace {
32 struct CapFreeDeleter {
33 inline void operator()(cap_t cap) const {
34 int ret = cap_free(cap);
35 CHECK_EQ(0, ret);
39 // Wrapper to manage libcap2's cap_t type.
40 typedef scoped_ptr<typeof(*((cap_t)0)), CapFreeDeleter> ScopedCap;
42 bool WorkingDirectoryIsRoot() {
43 char current_dir[PATH_MAX];
44 char* cwd = getcwd(current_dir, sizeof(current_dir));
45 PCHECK(cwd);
46 if (strcmp("/", cwd)) return false;
48 // The current directory is the root. Add a few paranoid checks.
49 struct stat current;
50 CHECK_EQ(0, stat(".", &current));
51 struct stat parrent;
52 CHECK_EQ(0, stat("..", &parrent));
53 CHECK_EQ(current.st_dev, parrent.st_dev);
54 CHECK_EQ(current.st_ino, parrent.st_ino);
55 CHECK_EQ(current.st_mode, parrent.st_mode);
56 CHECK_EQ(current.st_uid, parrent.st_uid);
57 CHECK_EQ(current.st_gid, parrent.st_gid);
58 return true;
61 SANDBOX_TEST(Credentials, DropAllCaps) {
62 CHECK(Credentials::DropAllCapabilities());
63 CHECK(!Credentials::HasAnyCapability());
66 SANDBOX_TEST(Credentials, MoveToNewUserNS) {
67 CHECK(Credentials::DropAllCapabilities());
68 bool moved_to_new_ns = Credentials::MoveToNewUserNS();
69 fprintf(stdout,
70 "Unprivileged CLONE_NEWUSER supported: %s\n",
71 moved_to_new_ns ? "true." : "false.");
72 fflush(stdout);
73 if (!moved_to_new_ns) {
74 fprintf(stdout, "This kernel does not support unprivileged namespaces. "
75 "USERNS tests will succeed without running.\n");
76 fflush(stdout);
77 return;
79 CHECK(Credentials::HasAnyCapability());
80 CHECK(Credentials::DropAllCapabilities());
81 CHECK(!Credentials::HasAnyCapability());
84 SANDBOX_TEST(Credentials, CanCreateProcessInNewUserNS) {
85 CHECK(Credentials::DropAllCapabilities());
86 bool user_ns_supported = Credentials::CanCreateProcessInNewUserNS();
87 bool moved_to_new_ns = Credentials::MoveToNewUserNS();
88 CHECK_EQ(user_ns_supported, moved_to_new_ns);
91 SANDBOX_TEST(Credentials, UidIsPreserved) {
92 CHECK(Credentials::DropAllCapabilities());
93 uid_t old_ruid, old_euid, old_suid;
94 gid_t old_rgid, old_egid, old_sgid;
95 PCHECK(0 == getresuid(&old_ruid, &old_euid, &old_suid));
96 PCHECK(0 == getresgid(&old_rgid, &old_egid, &old_sgid));
97 // Probably missing kernel support.
98 if (!Credentials::MoveToNewUserNS()) return;
99 uid_t new_ruid, new_euid, new_suid;
100 PCHECK(0 == getresuid(&new_ruid, &new_euid, &new_suid));
101 CHECK(old_ruid == new_ruid);
102 CHECK(old_euid == new_euid);
103 CHECK(old_suid == new_suid);
105 gid_t new_rgid, new_egid, new_sgid;
106 PCHECK(0 == getresgid(&new_rgid, &new_egid, &new_sgid));
107 CHECK(old_rgid == new_rgid);
108 CHECK(old_egid == new_egid);
109 CHECK(old_sgid == new_sgid);
112 bool NewUserNSCycle() {
113 if (!Credentials::MoveToNewUserNS() ||
114 !Credentials::HasAnyCapability() ||
115 !Credentials::DropAllCapabilities() ||
116 Credentials::HasAnyCapability()) {
117 return false;
119 return true;
122 SANDBOX_TEST(Credentials, NestedUserNS) {
123 CHECK(Credentials::DropAllCapabilities());
124 // Probably missing kernel support.
125 if (!Credentials::MoveToNewUserNS()) return;
126 CHECK(Credentials::DropAllCapabilities());
127 // As of 3.12, the kernel has a limit of 32. See create_user_ns().
128 const int kNestLevel = 10;
129 for (int i = 0; i < kNestLevel; ++i) {
130 CHECK(NewUserNSCycle()) << "Creating new user NS failed at iteration "
131 << i << ".";
135 // Test the WorkingDirectoryIsRoot() helper.
136 SANDBOX_TEST(Credentials, CanDetectRoot) {
137 PCHECK(0 == chdir("/proc/"));
138 CHECK(!WorkingDirectoryIsRoot());
139 PCHECK(0 == chdir("/"));
140 CHECK(WorkingDirectoryIsRoot());
143 // Disabled on ASAN because of crbug.com/451603.
144 SANDBOX_TEST(Credentials, DISABLE_ON_ASAN(DropFileSystemAccessIsSafe)) {
145 CHECK(Credentials::DropAllCapabilities());
146 // Probably missing kernel support.
147 if (!Credentials::MoveToNewUserNS()) return;
148 CHECK(Credentials::DropFileSystemAccess(ProcUtil::OpenProc().get()));
149 CHECK(!base::DirectoryExists(base::FilePath("/proc")));
150 CHECK(WorkingDirectoryIsRoot());
151 CHECK(base::IsDirectoryEmpty(base::FilePath("/")));
152 // We want the chroot to never have a subdirectory. A subdirectory
153 // could allow a chroot escape.
154 CHECK_NE(0, mkdir("/test", 0700));
157 // Check that after dropping filesystem access and dropping privileges
158 // it is not possible to regain capabilities.
159 SANDBOX_TEST(Credentials, DISABLE_ON_ASAN(CannotRegainPrivileges)) {
160 base::ScopedFD proc_fd(ProcUtil::OpenProc());
161 CHECK(Credentials::DropAllCapabilities(proc_fd.get()));
162 // Probably missing kernel support.
163 if (!Credentials::MoveToNewUserNS()) return;
164 CHECK(Credentials::DropFileSystemAccess(proc_fd.get()));
165 CHECK(Credentials::DropAllCapabilities(proc_fd.get()));
167 // The kernel should now prevent us from regaining capabilities because we
168 // are in a chroot.
169 CHECK(!Credentials::CanCreateProcessInNewUserNS());
170 CHECK(!Credentials::MoveToNewUserNS());
173 SANDBOX_TEST(Credentials, SetCapabilities) {
174 // Probably missing kernel support.
175 if (!Credentials::MoveToNewUserNS())
176 return;
178 base::ScopedFD proc_fd(ProcUtil::OpenProc());
180 CHECK(Credentials::HasCapability(Credentials::Capability::SYS_ADMIN));
181 CHECK(Credentials::HasCapability(Credentials::Capability::SYS_CHROOT));
183 std::vector<Credentials::Capability> caps;
184 caps.push_back(Credentials::Capability::SYS_CHROOT);
185 CHECK(Credentials::SetCapabilities(proc_fd.get(), caps));
187 CHECK(!Credentials::HasCapability(Credentials::Capability::SYS_ADMIN));
188 CHECK(Credentials::HasCapability(Credentials::Capability::SYS_CHROOT));
190 const std::vector<Credentials::Capability> no_caps;
191 CHECK(Credentials::SetCapabilities(proc_fd.get(), no_caps));
192 CHECK(!Credentials::HasAnyCapability());
195 SANDBOX_TEST(Credentials, SetCapabilitiesAndChroot) {
196 // Probably missing kernel support.
197 if (!Credentials::MoveToNewUserNS())
198 return;
200 base::ScopedFD proc_fd(ProcUtil::OpenProc());
202 CHECK(Credentials::HasCapability(Credentials::Capability::SYS_CHROOT));
203 PCHECK(chroot("/") == 0);
205 std::vector<Credentials::Capability> caps;
206 caps.push_back(Credentials::Capability::SYS_CHROOT);
207 CHECK(Credentials::SetCapabilities(proc_fd.get(), caps));
208 PCHECK(chroot("/") == 0);
210 CHECK(Credentials::DropAllCapabilities());
211 PCHECK(chroot("/") == -1 && errno == EPERM);
214 SANDBOX_TEST(Credentials, SetCapabilitiesMatchesLibCap2) {
215 // Probably missing kernel support.
216 if (!Credentials::MoveToNewUserNS())
217 return;
219 base::ScopedFD proc_fd(ProcUtil::OpenProc());
221 std::vector<Credentials::Capability> caps;
222 caps.push_back(Credentials::Capability::SYS_CHROOT);
223 CHECK(Credentials::SetCapabilities(proc_fd.get(), caps));
225 ScopedCap actual_cap(cap_get_proc());
226 PCHECK(actual_cap != nullptr);
228 ScopedCap expected_cap(cap_init());
229 PCHECK(expected_cap != nullptr);
231 const cap_value_t allowed_cap = CAP_SYS_CHROOT;
232 for (const cap_flag_t flag : {CAP_EFFECTIVE, CAP_PERMITTED}) {
233 PCHECK(cap_set_flag(expected_cap.get(), flag, 1, &allowed_cap, CAP_SET) ==
237 CHECK_EQ(0, cap_compare(expected_cap.get(), actual_cap.get()));
240 } // namespace.
242 } // namespace sandbox.