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

Unified 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, 10 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « sandbox/linux/services/credentials.h ('k') | sandbox/linux/services/credentials_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sandbox/linux/services/credentials.cc
diff --git a/sandbox/linux/services/credentials.cc b/sandbox/linux/services/credentials.cc
index 4f041dc2887b681fb20538b07beeb52627af48a2..21214c3a2fe14c811ae9c6be410bcd3866480198 100644
--- a/sandbox/linux/services/credentials.cc
+++ b/sandbox/linux/services/credentials.cc
@@ -7,21 +7,28 @@
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
+#include <signal.h>
#include <stdio.h>
#include <sys/capability.h>
#include <sys/stat.h>
+#include <sys/syscall.h>
#include <sys/types.h>
+#include <sys/wait.h>
#include <unistd.h>
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
#include "base/strings/string_number_conversions.h"
#include "base/template_util.h"
+#include "base/third_party/valgrind/valgrind.h"
#include "base/threading/thread.h"
namespace {
+bool IsRunningOnValgrind() { return RUNNING_ON_VALGRIND; }
+
struct CapFreeDeleter {
inline void operator()(cap_t cap) const {
int ret = cap_free(cap);
@@ -146,6 +153,16 @@ bool ChrootToSafeEmptyDir() {
return is_chrooted;
}
+// CHECK() that an attempt to move to a new user namespace raised an expected
+// errno.
+void CheckCloneNewUserErrno(int error) {
+ // EPERM can happen if already in a chroot. EUSERS if too many nested
+ // namespaces are used. EINVAL for kernels that don't support the feature.
+ // Valgrind will ENOSYS unshare().
+ PCHECK(error == EPERM || error == EUSERS || error == EINVAL ||
+ error == ENOSYS);
+}
+
} // namespace.
namespace sandbox {
@@ -231,6 +248,37 @@ scoped_ptr<std::string> Credentials::GetCurrentCapString() const {
return scoped_ptr<std::string> (new std::string(cap_text.get()));
}
+// static
+bool Credentials::SupportsNewUserNS() {
+ // Valgrind will let clone(2) pass-through, but doesn't support unshare(),
+ // so always consider UserNS unsupported there.
+ if (IsRunningOnValgrind()) {
+ return false;
+ }
+
+ // This is roughly a fork().
+ const pid_t pid = syscall(__NR_clone, CLONE_NEWUSER | SIGCHLD, 0, 0, 0);
+
+ if (pid == -1) {
+ CheckCloneNewUserErrno(errno);
+ return false;
+ }
+
+ // The parent process could have had threads. In the child, these threads
+ // have disappeared. Make sure to not do anything in the child, as this is a
+ // fragile execution environment.
+ if (pid == 0) {
+ _exit(0);
+ }
+
+ // Always reap the child.
+ siginfo_t infop;
+ PCHECK(0 == HANDLE_EINTR(waitid(P_PID, pid, &infop, WEXITED)));
+
+ // clone(2) succeeded, we can use CLONE_NEWUSER.
+ return true;
+}
+
bool Credentials::MoveToNewUserNS() {
uid_t uid;
gid_t gid;
@@ -241,16 +289,14 @@ bool Credentials::MoveToNewUserNS() {
return false;
}
int ret = unshare(CLONE_NEWUSER);
- // EPERM can happen if already in a chroot. EUSERS if too many nested
- // namespaces are used. EINVAL for kernels that don't support the feature.
- // Valgrind will ENOSYS unshare().
- PCHECK(!ret || errno == EPERM || errno == EUSERS || errno == EINVAL ||
- errno == ENOSYS);
if (ret) {
+ const int unshare_errno = errno;
VLOG(1) << "Looks like unprivileged CLONE_NEWUSER may not be available "
<< "on this kernel.";
+ CheckCloneNewUserErrno(unshare_errno);
return false;
}
+
// The current {r,e,s}{u,g}id is now an overflow id (c.f.
// /proc/sys/kernel/overflowuid). Setup the uid and gid maps.
DCHECK(GetRESIds(NULL, NULL));
« 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