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"
11 #include <sys/types.h>
14 #include "base/files/file_path.h"
15 #include "base/files/file_util.h"
16 #include "base/files/scoped_file.h"
17 #include "base/logging.h"
18 #include "base/memory/scoped_ptr.h"
19 #include "sandbox/linux/tests/unit_tests.h"
20 #include "testing/gtest/include/gtest/gtest.h"
26 bool WorkingDirectoryIsRoot() {
27 char current_dir
[PATH_MAX
];
28 char* cwd
= getcwd(current_dir
, sizeof(current_dir
));
30 if (strcmp("/", cwd
)) return false;
32 // The current directory is the root. Add a few paranoid checks.
34 CHECK_EQ(0, stat(".", ¤t
));
36 CHECK_EQ(0, stat("..", &parrent
));
37 CHECK_EQ(current
.st_dev
, parrent
.st_dev
);
38 CHECK_EQ(current
.st_ino
, parrent
.st_ino
);
39 CHECK_EQ(current
.st_mode
, parrent
.st_mode
);
40 CHECK_EQ(current
.st_uid
, parrent
.st_uid
);
41 CHECK_EQ(current
.st_gid
, parrent
.st_gid
);
45 SANDBOX_TEST(Credentials
, DropAllCaps
) {
46 CHECK(Credentials::DropAllCapabilities());
47 CHECK(!Credentials::HasAnyCapability());
50 SANDBOX_TEST(Credentials
, GetCurrentCapString
) {
51 CHECK(Credentials::DropAllCapabilities());
52 const char kNoCapabilityText
[] = "=";
53 CHECK(*Credentials::GetCurrentCapString() == kNoCapabilityText
);
56 SANDBOX_TEST(Credentials
, MoveToNewUserNS
) {
57 CHECK(Credentials::DropAllCapabilities());
58 bool moved_to_new_ns
= Credentials::MoveToNewUserNS();
60 "Unprivileged CLONE_NEWUSER supported: %s\n",
61 moved_to_new_ns
? "true." : "false.");
63 if (!moved_to_new_ns
) {
64 fprintf(stdout
, "This kernel does not support unprivileged namespaces. "
65 "USERNS tests will succeed without running.\n");
69 CHECK(Credentials::HasAnyCapability());
70 CHECK(Credentials::DropAllCapabilities());
71 CHECK(!Credentials::HasAnyCapability());
74 SANDBOX_TEST(Credentials
, SupportsUserNS
) {
75 CHECK(Credentials::DropAllCapabilities());
76 bool user_ns_supported
= Credentials::SupportsNewUserNS();
77 bool moved_to_new_ns
= Credentials::MoveToNewUserNS();
78 CHECK_EQ(user_ns_supported
, moved_to_new_ns
);
81 SANDBOX_TEST(Credentials
, UidIsPreserved
) {
82 CHECK(Credentials::DropAllCapabilities());
83 uid_t old_ruid
, old_euid
, old_suid
;
84 gid_t old_rgid
, old_egid
, old_sgid
;
85 PCHECK(0 == getresuid(&old_ruid
, &old_euid
, &old_suid
));
86 PCHECK(0 == getresgid(&old_rgid
, &old_egid
, &old_sgid
));
87 // Probably missing kernel support.
88 if (!Credentials::MoveToNewUserNS()) return;
89 uid_t new_ruid
, new_euid
, new_suid
;
90 PCHECK(0 == getresuid(&new_ruid
, &new_euid
, &new_suid
));
91 CHECK(old_ruid
== new_ruid
);
92 CHECK(old_euid
== new_euid
);
93 CHECK(old_suid
== new_suid
);
95 gid_t new_rgid
, new_egid
, new_sgid
;
96 PCHECK(0 == getresgid(&new_rgid
, &new_egid
, &new_sgid
));
97 CHECK(old_rgid
== new_rgid
);
98 CHECK(old_egid
== new_egid
);
99 CHECK(old_sgid
== new_sgid
);
102 bool NewUserNSCycle() {
103 if (!Credentials::MoveToNewUserNS() ||
104 !Credentials::HasAnyCapability() ||
105 !Credentials::DropAllCapabilities() ||
106 Credentials::HasAnyCapability()) {
112 SANDBOX_TEST(Credentials
, NestedUserNS
) {
113 CHECK(Credentials::DropAllCapabilities());
114 // Probably missing kernel support.
115 if (!Credentials::MoveToNewUserNS()) return;
116 CHECK(Credentials::DropAllCapabilities());
117 // As of 3.12, the kernel has a limit of 32. See create_user_ns().
118 const int kNestLevel
= 10;
119 for (int i
= 0; i
< kNestLevel
; ++i
) {
120 CHECK(NewUserNSCycle()) << "Creating new user NS failed at iteration "
125 // Test the WorkingDirectoryIsRoot() helper.
126 TEST(Credentials
, CanDetectRoot
) {
127 ASSERT_EQ(0, chdir("/proc/"));
128 ASSERT_FALSE(WorkingDirectoryIsRoot());
129 ASSERT_EQ(0, chdir("/"));
130 ASSERT_TRUE(WorkingDirectoryIsRoot());
133 SANDBOX_TEST(Credentials
, DISABLE_ON_LSAN(DropFileSystemAccessIsSafe
)) {
134 CHECK(Credentials::DropAllCapabilities());
135 // Probably missing kernel support.
136 if (!Credentials::MoveToNewUserNS()) return;
137 CHECK(Credentials::DropFileSystemAccess());
138 CHECK(!base::DirectoryExists(base::FilePath("/proc")));
139 CHECK(WorkingDirectoryIsRoot());
140 // We want the chroot to never have a subdirectory. A subdirectory
141 // could allow a chroot escape.
142 CHECK_NE(0, mkdir("/test", 0700));
145 // Check that after dropping filesystem access and dropping privileges
146 // it is not possible to regain capabilities.
147 SANDBOX_TEST(Credentials
, DISABLE_ON_LSAN(CannotRegainPrivileges
)) {
148 CHECK(Credentials::DropAllCapabilities());
149 // Probably missing kernel support.
150 if (!Credentials::MoveToNewUserNS()) return;
151 CHECK(Credentials::DropFileSystemAccess());
152 CHECK(Credentials::DropAllCapabilities());
154 // The kernel should now prevent us from regaining capabilities because we
156 CHECK(!Credentials::SupportsNewUserNS());
157 CHECK(!Credentials::MoveToNewUserNS());
162 } // namespace sandbox.