summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/app/generated_resources.grd21
-rw-r--r--chrome/browser/browser_about_handler.cc67
-rw-r--r--chrome/browser/zygote_host_linux.cc30
-rw-r--r--chrome/browser/zygote_host_linux.h22
-rw-r--r--chrome/browser/zygote_main_linux.cc29
-rw-r--r--sandbox/linux/suid/sandbox.c15
6 files changed, 179 insertions, 5 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 08756be..716c289 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -8682,6 +8682,27 @@ Keep your key file in a safe place. You will need it to create new versions of y
&lt;p&gt;But you can still configure via the command line. Please see &lt;code&gt;man <ph name="PRODUCT_BINARY_NAME">$2<ex>google-chrome</ex></ph>&lt;/code&gt; for more information on flags and environment variables.&lt;/p&gt;
</message>
+ <message name="IDS_ABOUT_SANDBOX_TITLE" desc="Title of HTML page which contains the status of the sandbox.">
+ Sandbox Status
+ </message>
+ <message name="IDS_ABOUT_SANDBOX_SUID_SANDBOX" desc="The name of a type of sandbox used by Chrome on UNIX like systems. The name 'SUID' stands for 'Set User ID', however it's a technical term and may be best left untranslated.">
+ SUID Sandbox
+ </message>
+ <message name="IDS_ABOUT_SANDBOX_PID_NAMESPACES" desc="This a technical term for an attribute of the SUID sandbox. PID stands for 'Process ID' but, as a technical term, may be best left untranslated. A namespace is another technical term which refers to set of names for objects which are disjoint from the members of all other namespaces.">
+ PID namespaces
+ </message>
+ <message name="IDS_ABOUT_SANDBOX_NET_NAMESPACES" desc="This a technical term for an attribute of the SUID sandbox. A namespace is a technical term which refers to set of names for objects which are disjoint from the members of all other namespaces.">
+ Network namespaces
+ </message>
+ <message name="IDS_ABOUT_SANDBOX_SECCOMP_SANDBOX" desc="The name of a type of sandbox used by Chrome on UNIX like systems. 'Seccomp' is a technical term which should be left untranslated.">
+ Seccomp sandbox
+ </message>
+ <message name="IDS_ABOUT_SANDBOX_OK" desc="A message telling the user that their sandbox is sufficient.">
+ You are adequately sandboxed.
+ </message>
+ <message name="IDS_ABOUT_SANDBOX_BAD" desc="A message telling the user that their sandbox is insufficient.">
+ You are not adequately sandboxed!
+ </message>
</if>
</messages>
diff --git a/chrome/browser/browser_about_handler.cc b/chrome/browser/browser_about_handler.cc
index 888f2914..62df49d 100644
--- a/chrome/browser/browser_about_handler.cc
+++ b/chrome/browser/browser_about_handler.cc
@@ -63,6 +63,8 @@
#include "chrome/browser/chromeos/version_loader.h"
#elif defined(OS_MACOSX)
#include "chrome/browser/cocoa/about_ipc_dialog.h"
+#elif defined(OS_LINUX)
+#include "chrome/browser/zygote_host_linux.h"
#endif
#if defined(USE_TCMALLOC)
@@ -103,6 +105,7 @@ const char kPluginsPath[] = "plugins";
#if defined(OS_LINUX)
const char kLinuxProxyConfigPath[] = "linux-proxy-config";
+const char kSandboxPath[] = "sandbox";
#endif
#if defined(OS_CHROMEOS)
@@ -128,6 +131,7 @@ const char *kAllAboutPaths[] = {
kVersionPath,
#if defined(OS_LINUX)
kLinuxProxyConfigPath,
+ kSandboxPath,
#endif
#if defined(OS_CHROMEOS)
kNetworkPath,
@@ -527,6 +531,67 @@ std::string AboutLinuxProxyConfig() {
data.append("</body></html>\n");
return data;
}
+
+void AboutSandboxRow(std::string* data, const std::string& prefix, int name_id,
+ bool good) {
+ data->append("<tr><td>");
+ data->append(prefix);
+ data->append(l10n_util::GetStringUTF8(name_id));
+ if (good) {
+ data->append("</td><td style=\"color: green;\">");
+ data->append(
+ l10n_util::GetStringUTF8(IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL));
+ } else {
+ data->append("</td><td style=\"color: red;\">");
+ data->append(
+ l10n_util::GetStringUTF8(IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL));
+ }
+ data->append("</td></tr>");
+}
+
+std::string AboutSandbox() {
+ std::string data;
+ data.append("<!DOCTYPE HTML>\n");
+ data.append("<html><head><meta charset=\"utf-8\"><title>");
+ data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_TITLE));
+ data.append("</title>");
+ data.append("</head><body>\n");
+ data.append("<h1>");
+ data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_TITLE));
+ data.append("</h1>");
+
+ const int status = Singleton<ZygoteHost>()->sandbox_status();
+
+ data.append("<table>");
+
+ AboutSandboxRow(&data, "", IDS_ABOUT_SANDBOX_SUID_SANDBOX,
+ status & ZygoteHost::kSandboxSUID);
+ if (status & ZygoteHost::kSandboxPIDNS) {
+ AboutSandboxRow(&data, "&nbsp;&nbsp;", IDS_ABOUT_SANDBOX_PID_NAMESPACES,
+ status & ZygoteHost::kSandboxPIDNS);
+ AboutSandboxRow(&data, "&nbsp;&nbsp;", IDS_ABOUT_SANDBOX_NET_NAMESPACES,
+ status & ZygoteHost::kSandboxNetNS);
+ }
+ AboutSandboxRow(&data, "", IDS_ABOUT_SANDBOX_SECCOMP_SANDBOX,
+ status & ZygoteHost::kSandboxSeccomp);
+
+ data.append("</table>");
+
+ bool good = ((status & ZygoteHost::kSandboxSUID) &&
+ (status & ZygoteHost::kSandboxPIDNS)) ||
+ (status & ZygoteHost::kSandboxSeccomp);
+ if (good) {
+ data.append("<p style=\"color: green\">");
+ data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_OK));
+ } else {
+ data.append("<p style=\"color: red\">");
+ data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_BAD));
+ }
+ data.append("</p>");
+
+ data.append("</body></html>\n");
+ return data;
+}
#endif
std::string AboutVersion(DictionaryValue* localized_strings) {
@@ -816,6 +881,8 @@ void AboutSource::StartDataRequest(const std::string& path_raw,
#if defined(OS_LINUX)
} else if (path == kLinuxProxyConfigPath) {
response = AboutLinuxProxyConfig();
+ } else if (path == kSandboxPath) {
+ response = AboutSandbox();
#endif
} else if (path == kSyncPath) {
response = AboutSync();
diff --git a/chrome/browser/zygote_host_linux.cc b/chrome/browser/zygote_host_linux.cc
index de8590d..9423598 100644
--- a/chrome/browser/zygote_host_linux.cc
+++ b/chrome/browser/zygote_host_linux.cc
@@ -50,7 +50,8 @@ static void SaveSUIDUnsafeEnvironmentVariables() {
ZygoteHost::ZygoteHost()
: pid_(-1),
init_(false),
- using_suid_sandbox_(false) {
+ using_suid_sandbox_(false),
+ have_read_sandbox_status_word_(false) {
}
ZygoteHost::~ZygoteHost() {
@@ -188,6 +189,29 @@ void ZygoteHost::Init(const std::string& sandbox_cmd) {
close(fds[1]);
control_fd_ = fds[0];
+
+ Pickle pickle;
+ pickle.WriteInt(kCmdGetSandboxStatus);
+ std::vector<int> empty_fds;
+ if (!base::SendMsg(control_fd_, pickle.data(), pickle.size(), empty_fds))
+ LOG(FATAL) << "Cannot communicate with zygote";
+ // We don't wait for the reply. We'll read it in ReadReply.
+}
+
+ssize_t ZygoteHost::ReadReply(void* buf, size_t buf_len) {
+ // At startup we send a kCmdGetSandboxStatus request to the zygote, but don't
+ // wait for the reply. Thus, the first time that we read from the zygote, we
+ // get the reply to that request.
+ if (!have_read_sandbox_status_word_) {
+ if (HANDLE_EINTR(read(control_fd_, &sandbox_status_,
+ sizeof(sandbox_status_))) !=
+ sizeof(sandbox_status_)) {
+ return -1;
+ }
+ have_read_sandbox_status_word_ = true;
+ }
+
+ return HANDLE_EINTR(read(control_fd_, buf, buf_len));
}
pid_t ZygoteHost::ForkRenderer(
@@ -217,7 +241,7 @@ pid_t ZygoteHost::ForkRenderer(
if (!base::SendMsg(control_fd_, pickle.data(), pickle.size(), fds))
return base::kNullProcessHandle;
- if (HANDLE_EINTR(read(control_fd_, &pid, sizeof(pid))) != sizeof(pid))
+ if (ReadReply(&pid, sizeof(pid)) != sizeof(pid))
return base::kNullProcessHandle;
}
@@ -302,7 +326,7 @@ bool ZygoteHost::DidProcessCrash(base::ProcessHandle handle,
if (HANDLE_EINTR(write(control_fd_, pickle.data(), pickle.size())) < 0)
PLOG(ERROR) << "write";
- len = HANDLE_EINTR(read(control_fd_, buf, sizeof(buf)));
+ len = ReadReply(buf, sizeof(buf));
}
if (len == -1) {
diff --git a/chrome/browser/zygote_host_linux.h b/chrome/browser/zygote_host_linux.h
index 580770a..545df8d 100644
--- a/chrome/browser/zygote_host_linux.h
+++ b/chrome/browser/zygote_host_linux.h
@@ -44,15 +44,35 @@ class ZygoteHost {
kCmdFork = 0, // Fork off a new renderer.
kCmdReap = 1, // Reap a renderer child.
kCmdDidProcessCrash = 2, // Check if child process crashed.
+ kCmdGetSandboxStatus = 3, // Read a bitmask of kSandbox*
+ };
+
+ // These form a bitmask which describes the conditions of the sandbox that
+ // the zygote finds itself in.
+ enum {
+ kSandboxSUID = 1 << 0, // SUID sandbox active
+ kSandboxPIDNS = 1 << 1, // SUID sandbox is using the PID namespace
+ kSandboxNetNS = 1 << 2, // SUID sandbox is using the network namespace
+ kSandboxSeccomp = 1 << 3, // seccomp sandbox active.
};
pid_t pid() const { return pid_; }
+ // Returns an int which is a bitmask of kSandbox* values. Only valid after
+ // the first render has been forked.
+ int sandbox_status() const {
+ if (have_read_sandbox_status_word_)
+ return sandbox_status_;
+ return 0;
+ }
+
private:
friend struct DefaultSingletonTraits<ZygoteHost>;
ZygoteHost();
~ZygoteHost();
+ ssize_t ReadReply(void* buf, size_t buflen);
+
int control_fd_; // the socket to the zygote
// A lock protecting all communication with the zygote. This lock must be
// acquired before sending a command and released after the result has been
@@ -62,6 +82,8 @@ class ZygoteHost {
bool init_;
bool using_suid_sandbox_;
std::string sandbox_binary_;
+ bool have_read_sandbox_status_word_;
+ int sandbox_status_;
};
#endif // CHROME_BROWSER_ZYGOTE_HOST_LINUX_H_
diff --git a/chrome/browser/zygote_main_linux.cc b/chrome/browser/zygote_main_linux.cc
index 1dbbbf5..5717390 100644
--- a/chrome/browser/zygote_main_linux.cc
+++ b/chrome/browser/zygote_main_linux.cc
@@ -93,6 +93,10 @@ static void SELinuxTransitionToTypeOrDie(const char* type) {
// runs it.
class Zygote {
public:
+ explicit Zygote(int sandbox_flags)
+ : sandbox_flags_(sandbox_flags) {
+ }
+
bool ProcessRequests() {
// A SOCK_SEQPACKET socket is installed in fd 3. We get commands from the
// browser on it.
@@ -166,6 +170,9 @@ class Zygote {
break;
HandleDidProcessCrash(fd, pickle, iter);
return false;
+ case ZygoteHost::kCmdGetSandboxStatus:
+ HandleGetSandboxStatus(fd, pickle, iter);
+ return false;
default:
NOTREACHED();
break;
@@ -351,11 +358,22 @@ class Zygote {
return false;
}
+ bool HandleGetSandboxStatus(int fd, const Pickle& pickle, void* iter) {
+ if (HANDLE_EINTR(write(fd, &sandbox_flags_, sizeof(sandbox_flags_)) !=
+ sizeof(sandbox_flags_))) {
+ PLOG(ERROR) << "write";
+ }
+
+ return false;
+ }
+
// In the SUID sandbox, we try to use a new PID namespace. Thus the PIDs
// fork() returns are not the real PIDs, so we need to map the Real PIDS
// into the sandbox PID namespace.
typedef base::hash_map<base::ProcessHandle, base::ProcessHandle> ProcessMap;
ProcessMap real_pids_to_sandbox_pids;
+
+ const int sandbox_flags_;
};
// With SELinux we can carve out a precise sandbox, so we don't have to play
@@ -655,6 +673,14 @@ bool ZygoteMain(const MainFunctionParams& params) {
return false;
}
+ int sandbox_flags = 0;
+ if (getenv("SBX_D"))
+ sandbox_flags |= ZygoteHost::kSandboxSUID;
+ if (getenv("SBX_PID_NS"))
+ sandbox_flags |= ZygoteHost::kSandboxPIDNS;
+ if (getenv("SBX_NET_NS"))
+ sandbox_flags |= ZygoteHost::kSandboxNetNS;
+
#if defined(SECCOMP_SANDBOX)
// The seccomp sandbox will be turned on when the renderers start. But we can
// already check if sufficient support is available so that we only need to
@@ -670,11 +696,12 @@ bool ZygoteMain(const MainFunctionParams& params) {
"sandboxing disabled.";
} else {
LOG(INFO) << "Enabling experimental Seccomp sandbox.";
+ sandbox_flags |= ZygoteHost::kSandboxSeccomp;
}
}
#endif // SECCOMP_SANDBOX
- Zygote zygote;
+ Zygote zygote(sandbox_flags);
// This function call can return multiple times, once per fork().
return zygote.ProcessRequests();
}
diff --git a/sandbox/linux/suid/sandbox.c b/sandbox/linux/suid/sandbox.c
index be6176a..0c92ad2 100644
--- a/sandbox/linux/suid/sandbox.c
+++ b/sandbox/linux/suid/sandbox.c
@@ -282,8 +282,21 @@ static bool MoveToNewNamespaces() {
if (pid > 0)
_exit(0);
- if (pid == 0)
+ if (pid == 0) {
+ if (kCloneExtraFlags[i] & CLONE_NEWPID) {
+ setenv("SBX_PID_NS", "", 1 /* overwrite */);
+ } else {
+ unsetenv("SBX_PID_NS");
+ }
+
+ if (kCloneExtraFlags[i] & CLONE_NEWPID) {
+ setenv("SBX_NET_NS", "", 1 /* overwrite */);
+ } else {
+ unsetenv("SBX_NET_NS");
+ }
+
break;
+ }
if (errno != EINVAL) {
perror("Failed to move to new PID namespace");