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

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

Issue 182453004: Linux Sandbox: add Credentials::SupportsNewUserNS() (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Save errno. Created 6 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 | Annotate | Revision Log
« no previous file with comments | « sandbox/linux/services/credentials.h ('k') | sandbox/linux/services/credentials_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 <dirent.h> 7 #include <dirent.h>
8 #include <errno.h> 8 #include <errno.h>
9 #include <fcntl.h> 9 #include <fcntl.h>
10 #include <signal.h>
10 #include <stdio.h> 11 #include <stdio.h>
11 #include <sys/capability.h> 12 #include <sys/capability.h>
12 #include <sys/stat.h> 13 #include <sys/stat.h>
14 #include <sys/syscall.h>
13 #include <sys/types.h> 15 #include <sys/types.h>
16 #include <sys/wait.h>
14 #include <unistd.h> 17 #include <unistd.h>
15 18
16 #include "base/basictypes.h" 19 #include "base/basictypes.h"
17 #include "base/bind.h" 20 #include "base/bind.h"
18 #include "base/logging.h" 21 #include "base/logging.h"
22 #include "base/posix/eintr_wrapper.h"
19 #include "base/strings/string_number_conversions.h" 23 #include "base/strings/string_number_conversions.h"
20 #include "base/template_util.h" 24 #include "base/template_util.h"
25 #include "base/third_party/valgrind/valgrind.h"
21 #include "base/threading/thread.h" 26 #include "base/threading/thread.h"
22 27
23 namespace { 28 namespace {
24 29
30 bool IsRunningOnValgrind() { return RUNNING_ON_VALGRIND; }
31
25 struct CapFreeDeleter { 32 struct CapFreeDeleter {
26 inline void operator()(cap_t cap) const { 33 inline void operator()(cap_t cap) const {
27 int ret = cap_free(cap); 34 int ret = cap_free(cap);
28 CHECK_EQ(0, ret); 35 CHECK_EQ(0, ret);
29 } 36 }
30 }; 37 };
31 38
32 // Wrapper to manage libcap2's cap_t type. 39 // Wrapper to manage libcap2's cap_t type.
33 typedef scoped_ptr<typeof(*((cap_t)0)), CapFreeDeleter> ScopedCap; 40 typedef scoped_ptr<typeof(*((cap_t)0)), CapFreeDeleter> ScopedCap;
34 41
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
139 base::Thread chrooter("sandbox_chrooter"); 146 base::Thread chrooter("sandbox_chrooter");
140 if (!chrooter.Start()) return false; 147 if (!chrooter.Start()) return false;
141 bool is_chrooted = false; 148 bool is_chrooted = false;
142 chrooter.message_loop()->PostTask(FROM_HERE, 149 chrooter.message_loop()->PostTask(FROM_HERE,
143 base::Bind(&ChrootToThreadFdInfo, chrooter.thread_id(), &is_chrooted)); 150 base::Bind(&ChrootToThreadFdInfo, chrooter.thread_id(), &is_chrooted));
144 // Make sure our task has run before committing the return value. 151 // Make sure our task has run before committing the return value.
145 chrooter.Stop(); 152 chrooter.Stop();
146 return is_chrooted; 153 return is_chrooted;
147 } 154 }
148 155
156 // CHECK() that an attempt to move to a new user namespace raised an expected
157 // errno.
158 void CheckCloneNewUserErrno(int error) {
159 // EPERM can happen if already in a chroot. EUSERS if too many nested
160 // namespaces are used. EINVAL for kernels that don't support the feature.
161 // Valgrind will ENOSYS unshare().
162 PCHECK(error == EPERM || error == EUSERS || error == EINVAL ||
163 error == ENOSYS);
164 }
165
149 } // namespace. 166 } // namespace.
150 167
151 namespace sandbox { 168 namespace sandbox {
152 169
153 Credentials::Credentials() { 170 Credentials::Credentials() {
154 } 171 }
155 172
156 Credentials::~Credentials() { 173 Credentials::~Credentials() {
157 } 174 }
158 175
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
224 } 241 }
225 242
226 scoped_ptr<std::string> Credentials::GetCurrentCapString() const { 243 scoped_ptr<std::string> Credentials::GetCurrentCapString() const {
227 ScopedCap current_cap(cap_get_proc()); 244 ScopedCap current_cap(cap_get_proc());
228 CHECK(current_cap); 245 CHECK(current_cap);
229 ScopedCapText cap_text(cap_to_text(current_cap.get(), NULL)); 246 ScopedCapText cap_text(cap_to_text(current_cap.get(), NULL));
230 CHECK(cap_text); 247 CHECK(cap_text);
231 return scoped_ptr<std::string> (new std::string(cap_text.get())); 248 return scoped_ptr<std::string> (new std::string(cap_text.get()));
232 } 249 }
233 250
251 // static
252 bool Credentials::SupportsNewUserNS() {
253 // Valgrind will let clone(2) pass-through, but doesn't support unshare(),
254 // so always consider UserNS unsupported there.
255 if (IsRunningOnValgrind()) {
256 return false;
257 }
258
259 // This is roughly a fork().
260 const pid_t pid = syscall(__NR_clone, CLONE_NEWUSER | SIGCHLD, 0, 0, 0);
261
262 if (pid == -1) {
263 CheckCloneNewUserErrno(errno);
264 return false;
265 }
266
267 // The parent process could have had threads. In the child, these threads
268 // have disappeared. Make sure to not do anything in the child, as this is a
269 // fragile execution environment.
270 if (pid == 0) {
271 _exit(0);
272 }
273
274 // Always reap the child.
275 siginfo_t infop;
276 PCHECK(0 == HANDLE_EINTR(waitid(P_PID, pid, &infop, WEXITED)));
277
278 // clone(2) succeeded, we can use CLONE_NEWUSER.
279 return true;
280 }
281
234 bool Credentials::MoveToNewUserNS() { 282 bool Credentials::MoveToNewUserNS() {
235 uid_t uid; 283 uid_t uid;
236 gid_t gid; 284 gid_t gid;
237 if (!GetRESIds(&uid, &gid)) { 285 if (!GetRESIds(&uid, &gid)) {
238 // If all the uids (or gids) are not equal to each other, the security 286 // If all the uids (or gids) are not equal to each other, the security
239 // model will most likely confuse the caller, abort. 287 // model will most likely confuse the caller, abort.
240 DVLOG(1) << "uids or gids differ!"; 288 DVLOG(1) << "uids or gids differ!";
241 return false; 289 return false;
242 } 290 }
243 int ret = unshare(CLONE_NEWUSER); 291 int ret = unshare(CLONE_NEWUSER);
244 // EPERM can happen if already in a chroot. EUSERS if too many nested
245 // namespaces are used. EINVAL for kernels that don't support the feature.
246 // Valgrind will ENOSYS unshare().
247 PCHECK(!ret || errno == EPERM || errno == EUSERS || errno == EINVAL ||
248 errno == ENOSYS);
249 if (ret) { 292 if (ret) {
293 const int unshare_errno = errno;
250 VLOG(1) << "Looks like unprivileged CLONE_NEWUSER may not be available " 294 VLOG(1) << "Looks like unprivileged CLONE_NEWUSER may not be available "
251 << "on this kernel."; 295 << "on this kernel.";
296 CheckCloneNewUserErrno(unshare_errno);
252 return false; 297 return false;
253 } 298 }
299
254 // The current {r,e,s}{u,g}id is now an overflow id (c.f. 300 // The current {r,e,s}{u,g}id is now an overflow id (c.f.
255 // /proc/sys/kernel/overflowuid). Setup the uid and gid maps. 301 // /proc/sys/kernel/overflowuid). Setup the uid and gid maps.
256 DCHECK(GetRESIds(NULL, NULL)); 302 DCHECK(GetRESIds(NULL, NULL));
257 const char kGidMapFile[] = "/proc/self/gid_map"; 303 const char kGidMapFile[] = "/proc/self/gid_map";
258 const char kUidMapFile[] = "/proc/self/uid_map"; 304 const char kUidMapFile[] = "/proc/self/uid_map";
259 CHECK(WriteToIdMapFile(kGidMapFile, gid)); 305 CHECK(WriteToIdMapFile(kGidMapFile, gid));
260 CHECK(WriteToIdMapFile(kUidMapFile, uid)); 306 CHECK(WriteToIdMapFile(kUidMapFile, uid));
261 DCHECK(GetRESIds(NULL, NULL)); 307 DCHECK(GetRESIds(NULL, NULL));
262 return true; 308 return true;
263 } 309 }
264 310
265 bool Credentials::DropFileSystemAccess() { 311 bool Credentials::DropFileSystemAccess() {
266 // Chrooting to a safe empty dir will only be safe if no directory file 312 // Chrooting to a safe empty dir will only be safe if no directory file
267 // descriptor is available to the process. 313 // descriptor is available to the process.
268 DCHECK(!HasOpenDirectory(-1)); 314 DCHECK(!HasOpenDirectory(-1));
269 return ChrootToSafeEmptyDir(); 315 return ChrootToSafeEmptyDir();
270 } 316 }
271 317
272 } // namespace sandbox. 318 } // namespace sandbox.
OLDNEW
« no previous file with comments | « sandbox/linux/services/credentials.h ('k') | sandbox/linux/services/credentials_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698