Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(50)

Side by Side Diff: sandbox/linux/services/credentials.cc

Issue 997463002: Add SetCapabilities for setting capabilities to an exact set. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Respond to comments. Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 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 <signal.h> 8 #include <signal.h>
9 #include <stdio.h> 9 #include <stdio.h>
10 #include <sys/capability.h>
11 #include <sys/syscall.h> 10 #include <sys/syscall.h>
12 #include <sys/types.h> 11 #include <sys/types.h>
13 #include <sys/wait.h> 12 #include <sys/wait.h>
14 #include <unistd.h> 13 #include <unistd.h>
15 14
16 #include "base/basictypes.h" 15 #include "base/basictypes.h"
17 #include "base/bind.h" 16 #include "base/bind.h"
18 #include "base/files/file_path.h" 17 #include "base/files/file_path.h"
19 #include "base/files/file_util.h" 18 #include "base/files/file_util.h"
20 #include "base/logging.h" 19 #include "base/logging.h"
21 #include "base/posix/eintr_wrapper.h" 20 #include "base/posix/eintr_wrapper.h"
22 #include "base/process/launch.h" 21 #include "base/process/launch.h"
23 #include "base/template_util.h" 22 #include "base/template_util.h"
24 #include "base/third_party/valgrind/valgrind.h" 23 #include "base/third_party/valgrind/valgrind.h"
25 #include "build/build_config.h" 24 #include "build/build_config.h"
26 #include "sandbox/linux/services/namespace_utils.h" 25 #include "sandbox/linux/services/namespace_utils.h"
27 #include "sandbox/linux/services/proc_util.h" 26 #include "sandbox/linux/services/proc_util.h"
28 #include "sandbox/linux/services/syscall_wrappers.h" 27 #include "sandbox/linux/services/syscall_wrappers.h"
29 #include "sandbox/linux/services/thread_helpers.h" 28 #include "sandbox/linux/services/thread_helpers.h"
29 #include "sandbox/linux/system_headers/capability.h"
30 30
31 namespace sandbox { 31 namespace sandbox {
32 32
33 namespace { 33 namespace {
34 34
35 bool IsRunningOnValgrind() { return RUNNING_ON_VALGRIND; } 35 bool IsRunningOnValgrind() { return RUNNING_ON_VALGRIND; }
36 36
37 struct CapFreeDeleter {
38 inline void operator()(cap_t cap) const {
39 int ret = cap_free(cap);
40 CHECK_EQ(0, ret);
41 }
42 };
43
44 // Wrapper to manage libcap2's cap_t type.
45 typedef scoped_ptr<typeof(*((cap_t)0)), CapFreeDeleter> ScopedCap;
46
47 struct CapTextFreeDeleter {
48 inline void operator()(char* cap_text) const {
49 int ret = cap_free(cap_text);
50 CHECK_EQ(0, ret);
51 }
52 };
53
54 // Wrapper to manage the result from libcap2's cap_from_text().
55 typedef scoped_ptr<char, CapTextFreeDeleter> ScopedCapText;
56
57 // Checks that the set of RES-uids and the set of RES-gids have 37 // Checks that the set of RES-uids and the set of RES-gids have
58 // one element each and return that element in |resuid| and |resgid| 38 // one element each and return that element in |resuid| and |resgid|
59 // respectively. It's ok to pass NULL as one or both of the ids. 39 // respectively. It's ok to pass NULL as one or both of the ids.
60 bool GetRESIds(uid_t* resuid, gid_t* resgid) { 40 bool GetRESIds(uid_t* resuid, gid_t* resgid) {
61 uid_t ruid, euid, suid; 41 uid_t ruid, euid, suid;
62 gid_t rgid, egid, sgid; 42 gid_t rgid, egid, sgid;
63 PCHECK(getresuid(&ruid, &euid, &suid) == 0); 43 PCHECK(getresuid(&ruid, &euid, &suid) == 0);
64 PCHECK(getresgid(&rgid, &egid, &sgid) == 0); 44 PCHECK(getresgid(&rgid, &egid, &sgid) == 0);
65 const bool uids_are_equal = (ruid == euid) && (ruid == suid); 45 const bool uids_are_equal = (ruid == euid) && (ruid == suid);
66 const bool gids_are_equal = (rgid == egid) && (rgid == sgid); 46 const bool gids_are_equal = (rgid == egid) && (rgid == sgid);
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
126 // EPERM can happen if already in a chroot. EUSERS if too many nested 106 // EPERM can happen if already in a chroot. EUSERS if too many nested
127 // namespaces are used. EINVAL for kernels that don't support the feature. 107 // namespaces are used. EINVAL for kernels that don't support the feature.
128 // Valgrind will ENOSYS unshare(). 108 // Valgrind will ENOSYS unshare().
129 PCHECK(error == EPERM || error == EUSERS || error == EINVAL || 109 PCHECK(error == EPERM || error == EUSERS || error == EINVAL ||
130 error == ENOSYS); 110 error == ENOSYS);
131 } 111 }
132 112
133 } // namespace. 113 } // namespace.
134 114
135 bool Credentials::DropAllCapabilities(int proc_fd) { 115 bool Credentials::DropAllCapabilities(int proc_fd) {
136 DCHECK_LE(0, proc_fd); 116 if (!SetCapabilities(proc_fd, std::vector<int>())) {
137 #if !defined(THREAD_SANITIZER) 117 return false;
138 // With TSAN, accept to break the security model as it is a testing 118 }
139 // configuration.
140 CHECK(ThreadHelpers::IsSingleThreaded(proc_fd));
141 #endif
142 119
143 ScopedCap cap(cap_init());
144 CHECK(cap);
145 PCHECK(0 == cap_set_proc(cap.get()));
146 CHECK(!HasAnyCapability()); 120 CHECK(!HasAnyCapability());
147 // We never let this function fail.
148 return true; 121 return true;
149 } 122 }
150 123
151 bool Credentials::DropAllCapabilities() { 124 bool Credentials::DropAllCapabilities() {
152 base::ScopedFD proc_fd(ProcUtil::OpenProc()); 125 base::ScopedFD proc_fd(ProcUtil::OpenProc());
153 return Credentials::DropAllCapabilities(proc_fd.get()); 126 return Credentials::DropAllCapabilities(proc_fd.get());
154 } 127 }
155 128
156 bool Credentials::HasAnyCapability() { 129 // static
157 ScopedCap current_cap(cap_get_proc()); 130 bool Credentials::SetCapabilities(int proc_fd,
158 CHECK(current_cap); 131 const std::vector<int>& caps) {
159 ScopedCap empty_cap(cap_init()); 132 DCHECK_LE(0, proc_fd);
160 CHECK(empty_cap); 133
161 return cap_compare(current_cap.get(), empty_cap.get()) != 0; 134 #if !defined(THREAD_SANITIZER)
135 // With TSAN, accept to break the security model as it is a testing
136 // configuration.
137 CHECK(ThreadHelpers::IsSingleThreaded(proc_fd));
138 #endif
139
140 cap_hdr hdr;
141 hdr.version = _LINUX_CAPABILITY_VERSION_3;
142 cap_data data[_LINUX_CAPABILITY_U32S_3];
jln (very slow on Chromium) 2015/03/12 19:24:15 Even here I would use "struct cap_data", given tha
rickyz (no longer on Chrome) 2015/03/12 23:36:01 Done.
143
144 // Initially, cap has no capability flags set. Enable the effective and
145 // permitted flags only for the requested capabilities.
146 for (const int cap : caps) {
147 DCHECK(cap >= 0 && cap < CAP_LAST_CAP);
148 data[CAP_TO_INDEX(cap)].effective |= CAP_TO_MASK(cap);
149 data[CAP_TO_INDEX(cap)].permitted |= CAP_TO_MASK(cap);
150 }
151
152 return sys_capset(&hdr, data) == 0;
162 } 153 }
163 154
164 scoped_ptr<std::string> Credentials::GetCurrentCapString() { 155 bool Credentials::HasAnyCapability() {
165 ScopedCap current_cap(cap_get_proc()); 156 cap_hdr hdr;
166 CHECK(current_cap); 157 hdr.version = _LINUX_CAPABILITY_VERSION_3;
167 ScopedCapText cap_text(cap_to_text(current_cap.get(), NULL)); 158 cap_data data[_LINUX_CAPABILITY_U32S_3];
168 CHECK(cap_text); 159
169 return scoped_ptr<std::string> (new std::string(cap_text.get())); 160 PCHECK(sys_capget(&hdr, data) == 0);
161
162 for (size_t i = 0; i < arraysize(data); ++i) {
163 if (data[i].effective || data[i].permitted || data[i].inheritable) {
164 return true;
165 }
166 }
167
168 return false;
169 }
170
171 bool Credentials::HasCapability(int cap) {
172 DCHECK(cap >= 0 && cap < CAP_LAST_CAP);
173 cap_hdr hdr;
174 hdr.version = _LINUX_CAPABILITY_VERSION_3;
175 cap_data data[_LINUX_CAPABILITY_U32S_3];
176
177 PCHECK(sys_capget(&hdr, data) == 0);
178
179 const size_t index = CAP_TO_INDEX(cap);
180 const uint32_t mask = CAP_TO_MASK(cap);
181
182 return (data[index].effective | data[index].permitted |
183 data[index].inheritable) &
jln (very slow on Chromium) 2015/03/12 19:24:14 conidering .inheritable doesn't match the document
rickyz (no longer on Chrome) 2015/03/12 23:36:01 Done.
184 mask;
170 } 185 }
171 186
172 // static 187 // static
173 bool Credentials::CanCreateProcessInNewUserNS() { 188 bool Credentials::CanCreateProcessInNewUserNS() {
174 // Valgrind will let clone(2) pass-through, but doesn't support unshare(), 189 // Valgrind will let clone(2) pass-through, but doesn't support unshare(),
175 // so always consider UserNS unsupported there. 190 // so always consider UserNS unsupported there.
176 if (IsRunningOnValgrind()) { 191 if (IsRunningOnValgrind()) {
177 return false; 192 return false;
178 } 193 }
179 194
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
245 CHECK_LE(0, proc_fd); 260 CHECK_LE(0, proc_fd);
246 261
247 CHECK(ChrootToSafeEmptyDir()); 262 CHECK(ChrootToSafeEmptyDir());
248 CHECK(!base::DirectoryExists(base::FilePath("/proc"))); 263 CHECK(!base::DirectoryExists(base::FilePath("/proc")));
249 CHECK(!ProcUtil::HasOpenDirectory(proc_fd)); 264 CHECK(!ProcUtil::HasOpenDirectory(proc_fd));
250 // We never let this function fail. 265 // We never let this function fail.
251 return true; 266 return true;
252 } 267 }
253 268
254 } // namespace sandbox. 269 } // namespace sandbox.
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698