OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "content/browser/zygote_host/zygote_host_impl_linux.h" | 5 #include "content/browser/zygote_host/zygote_host_impl_linux.h" |
6 | 6 |
| 7 #include <string.h> |
7 #include <sys/socket.h> | 8 #include <sys/socket.h> |
8 #include <sys/stat.h> | 9 #include <sys/stat.h> |
9 #include <sys/types.h> | 10 #include <sys/types.h> |
10 #include <unistd.h> | 11 #include <unistd.h> |
11 | 12 |
12 #include "base/base_switches.h" | 13 #include "base/base_switches.h" |
13 #include "base/command_line.h" | 14 #include "base/command_line.h" |
14 #include "base/environment.h" | 15 #include "base/environment.h" |
15 #include "base/file_util.h" | 16 #include "base/file_util.h" |
16 #include "base/files/file_enumerator.h" | 17 #include "base/files/file_enumerator.h" |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
119 sandbox_binary_ = sandbox_cmd.c_str(); | 120 sandbox_binary_ = sandbox_cmd.c_str(); |
120 | 121 |
121 // A non empty sandbox_cmd means we want a SUID sandbox. | 122 // A non empty sandbox_cmd means we want a SUID sandbox. |
122 using_suid_sandbox_ = !sandbox_cmd.empty(); | 123 using_suid_sandbox_ = !sandbox_cmd.empty(); |
123 | 124 |
124 // Start up the sandbox host process and get the file descriptor for the | 125 // Start up the sandbox host process and get the file descriptor for the |
125 // renderers to talk to it. | 126 // renderers to talk to it. |
126 const int sfd = RenderSandboxHostLinux::GetInstance()->GetRendererSocket(); | 127 const int sfd = RenderSandboxHostLinux::GetInstance()->GetRendererSocket(); |
127 fds_to_map.push_back(std::make_pair(sfd, GetSandboxFD())); | 128 fds_to_map.push_back(std::make_pair(sfd, GetSandboxFD())); |
128 | 129 |
129 int dummy_fd = -1; | 130 base::ScopedFD dummy_fd; |
130 if (using_suid_sandbox_) { | 131 if (using_suid_sandbox_) { |
131 scoped_ptr<sandbox::SetuidSandboxClient> | 132 scoped_ptr<sandbox::SetuidSandboxClient> |
132 sandbox_client(sandbox::SetuidSandboxClient::Create()); | 133 sandbox_client(sandbox::SetuidSandboxClient::Create()); |
133 sandbox_client->PrependWrapper(&cmd_line, &options); | 134 sandbox_client->PrependWrapper(&cmd_line, &options); |
134 sandbox_client->SetupLaunchEnvironment(); | 135 sandbox_client->SetupLaunchEnvironment(); |
135 | 136 |
| 137 // We no longer need this dummy socket for discovering the zygote's PID, |
| 138 // but the sandbox is still hard-coded to expect a file descriptor at |
| 139 // kZygoteIdFd. Fixing this requires a sandbox API change. :( |
136 CHECK_EQ(kZygoteIdFd, sandbox_client->GetUniqueToChildFileDescriptor()); | 140 CHECK_EQ(kZygoteIdFd, sandbox_client->GetUniqueToChildFileDescriptor()); |
137 dummy_fd = socket(AF_UNIX, SOCK_DGRAM, 0); | 141 dummy_fd.reset(socket(AF_UNIX, SOCK_DGRAM, 0)); |
138 CHECK(dummy_fd >= 0); | 142 CHECK_GE(dummy_fd.get(), 0); |
139 fds_to_map.push_back(std::make_pair(dummy_fd, kZygoteIdFd)); | 143 fds_to_map.push_back(std::make_pair(dummy_fd.get(), kZygoteIdFd)); |
| 144 |
| 145 CHECK(UnixDomainSocket::EnableReceiveProcessId(fds[0])); |
140 } | 146 } |
141 | 147 |
142 base::ProcessHandle process = -1; | 148 base::ProcessHandle process = -1; |
143 options.fds_to_remap = &fds_to_map; | 149 options.fds_to_remap = &fds_to_map; |
144 base::LaunchProcess(cmd_line.argv(), options, &process); | 150 base::LaunchProcess(cmd_line.argv(), options, &process); |
145 CHECK(process != -1) << "Failed to launch zygote process"; | 151 CHECK(process != -1) << "Failed to launch zygote process"; |
146 | 152 |
| 153 dummy_fd.reset(); |
| 154 |
147 if (using_suid_sandbox_) { | 155 if (using_suid_sandbox_) { |
148 // In the SUID sandbox, the real zygote is forked from the sandbox. | |
149 // We need to look for it. | |
150 // But first, wait for the zygote to tell us it's running. | |
151 // The sending code is in content/browser/zygote_main_linux.cc. | 156 // The sending code is in content/browser/zygote_main_linux.cc. |
152 std::vector<int> fds_vec; | 157 std::vector<int> fds_vec; |
153 const int kExpectedLength = sizeof(kZygoteHelloMessage); | 158 const size_t kExpectedLength = sizeof(kZygoteHelloMessage); |
154 char buf[kExpectedLength]; | 159 char buf[kExpectedLength]; |
155 const ssize_t len = UnixDomainSocket::RecvMsg(fds[0], buf, sizeof(buf), | 160 const ssize_t len = UnixDomainSocket::RecvMsgWithPid( |
156 &fds_vec); | 161 fds[0], buf, sizeof(buf), &fds_vec, &pid_); |
157 CHECK_EQ(kExpectedLength, len) << "Incorrect zygote magic length"; | 162 CHECK_EQ(kExpectedLength, static_cast<size_t>(len)) |
158 CHECK(0 == strcmp(buf, kZygoteHelloMessage)) << "Incorrect zygote hello"; | 163 << "Incorrect zygote magic length"; |
| 164 CHECK_EQ(0, memcmp(buf, kZygoteHelloMessage, kExpectedLength)) |
| 165 << "Incorrect zygote hello"; |
| 166 CHECK_EQ(0U, fds_vec.size()) << "Zygote shouldn't send us any descriptors"; |
| 167 CHECK_GT(pid_, 1) << "Did not find zygote process"; |
159 | 168 |
160 std::string inode_output; | 169 // TODO(mdempsky): Sanity check that pid_ is valid for our namespace. Linux |
161 ino_t inode = 0; | 170 // kernels before 3.0 didn't translate across namespaces (crbug.com/357670). |
162 // Figure out the inode for |dummy_fd|, close |dummy_fd| on our end, | |
163 // and find the zygote process holding |dummy_fd|. | |
164 CHECK(base::FileDescriptorGetInode(&inode, dummy_fd)) | |
165 << "Cannot get inode for dummy_fd " << dummy_fd; | |
166 close(dummy_fd); | |
167 | |
168 std::vector<std::string> get_inode_cmdline; | |
169 get_inode_cmdline.push_back(sandbox_binary_); | |
170 get_inode_cmdline.push_back(base::kFindInodeSwitch); | |
171 get_inode_cmdline.push_back(base::Int64ToString(inode)); | |
172 CommandLine get_inode_cmd(get_inode_cmdline); | |
173 CHECK(base::GetAppOutput(get_inode_cmd, &inode_output)) | |
174 << "Find inode command failed for inode " << inode; | |
175 | |
176 base::TrimWhitespaceASCII(inode_output, base::TRIM_ALL, &inode_output); | |
177 CHECK(base::StringToInt(inode_output, &pid_)) | |
178 << "Invalid find inode output: " << inode_output; | |
179 CHECK(pid_ > 0) << "Did not find zygote process (using sandbox binary " | |
180 << sandbox_binary_ << ")"; | |
181 | 171 |
182 if (process != pid_) { | 172 if (process != pid_) { |
183 // Reap the sandbox. | 173 // Reap the sandbox. |
184 base::EnsureProcessGetsReaped(process); | 174 base::EnsureProcessGetsReaped(process); |
185 } | 175 } |
186 } else { | 176 } else { |
187 // Not using the SUID sandbox. | 177 // Not using the SUID sandbox. |
188 pid_ = process; | 178 pid_ = process; |
189 } | 179 } |
190 | 180 |
(...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
506 return RenderSandboxHostLinux::GetInstance()->pid(); | 496 return RenderSandboxHostLinux::GetInstance()->pid(); |
507 } | 497 } |
508 | 498 |
509 int ZygoteHostImpl::GetSandboxStatus() const { | 499 int ZygoteHostImpl::GetSandboxStatus() const { |
510 if (have_read_sandbox_status_word_) | 500 if (have_read_sandbox_status_word_) |
511 return sandbox_status_; | 501 return sandbox_status_; |
512 return 0; | 502 return 0; |
513 } | 503 } |
514 | 504 |
515 } // namespace content | 505 } // namespace content |
OLD | NEW |