OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "sandbox/linux/services/credentials.h" | 5 #include "sandbox/linux/services/credentials.h" |
6 | 6 |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <fcntl.h> | 8 #include <fcntl.h> |
9 #include <stdio.h> | 9 #include <stdio.h> |
10 #include <sys/capability.h> | |
10 #include <sys/stat.h> | 11 #include <sys/stat.h> |
11 #include <sys/types.h> | 12 #include <sys/types.h> |
12 #include <unistd.h> | 13 #include <unistd.h> |
13 | 14 |
15 #include <vector> | |
16 | |
14 #include "base/files/file_path.h" | 17 #include "base/files/file_path.h" |
15 #include "base/files/file_util.h" | 18 #include "base/files/file_util.h" |
16 #include "base/files/scoped_file.h" | 19 #include "base/files/scoped_file.h" |
17 #include "base/logging.h" | 20 #include "base/logging.h" |
18 #include "base/memory/scoped_ptr.h" | 21 #include "base/memory/scoped_ptr.h" |
19 #include "sandbox/linux/services/proc_util.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" | |
20 #include "sandbox/linux/tests/unit_tests.h" | 25 #include "sandbox/linux/tests/unit_tests.h" |
21 #include "testing/gtest/include/gtest/gtest.h" | 26 #include "testing/gtest/include/gtest/gtest.h" |
22 | 27 |
23 namespace sandbox { | 28 namespace sandbox { |
24 | 29 |
25 namespace { | 30 namespace { |
26 | 31 |
32 struct CapFreeDeleter { | |
33 inline void operator()(cap_t cap) const { | |
34 int ret = cap_free(cap); | |
35 CHECK_EQ(0, ret); | |
36 } | |
37 }; | |
38 | |
39 // Wrapper to manage libcap2's cap_t type. | |
40 typedef scoped_ptr<typeof(*((cap_t)0)), CapFreeDeleter> ScopedCap; | |
41 | |
27 bool WorkingDirectoryIsRoot() { | 42 bool WorkingDirectoryIsRoot() { |
28 char current_dir[PATH_MAX]; | 43 char current_dir[PATH_MAX]; |
29 char* cwd = getcwd(current_dir, sizeof(current_dir)); | 44 char* cwd = getcwd(current_dir, sizeof(current_dir)); |
30 PCHECK(cwd); | 45 PCHECK(cwd); |
31 if (strcmp("/", cwd)) return false; | 46 if (strcmp("/", cwd)) return false; |
32 | 47 |
33 // The current directory is the root. Add a few paranoid checks. | 48 // The current directory is the root. Add a few paranoid checks. |
34 struct stat current; | 49 struct stat current; |
35 CHECK_EQ(0, stat(".", ¤t)); | 50 CHECK_EQ(0, stat(".", ¤t)); |
36 struct stat parrent; | 51 struct stat parrent; |
37 CHECK_EQ(0, stat("..", &parrent)); | 52 CHECK_EQ(0, stat("..", &parrent)); |
38 CHECK_EQ(current.st_dev, parrent.st_dev); | 53 CHECK_EQ(current.st_dev, parrent.st_dev); |
39 CHECK_EQ(current.st_ino, parrent.st_ino); | 54 CHECK_EQ(current.st_ino, parrent.st_ino); |
40 CHECK_EQ(current.st_mode, parrent.st_mode); | 55 CHECK_EQ(current.st_mode, parrent.st_mode); |
41 CHECK_EQ(current.st_uid, parrent.st_uid); | 56 CHECK_EQ(current.st_uid, parrent.st_uid); |
42 CHECK_EQ(current.st_gid, parrent.st_gid); | 57 CHECK_EQ(current.st_gid, parrent.st_gid); |
43 return true; | 58 return true; |
44 } | 59 } |
45 | 60 |
46 SANDBOX_TEST(Credentials, DropAllCaps) { | 61 SANDBOX_TEST(Credentials, DropAllCaps) { |
47 CHECK(Credentials::DropAllCapabilities()); | 62 CHECK(Credentials::DropAllCapabilities()); |
48 CHECK(!Credentials::HasAnyCapability()); | 63 CHECK(!Credentials::HasAnyCapability()); |
49 } | 64 } |
50 | 65 |
51 SANDBOX_TEST(Credentials, GetCurrentCapString) { | |
52 CHECK(Credentials::DropAllCapabilities()); | |
53 const char kNoCapabilityText[] = "="; | |
54 CHECK(*Credentials::GetCurrentCapString() == kNoCapabilityText); | |
55 } | |
56 | |
57 SANDBOX_TEST(Credentials, MoveToNewUserNS) { | 66 SANDBOX_TEST(Credentials, MoveToNewUserNS) { |
58 CHECK(Credentials::DropAllCapabilities()); | 67 CHECK(Credentials::DropAllCapabilities()); |
59 bool moved_to_new_ns = Credentials::MoveToNewUserNS(); | 68 bool moved_to_new_ns = Credentials::MoveToNewUserNS(); |
60 fprintf(stdout, | 69 fprintf(stdout, |
61 "Unprivileged CLONE_NEWUSER supported: %s\n", | 70 "Unprivileged CLONE_NEWUSER supported: %s\n", |
62 moved_to_new_ns ? "true." : "false."); | 71 moved_to_new_ns ? "true." : "false."); |
63 fflush(stdout); | 72 fflush(stdout); |
64 if (!moved_to_new_ns) { | 73 if (!moved_to_new_ns) { |
65 fprintf(stdout, "This kernel does not support unprivileged namespaces. " | 74 fprintf(stdout, "This kernel does not support unprivileged namespaces. " |
66 "USERNS tests will succeed without running.\n"); | 75 "USERNS tests will succeed without running.\n"); |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
154 if (!Credentials::MoveToNewUserNS()) return; | 163 if (!Credentials::MoveToNewUserNS()) return; |
155 CHECK(Credentials::DropFileSystemAccess(proc_fd.get())); | 164 CHECK(Credentials::DropFileSystemAccess(proc_fd.get())); |
156 CHECK(Credentials::DropAllCapabilities(proc_fd.get())); | 165 CHECK(Credentials::DropAllCapabilities(proc_fd.get())); |
157 | 166 |
158 // The kernel should now prevent us from regaining capabilities because we | 167 // The kernel should now prevent us from regaining capabilities because we |
159 // are in a chroot. | 168 // are in a chroot. |
160 CHECK(!Credentials::CanCreateProcessInNewUserNS()); | 169 CHECK(!Credentials::CanCreateProcessInNewUserNS()); |
161 CHECK(!Credentials::MoveToNewUserNS()); | 170 CHECK(!Credentials::MoveToNewUserNS()); |
162 } | 171 } |
163 | 172 |
173 SANDBOX_TEST(Credentials, SetCapabilities) { | |
174 // Probably missing kernel support. | |
175 if (!Credentials::MoveToNewUserNS()) | |
176 return; | |
177 | |
178 base::ScopedFD proc_fd(ProcUtil::OpenProc()); | |
179 | |
180 CHECK(Credentials::HasCapability(LinuxCapability::kCapSysAdmin)); | |
181 CHECK(Credentials::HasCapability(LinuxCapability::kCapSysChroot)); | |
182 | |
183 const std::vector<LinuxCapability> caps = {LinuxCapability::kCapSysChroot}; | |
184 CHECK(Credentials::SetCapabilities(proc_fd.get(), caps)); | |
185 | |
186 CHECK(!Credentials::HasCapability(LinuxCapability::kCapSysAdmin)); | |
187 CHECK(Credentials::HasCapability(LinuxCapability::kCapSysChroot)); | |
188 | |
189 const std::vector<LinuxCapability> no_caps; | |
190 CHECK(Credentials::SetCapabilities(proc_fd.get(), no_caps)); | |
191 CHECK(!Credentials::HasAnyCapability()); | |
192 } | |
193 | |
194 SANDBOX_TEST(Credentials, SetCapabilitiesAndChroot) { | |
jln (very slow on Chromium)
2015/03/16 21:38:10
Might need DISABLE_ON_ASAN as above, no?
rickyz (no longer on Chrome)
2015/03/16 23:10:12
I don't think it's needed in this case since I onl
| |
195 // Probably missing kernel support. | |
196 if (!Credentials::MoveToNewUserNS()) | |
197 return; | |
198 | |
199 base::ScopedFD proc_fd(ProcUtil::OpenProc()); | |
200 | |
201 CHECK(Credentials::HasCapability(LinuxCapability::kCapSysChroot)); | |
202 PCHECK(chroot("/") == 0); | |
203 | |
204 const std::vector<LinuxCapability> caps = {LinuxCapability::kCapSysChroot}; | |
205 CHECK(Credentials::SetCapabilities(proc_fd.get(), caps)); | |
206 PCHECK(chroot("/") == 0); | |
207 | |
208 CHECK(Credentials::DropAllCapabilities()); | |
209 PCHECK(chroot("/") == -1 && errno == EPERM); | |
210 } | |
211 | |
212 SANDBOX_TEST(Credentials, SetCapabilitiesMatchesLibCap2) { | |
213 // Probably missing kernel support. | |
214 if (!Credentials::MoveToNewUserNS()) | |
215 return; | |
216 | |
217 static_assert( | |
218 static_cast<int>(LinuxCapability::kCapSysChroot) == CAP_SYS_CHROOT, | |
jln (very slow on Chromium)
2015/03/16 21:38:10
I possible, I would rather have LinuxCapability va
rickyz (no longer on Chrome)
2015/03/16 23:10:12
Done.
| |
219 "CAP_SYS_CHROOT values do not match."); | |
220 static_assert( | |
221 static_cast<int>(LinuxCapability::kCapSysAdmin) == CAP_SYS_ADMIN, | |
222 "CAP_SYS_ADMIN values do not match."); | |
223 | |
224 base::ScopedFD proc_fd(ProcUtil::OpenProc()); | |
225 | |
226 const std::vector<LinuxCapability> caps = {LinuxCapability::kCapSysChroot}; | |
227 CHECK(Credentials::SetCapabilities(proc_fd.get(), caps)); | |
228 | |
229 ScopedCap actual_cap(cap_get_proc()); | |
230 PCHECK(actual_cap != nullptr); | |
231 | |
232 ScopedCap expected_cap(cap_init()); | |
233 PCHECK(expected_cap != nullptr); | |
234 | |
235 const cap_value_t allowed_cap = CAP_SYS_CHROOT; | |
236 for (const cap_flag_t flag : {CAP_EFFECTIVE, CAP_PERMITTED}) { | |
237 PCHECK(cap_set_flag(expected_cap.get(), flag, 1, &allowed_cap, CAP_SET) == | |
238 0); | |
239 } | |
240 | |
241 CHECK_EQ(0, cap_compare(expected_cap.get(), actual_cap.get())); | |
242 } | |
243 | |
164 } // namespace. | 244 } // namespace. |
165 | 245 |
166 } // namespace sandbox. | 246 } // namespace sandbox. |
OLD | NEW |