diff --git a/base/linux_util.h b/base/linux_util.h
index 657edda3f4aae6a5fcd12493a08d1596086237b3..1da519e2a67c20118455392dbbc3154db708f60a 100644
--- a/base/linux_util.h
+++ b/base/linux_util.h
@@ -12,6 +12,8 @@
 
 namespace base {
 
+static const char kFindInodeSwitch[] = "--find-inode";
+
 // Makes a copy of |pixels| with the ordering changed from BGRA to RGBA.
 // The caller is responsible for free()ing the data. If |stride| is 0,
 // it's assumed to be 4 * |width|.
diff --git a/chrome/app/chrome_dll_main.cc b/chrome/app/chrome_dll_main.cc
index f46ec701a92e260377fab5161b2062aa231f4f1c..22e95d2ab1ea04edab7e672a3276338e0fe4b260 100644
--- a/chrome/app/chrome_dll_main.cc
+++ b/chrome/app/chrome_dll_main.cc
@@ -18,8 +18,8 @@
 #elif defined(OS_POSIX)
 #include <locale.h>
 #include <signal.h>
-#include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/types.h>
 #include <unistd.h>
 #endif
 
@@ -27,6 +27,7 @@
 #include <gdk/gdk.h>
 #include <glib.h>
 #include <gtk/gtk.h>
+#include <stdlib.h>
 #include <string.h>
 #endif
 
@@ -58,6 +59,7 @@
 #if defined(OS_LINUX)
 #include "base/nss_init.h"
 #include "chrome/browser/renderer_host/render_sandbox_host_linux.h"
+#include "chrome/browser/zygote_host_linux.h"
 #endif
 
 #if defined(OS_MACOSX)
@@ -385,7 +387,7 @@ int ChromeMain(int argc, char** argv) {
 
     browser_pid =
         static_cast<base::ProcessId>(StringToInt(WideToASCII(channel_name)));
-    DCHECK(browser_pid != 0);
+    DCHECK_NE(browser_pid, 0);
 #else
     browser_pid = base::GetCurrentProcId();
 #endif
@@ -579,8 +581,29 @@ int ChromeMain(int argc, char** argv) {
 #endif
   } else if (process_type.empty()) {
 #if defined(OS_LINUX)
-    // Tickle the sandbox host so it forks now.
-    Singleton<RenderSandboxHostLinux>().get();
+    const char* sandbox_binary = NULL;
+    struct stat st;
+
+    // In Chromium branded builds, developers can set an environment variable to
+    // use the development sandbox. See
+    // http://code.google.com/p/chromium/wiki/LinuxSUIDSandboxDevelopment
+    if (stat("/proc/self/exe", &st) == 0 && st.st_uid == getuid())
+      sandbox_binary = getenv("CHROME_DEVEL_SANDBOX");
+
+#if defined(LINUX_SANDBOX_PATH)
+    if (!sandbox_binary)
+      sandbox_binary = LINUX_SANDBOX_PATH;
+#endif
+
+    std::string sandbox_cmd;
+    if (sandbox_binary)
+      sandbox_cmd = sandbox_binary;
+
+    // Tickle the sandbox host and zygote host so they fork now.
+    RenderSandboxHostLinux* shost = Singleton<RenderSandboxHostLinux>().get();
+    shost->Init(sandbox_cmd);
+    ZygoteHost* zhost = Singleton<ZygoteHost>().get();
+    zhost->Init(sandbox_cmd);
 
     // We want to be sure to init NSPR on the main thread.
     base::EnsureNSPRInit();
@@ -595,7 +618,7 @@ int ChromeMain(int argc, char** argv) {
     // gtk_init() can change |argc| and |argv|.
     gtk_init(&argc, &argv);
     SetUpGLibLogHandler();
-#endif
+#endif  // defined(OS_LINUX)
 
     ScopedOleInitializer ole_initializer;
     rv = BrowserMain(main_params);
diff --git a/chrome/browser/renderer_host/render_sandbox_host_linux.cc b/chrome/browser/renderer_host/render_sandbox_host_linux.cc
index 9e6e609a869f70577c0f79471345d46160274d1b..f31f71f13960ee4e29e381772e75645475b38a62 100644
--- a/chrome/browser/renderer_host/render_sandbox_host_linux.cc
+++ b/chrome/browser/renderer_host/render_sandbox_host_linux.cc
@@ -11,12 +11,14 @@
 #include <sys/poll.h>
 #include <time.h>
 
+#include <vector>
+
+#include "base/command_line.h"
 #include "base/eintr_wrapper.h"
-#include "base/platform_file.h"
-#include "base/process_util.h"
-#include "base/logging.h"
-#include "base/message_loop.h"
+#include "base/linux_util.h"
 #include "base/pickle.h"
+#include "base/process_util.h"
+#include "base/scoped_ptr.h"
 #include "base/string_util.h"
 #include "base/unix_domain_socket_posix.h"
 #include "chrome/common/sandbox_methods_linux.h"
@@ -42,7 +44,9 @@ class SandboxIPCProcess  {
   // browser_socket: the browser's end of the sandbox IPC socketpair. From the
   //   point of view of the renderer, it's talking to the browser but this
   //   object actually services the requests.
-  SandboxIPCProcess(int lifeline_fd, int browser_socket)
+  // sandbox_cmd: the path of the sandbox executable
+  SandboxIPCProcess(int lifeline_fd, int browser_socket,
+                    std::string sandbox_cmd)
       : lifeline_fd_(lifeline_fd),
         browser_socket_(browser_socket),
         font_config_(new FontConfigDirect()) {
@@ -51,6 +55,11 @@ class SandboxIPCProcess  {
     multimap.push_back(base::InjectionArc(0, browser_socket, false));
 
     base::CloseSuperfluousFds(multimap);
+
+    if (!sandbox_cmd.empty()) {
+      sandbox_cmd_.push_back(sandbox_cmd);
+      sandbox_cmd_.push_back(base::kFindInodeSwitch);
+    }
   }
 
   void Run() {
@@ -114,6 +123,8 @@ class SandboxIPCProcess  {
       HandleGetFontFamilyForChars(fd, pickle, iter, fds);
     } else if (kind == LinuxSandbox::METHOD_LOCALTIME) {
       HandleLocaltime(fd, pickle, iter, fds);
+    } else if (kind == LinuxSandbox::METHOD_GET_CHILD_WITH_INODE) {
+      HandleGetChildWithInode(fd, pickle, iter, fds);
     }
 
   error:
@@ -123,7 +134,7 @@ class SandboxIPCProcess  {
     }
   }
 
-  void HandleFontMatchRequest(int fd, Pickle& pickle, void* iter,
+  void HandleFontMatchRequest(int fd, const Pickle& pickle, void* iter,
                               std::vector<int>& fds) {
     bool fileid_valid;
     uint32_t fileid;
@@ -162,7 +173,7 @@ class SandboxIPCProcess  {
     SendRendererReply(fds, reply, -1);
   }
 
-  void HandleFontOpenRequest(int fd, Pickle& pickle, void* iter,
+  void HandleFontOpenRequest(int fd, const Pickle& pickle, void* iter,
                              std::vector<int>& fds) {
     uint32_t fileid;
     if (!pickle.ReadUInt32(&iter, &fileid))
@@ -182,7 +193,7 @@ class SandboxIPCProcess  {
       close(result_fd);
   }
 
-  void HandleGetFontFamilyForChars(int fd, Pickle& pickle, void* iter,
+  void HandleGetFontFamilyForChars(int fd, const Pickle& pickle, void* iter,
                                    std::vector<int>& fds) {
     // The other side of this call is
     // chrome/renderer/renderer_sandbox_support_linux.cc
@@ -222,7 +233,7 @@ class SandboxIPCProcess  {
     SendRendererReply(fds, reply, -1);
   }
 
-  void HandleLocaltime(int fd, Pickle& pickle, void* iter,
+  void HandleLocaltime(int fd, const Pickle& pickle, void* iter,
                        std::vector<int>& fds) {
     // The other side of this call is in zygote_main_linux.cc
 
@@ -247,6 +258,37 @@ class SandboxIPCProcess  {
     SendRendererReply(fds, reply, -1);
   }
 
+  void HandleGetChildWithInode(int fd, const Pickle& pickle, void* iter,
+                               std::vector<int>& fds) {
+    // The other side of this call is in zygote_main_linux.cc
+    if (sandbox_cmd_.empty()) {
+      LOG(ERROR) << "Not in the sandbox, this should not be called";
+      return;
+    }
+
+    uint64_t inode;
+    if (!pickle.ReadUInt64(&iter, &inode))
+      return;
+
+    base::ProcessId pid = 0;
+    std::string inode_output;
+
+    std::vector<std::string> sandbox_cmd = sandbox_cmd_;
+    sandbox_cmd.push_back(IntToString(inode));
+    CommandLine get_inode_cmd(sandbox_cmd);
+    if (base::GetAppOutput(get_inode_cmd, &inode_output))
+      StringToInt(inode_output, &pid);
+
+    if (!pid) {
+      LOG(ERROR) << "Could not get pid";
+      return;
+    }
+
+    Pickle reply;
+    reply.WriteInt(pid);
+    SendRendererReply(fds, reply, -1);
+  }
+
   void SendRendererReply(const std::vector<int>& fds, const Pickle& reply,
                          int reply_fd) {
     struct msghdr msg;
@@ -266,7 +308,7 @@ class SandboxIPCProcess  {
       cmsg->cmsg_level = SOL_SOCKET;
       cmsg->cmsg_type = SCM_RIGHTS;
       cmsg->cmsg_len = CMSG_LEN(sizeof(int));
-      memcpy(CMSG_DATA(cmsg), &reply_fd, sizeof(int));
+      memcpy(CMSG_DATA(cmsg), &reply_fd, sizeof(reply_fd));
       msg.msg_controllen = cmsg->cmsg_len;
     }
 
@@ -278,12 +320,20 @@ class SandboxIPCProcess  {
   const int lifeline_fd_;
   const int browser_socket_;
   FontConfigDirect* const font_config_;
+  std::vector<std::string> sandbox_cmd_;
 };
 
 // -----------------------------------------------------------------------------
 
 // Runs on the main thread at startup.
-RenderSandboxHostLinux::RenderSandboxHostLinux() {
+RenderSandboxHostLinux::RenderSandboxHostLinux()
+    : init_(false) {
+}
+
+void RenderSandboxHostLinux::Init(const std::string& sandbox_path) {
+  DCHECK(!init_);
+  init_ = true;
+
   int fds[2];
   // We use SOCK_SEQPACKET rather than SOCK_DGRAM to prevent the renderer from
   // sending datagrams to other sockets on the system. The sandbox may prevent
@@ -303,13 +353,15 @@ RenderSandboxHostLinux::RenderSandboxHostLinux() {
 
   pid_ = fork();
   if (pid_ == 0) {
-    SandboxIPCProcess handler(child_lifeline_fd, browser_socket);
+    SandboxIPCProcess handler(child_lifeline_fd, browser_socket, sandbox_path);
     handler.Run();
     _exit(0);
   }
 }
 
 RenderSandboxHostLinux::~RenderSandboxHostLinux() {
-  HANDLE_EINTR(close(renderer_socket_));
-  HANDLE_EINTR(close(childs_lifeline_fd_));
+  if (init_) {
+    HANDLE_EINTR(close(renderer_socket_));
+    HANDLE_EINTR(close(childs_lifeline_fd_));
+  }
 }
diff --git a/chrome/browser/renderer_host/render_sandbox_host_linux.h b/chrome/browser/renderer_host/render_sandbox_host_linux.h
index 6911787648b8cc0824e107d3bb20918e9a8a2e8a..ef871b8324aeeba35752db2a71f8118b08c5c2f1 100644
--- a/chrome/browser/renderer_host/render_sandbox_host_linux.h
+++ b/chrome/browser/renderer_host/render_sandbox_host_linux.h
@@ -7,6 +7,9 @@
 #ifndef CHROME_BROWSER_RENDERER_HOST_RENDER_SANDBOX_HOST_LINUX_H_
 #define CHROME_BROWSER_RENDERER_HOST_RENDER_SANDBOX_HOST_LINUX_H_
 
+#include <string>
+
+#include "base/logging.h"
 #include "base/singleton.h"
 
 // This is a singleton object which handles sandbox requests from the
@@ -15,8 +18,15 @@ class RenderSandboxHostLinux {
  public:
   // Get the file descriptor which renderers should be given in order to signal
   // crashes to the browser.
-  int GetRendererSocket() const { return renderer_socket_; }
-  pid_t pid() const { return pid_; }
+  int GetRendererSocket() const {
+    DCHECK(init_);
+    return renderer_socket_;
+  }
+  pid_t pid() const {
+    DCHECK(init_);
+    return pid_;
+  }
+  void Init(const std::string& sandbox_path);
 
  private:
   friend struct DefaultSingletonTraits<RenderSandboxHostLinux>;
@@ -24,11 +34,12 @@ class RenderSandboxHostLinux {
   RenderSandboxHostLinux();
   ~RenderSandboxHostLinux();
 
+  bool init_;
   int renderer_socket_;
   int childs_lifeline_fd_;
   pid_t pid_;
 
-  DISALLOW_EVIL_CONSTRUCTORS(RenderSandboxHostLinux);
+  DISALLOW_COPY_AND_ASSIGN(RenderSandboxHostLinux);
 };
 
 #endif  // CHROME_BROWSER_RENDERER_HOST_RENDER_SANDBOX_HOST_LINUX_H_
diff --git a/chrome/browser/zygote_host_linux.cc b/chrome/browser/zygote_host_linux.cc
index 3415926432626a451ca0fa8d14f974a291fbb87f..aafaecc1359a26f18a056c939d448a5fbeea4c88 100644
--- a/chrome/browser/zygote_host_linux.cc
+++ b/chrome/browser/zygote_host_linux.cc
@@ -4,13 +4,14 @@
 
 #include "chrome/browser/zygote_host_linux.h"
 
-#include <unistd.h>
-#include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #include "base/command_line.h"
 #include "base/eintr_wrapper.h"
+#include "base/linux_util.h"
 #include "base/logging.h"
 #include "base/path_service.h"
 #include "base/pickle.h"
@@ -21,6 +22,7 @@
 #include "chrome/browser/renderer_host/render_sandbox_host_linux.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/process_watcher.h"
 
 #include "sandbox/linux/suid/suid_unsafe_environment_variables.h"
 
@@ -45,7 +47,20 @@ static void SaveSUIDUnsafeEnvironmentVariables() {
   }
 }
 
-ZygoteHost::ZygoteHost() {
+ZygoteHost::ZygoteHost()
+    : pid_(-1),
+      init_(false) {
+}
+
+ZygoteHost::~ZygoteHost() {
+  if (init_)
+    close(control_fd_);
+}
+
+void ZygoteHost::Init(const std::string& sandbox_cmd) {
+  DCHECK(!init_);
+  init_ = true;
+
   FilePath chrome_path;
   CHECK(PathService::Get(base::FILE_EXE, &chrome_path));
   CommandLine cmd_line(chrome_path);
@@ -82,26 +97,15 @@ ZygoteHost::ZygoteHost() {
                                        switches::kEnableLogging));
   }
 
-  const char* sandbox_binary = NULL;
+  const char* sandbox_binary = sandbox_cmd.c_str();
   struct stat st;
 
-  // In Chromium branded builds, developers can set an environment variable to
-  // use the development sandbox. See
-  // http://code.google.com/p/chromium/wiki/LinuxSUIDSandboxDevelopment
-  if (stat("/proc/self/exe", &st) == 0 &&
-      st.st_uid == getuid()) {
-    sandbox_binary = getenv("CHROME_DEVEL_SANDBOX");
-  }
-
-#if defined(LINUX_SANDBOX_PATH)
-  if (!sandbox_binary)
-    sandbox_binary = LINUX_SANDBOX_PATH;
-#endif
-
-  if (sandbox_binary && stat(sandbox_binary, &st) == 0) {
+  bool using_suid_sandbox = false;
+  if (!sandbox_cmd.empty() && stat(sandbox_binary, &st) == 0) {
     if (access(sandbox_binary, X_OK) == 0 &&
         (st.st_mode & S_ISUID) &&
         (st.st_mode & S_IXOTH)) {
+      using_suid_sandbox = true;
       cmd_line.PrependWrapper(ASCIIToWide(sandbox_binary));
 
       SaveSUIDUnsafeEnvironmentVariables();
@@ -118,22 +122,63 @@ ZygoteHost::ZygoteHost() {
   const int sfd = Singleton<RenderSandboxHostLinux>()->GetRendererSocket();
   fds_to_map.push_back(std::make_pair(sfd, 5));
 
+  int dummy_fd = -1;
+  if (using_suid_sandbox) {
+    dummy_fd = socket(PF_UNIX, SOCK_DGRAM, 0);
+    CHECK(dummy_fd >= 0);
+    fds_to_map.push_back(std::make_pair(dummy_fd, 7));
+  }
+
   base::ProcessHandle process;
   base::LaunchApp(cmd_line.argv(), fds_to_map, false, &process);
   CHECK(process != -1) << "Failed to launch zygote process";
 
-  pid_ = process;
+  if (using_suid_sandbox) {
+    // In the SUID sandbox, the real zygote is forked from the sandbox.
+    // We need to look for it.
+    // But first, wait for the zygote to tell us it's running.
+    // The sending code is in chrome/browser/zygote_main_linux.cc.
+    std::vector<int> fds_vec;
+    const int kExpectedLength = sizeof(kZygoteMagic);
+    char buf[kExpectedLength];
+    const ssize_t len = base::RecvMsg(fds[0], buf, sizeof(buf), &fds_vec);
+    CHECK(len == kExpectedLength) << "Incorrect zygote magic length";
+    CHECK(0 == strcmp(buf, kZygoteMagic)) << "Incorrect zygote magic";
+
+    std::string inode_output;
+    ino_t inode = 0;
+    // Figure out the inode for |dummy_fd|, close |dummy_fd| on our end,
+    // and find the zygote process holding |dummy_fd|.
+    if (base::FileDescriptorGetInode(&inode, dummy_fd)) {
+      close(dummy_fd);
+      std::vector<std::string> get_inode_cmdline;
+      get_inode_cmdline.push_back(sandbox_binary);
+      get_inode_cmdline.push_back(base::kFindInodeSwitch);
+      get_inode_cmdline.push_back(IntToString(inode));
+      CommandLine get_inode_cmd(get_inode_cmdline);
+      if (base::GetAppOutput(get_inode_cmd, &inode_output)) {
+        StringToInt(inode_output, &pid_);
+      }
+    }
+    CHECK(pid_ > 0) << "Did not find zygote process";
+
+    if (process != pid_) {
+      // Reap the sandbox.
+      ProcessWatcher::EnsureProcessGetsReaped(process);
+    }
+  } else {
+    // Not using the SUID sandbox.
+    pid_ = process;
+  }
+
   close(fds[1]);
   control_fd_ = fds[0];
 }
 
-ZygoteHost::~ZygoteHost() {
-  close(control_fd_);
-}
-
 pid_t ZygoteHost::ForkRenderer(
     const std::vector<std::string>& argv,
     const base::GlobalDescriptors::Mapping& mapping) {
+  DCHECK(init_);
   Pickle pickle;
 
   pickle.WriteInt(kCmdFork);
@@ -162,6 +207,7 @@ pid_t ZygoteHost::ForkRenderer(
 }
 
 void ZygoteHost::EnsureProcessTerminated(pid_t process) {
+  DCHECK(init_);
   Pickle pickle;
 
   pickle.WriteInt(kCmdReap);
@@ -172,6 +218,7 @@ void ZygoteHost::EnsureProcessTerminated(pid_t process) {
 
 bool ZygoteHost::DidProcessCrash(base::ProcessHandle handle,
                                  bool* child_exited) {
+  DCHECK(init_);
   Pickle pickle;
   pickle.WriteInt(kCmdDidProcessCrash);
   pickle.WriteInt(handle);
diff --git a/chrome/browser/zygote_host_linux.h b/chrome/browser/zygote_host_linux.h
index 516a18ba89c9a9c95f6fbc6777debe82ee3ff961..5b4244c27f55445b670106c0734d9cdf11b6e1ea 100644
--- a/chrome/browser/zygote_host_linux.h
+++ b/chrome/browser/zygote_host_linux.h
@@ -5,24 +5,26 @@
 #ifndef CHROME_BROWSER_ZYGOTE_HOST_LINUX_H_
 #define CHROME_BROWSER_ZYGOTE_HOST_LINUX_H_
 
+#include <unistd.h>
+
 #include <string>
 #include <vector>
 
-#include <unistd.h>
-
 #include "base/global_descriptors_posix.h"
 #include "base/process.h"
 
 template<typename Type>
 struct DefaultSingletonTraits;
 
+static const char kZygoteMagic[] = "ZYGOTE_OK";
+
 // http://code.google.com/p/chromium/wiki/LinuxZygote
 
 // The zygote host is the interface, in the browser process, to the zygote
 // process.
 class ZygoteHost {
  public:
-  ~ZygoteHost();
+  void Init(const std::string& sandbox_cmd);
 
   pid_t ForkRenderer(const std::vector<std::string>& command_line,
                      const base::GlobalDescriptors::Mapping& mapping);
@@ -46,10 +48,11 @@ class ZygoteHost {
  private:
   friend struct DefaultSingletonTraits<ZygoteHost>;
   ZygoteHost();
-  void LaunchZygoteProcess();
+  ~ZygoteHost();
 
   int control_fd_;  // the socket to the zygote
   pid_t pid_;
+  bool init_;
 };
 
 #endif  // CHROME_BROWSER_ZYGOTE_HOST_LINUX_H_
diff --git a/chrome/browser/zygote_main_linux.cc b/chrome/browser/zygote_main_linux.cc
index ecf7291311f6103930d61c8af11db9af8c2745a6..b9839d308afe61bef994dc2fc4f50fdd7da1611f 100644
--- a/chrome/browser/zygote_main_linux.cc
+++ b/chrome/browser/zygote_main_linux.cc
@@ -3,18 +3,25 @@
 // found in the LICENSE file.
 
 #include <dlfcn.h>
-#include <unistd.h>
 #include <sys/epoll.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/signal.h>
 #include <sys/prctl.h>
+#include <sys/signal.h>
+#include <sys/socket.h>
+#include <sys/types.h>
 #include <sys/wait.h>
+#include <unistd.h>
+
+#if defined(CHROMIUM_SELINUX)
+#include <selinux/selinux.h>
+#include <selinux/context.h>
+#endif
 
 #include "base/basictypes.h"
 #include "base/command_line.h"
 #include "base/eintr_wrapper.h"
 #include "base/global_descriptors_posix.h"
+#include "base/hash_tables.h"
+#include "base/linux_util.h"
 #include "base/path_service.h"
 #include "base/pickle.h"
 #include "base/rand_util.h"
@@ -33,16 +40,14 @@
 
 #include "skia/ext/SkFontHost_fontconfig_control.h"
 
-#if defined(CHROMIUM_SELINUX)
-#include <selinux/selinux.h>
-#include <selinux/context.h>
-#endif
-
 #include "unicode/timezone.h"
 
 // http://code.google.com/p/chromium/wiki/LinuxZygote
 
+static const int kBrowserDescriptor = 3;
 static const int kMagicSandboxIPCDescriptor = 5;
+static const int kZygoteIdDescriptor = 7;
+static bool g_suid_sandbox_active = false;
 
 // This is the object which implements the zygote. The ZygoteMain function,
 // which is called from ChromeMain, at the the bottom and simple constructs one
@@ -52,7 +57,7 @@ class Zygote {
   bool ProcessRequests() {
     // A SOCK_SEQPACKET socket is installed in fd 3. We get commands from the
     // browser on it.
-    // A SOCK_DGRAM is installed in fd 4. This is the sandbox IPC channel.
+    // A SOCK_DGRAM is installed in fd 5. This is the sandbox IPC channel.
     // See http://code.google.com/p/chromium/wiki/LinuxSandboxIPC
 
     // We need to accept SIGCHLD, even though our handler is a no-op because
@@ -62,8 +67,17 @@ class Zygote {
     action.sa_handler = SIGCHLDHandler;
     CHECK(sigaction(SIGCHLD, &action, NULL) == 0);
 
+    if (g_suid_sandbox_active) {
+      // Let the ZygoteHost know we are ready to go.
+      // The receiving code is in chrome/browser/zygote_host_linux.cc.
+      std::vector<int> empty;
+      bool r = base::SendMsg(kBrowserDescriptor, kZygoteMagic,
+                             sizeof(kZygoteMagic), empty);
+      CHECK(r) << "Sending zygote magic failed";
+    }
+
     for (;;) {
-      if (HandleRequestFromBrowser(3))
+      if (HandleRequestFromBrowser(kBrowserDescriptor))
         return true;
     }
   }
@@ -122,20 +136,30 @@ class Zygote {
     return false;
   }
 
-  bool HandleReapRequest(int fd, Pickle& pickle, void* iter) {
-    pid_t child;
+  bool HandleReapRequest(int fd, const Pickle& pickle, void* iter) {
+    base::ProcessId child;
+    base::ProcessId actual_child;
 
     if (!pickle.ReadInt(&iter, &child)) {
       LOG(WARNING) << "Error parsing reap request from browser";
       return false;
     }
 
-    ProcessWatcher::EnsureProcessTerminated(child);
+    if (g_suid_sandbox_active) {
+      actual_child = real_pids_to_sandbox_pids[child];
+      if (!actual_child)
+        return false;
+      real_pids_to_sandbox_pids.erase(child);
+    } else {
+      actual_child = child;
+    }
+
+    ProcessWatcher::EnsureProcessTerminated(actual_child);
 
     return false;
   }
 
-  bool HandleDidProcessCrash(int fd, Pickle& pickle, void* iter) {
+  bool HandleDidProcessCrash(int fd, const Pickle& pickle, void* iter) {
     base::ProcessHandle child;
 
     if (!pickle.ReadInt(&iter, &child)) {
@@ -144,7 +168,13 @@ class Zygote {
     }
 
     bool child_exited;
-    bool did_crash = base::DidProcessCrash(&child_exited, child);
+    bool did_crash;
+    if (g_suid_sandbox_active)
+      child = real_pids_to_sandbox_pids[child];
+    if (child)
+      did_crash = base::DidProcessCrash(&child_exited, child);
+    else
+      did_crash = child_exited = false;
 
     Pickle write_pickle;
     write_pickle.WriteBool(did_crash);
@@ -156,12 +186,14 @@ class Zygote {
 
   // Handle a 'fork' request from the browser: this means that the browser
   // wishes to start a new renderer.
-  bool HandleForkRequest(int fd, Pickle& pickle, void* iter,
+  bool HandleForkRequest(int fd, const Pickle& pickle, void* iter,
                          std::vector<int>& fds) {
     std::vector<std::string> args;
     int argc, numfds;
     base::GlobalDescriptors::Mapping mapping;
-    pid_t child;
+    base::ProcessId child;
+    uint64_t dummy_inode = 0;
+    int dummy_fd = -1;
 
     if (!pickle.ReadInt(&iter, &argc))
       goto error;
@@ -186,12 +218,22 @@ class Zygote {
     }
 
     mapping.push_back(std::make_pair(
-        static_cast<uint32_t>(kSandboxIPCChannel), 5));
+        static_cast<uint32_t>(kSandboxIPCChannel), kMagicSandboxIPCDescriptor));
+
+    if (g_suid_sandbox_active) {
+      dummy_fd = socket(PF_UNIX, SOCK_DGRAM, 0);
+      if (dummy_fd < 0)
+        goto error;
+
+      if (!base::FileDescriptorGetInode(&dummy_inode, dummy_fd))
+        goto error;
+    }
 
     child = fork();
 
     if (!child) {
-      close(3);  // our socket from the browser is in fd 3
+      close(kBrowserDescriptor);  // our socket from the browser
+      close(kZygoteIdDescriptor);  // another socket from the browser
       Singleton<base::GlobalDescriptors>()->Reset(mapping);
 
       // Reset the process-wide command line to our new command line.
@@ -200,22 +242,59 @@ class Zygote {
       CommandLine::ForCurrentProcess()->InitFromArgv(args);
       CommandLine::SetProcTitle();
       return true;
+    } else if (child < 0) {
+      LOG(ERROR) << "Zygote could not fork";
+      goto error;
     }
 
-    for (std::vector<int>::const_iterator
-         i = fds.begin(); i != fds.end(); ++i)
-      close(*i);
+    {
+      base::ProcessId proc_id;
+      if (g_suid_sandbox_active) {
+        close(dummy_fd);
+        dummy_fd = -1;
+        uint8_t reply_buf[512];
+        Pickle request;
+        request.WriteInt(LinuxSandbox::METHOD_GET_CHILD_WITH_INODE);
+        request.WriteUInt64(dummy_inode);
+
+        const ssize_t r = base::SendRecvMsg(kMagicSandboxIPCDescriptor,
+                                            reply_buf, sizeof(reply_buf),
+                                            NULL, request);
+        if (r == -1)
+          goto error;
+
+        Pickle reply(reinterpret_cast<char*>(reply_buf), r);
+        void* iter2 = NULL;
+        if (!reply.ReadInt(&iter2, &proc_id))
+          goto error;
+        real_pids_to_sandbox_pids[proc_id] = child;
+      } else {
+        proc_id = child;
+      }
 
-    HANDLE_EINTR(write(fd, &child, sizeof(child)));
-    return false;
+      for (std::vector<int>::const_iterator
+           i = fds.begin(); i != fds.end(); ++i)
+        close(*i);
+
+      HANDLE_EINTR(write(fd, &proc_id, sizeof(proc_id)));
+      return false;
+    }
 
    error:
-    LOG(WARNING) << "Error parsing fork request from browser";
+    LOG(ERROR) << "Error parsing fork request from browser";
     for (std::vector<int>::const_iterator
          i = fds.begin(); i != fds.end(); ++i)
       close(*i);
+    if (dummy_fd >= 0)
+      close(dummy_fd);
     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;
 };
 
 // With SELinux we can carve out a precise sandbox, so we don't have to play
@@ -402,6 +481,8 @@ static bool EnterSandbox() {
     // over which we can signal that we have completed our startup and can be
     // chrooted.
 
+    g_suid_sandbox_active = true;
+
     char* endptr;
     const long fd_long = strtol(sandbox_fd_string, &endptr, 10);
     if (!*sandbox_fd_string || *endptr || fd_long < 0 || fd_long > INT_MAX)
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index c2f061c72d4115afeb4309ea3289c0ff3a8c4150..4ef2bff7e5dbfe8c1c2d8b9c57994ec92b6b40f8 100755
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -2531,11 +2531,6 @@
                 'browser/renderer_host/render_crash_handler_host_linux_stub.cc',
               ],
             }],
-            ['linux_sandbox_path != ""', {
-              'defines': [
-                'LINUX_SANDBOX_PATH="<(linux_sandbox_path)"',
-              ],
-            }],
           ],
         }],
         ['OS=="linux" and toolkit_views==0', {
@@ -3785,6 +3780,11 @@
                 '../sandbox/sandbox.gyp:sandbox',
               ],
             }],
+            ['linux_sandbox_path != ""', {
+              'defines': [
+                'LINUX_SANDBOX_PATH="<(linux_sandbox_path)"',
+              ],
+            }],
           ],
         }],
         ['OS=="mac" or OS=="win"', {
diff --git a/chrome/common/sandbox_methods_linux.h b/chrome/common/sandbox_methods_linux.h
index 4dceba0c6d67880b75a2bf4d6ca7657524d82c0e..22fbf29aebb3f662a880b1a3b324edf46cee62ce 100644
--- a/chrome/common/sandbox_methods_linux.h
+++ b/chrome/common/sandbox_methods_linux.h
@@ -14,6 +14,7 @@ class LinuxSandbox {
   enum Methods {
     METHOD_GET_FONT_FAMILY_FOR_CHARS = 32,
     METHOD_LOCALTIME = 33,
+    METHOD_GET_CHILD_WITH_INODE = 34,
   };
 };