diff options
-rw-r--r-- | chrome/browser/nacl_host/nacl_process_host.cc | 24 | ||||
-rw-r--r-- | chrome/nacl/nacl_thread.cc | 42 |
2 files changed, 66 insertions, 0 deletions
diff --git a/chrome/browser/nacl_host/nacl_process_host.cc b/chrome/browser/nacl_host/nacl_process_host.cc index b5123ef..8200892 100644 --- a/chrome/browser/nacl_host/nacl_process_host.cc +++ b/chrome/browser/nacl_host/nacl_process_host.cc @@ -248,11 +248,35 @@ void NaClProcessHost::SendStartMessage() { #else nacl::FileDescriptor channel; channel.fd = dup(sockets_for_sel_ldr_[i]); + if (channel.fd < 0) { + LOG(ERROR) << "Failed to dup() a file descriptor"; + return; + } channel.auto_close = true; handles_for_sel_ldr.push_back(channel); #endif } +#if defined(OS_MACOSX) + // For dynamic loading support, NaCl requires a file descriptor that + // was created in /tmp, since those created with shm_open() are not + // mappable with PROT_EXEC. Rather than requiring an extra IPC + // round trip out of the sandbox, we create an FD here. + base::SharedMemory memory_buffer; + if (!memory_buffer.CreateAnonymous(/* size= */ 1)) { + LOG(ERROR) << "Failed to allocate memory buffer"; + return; + } + nacl::FileDescriptor memory_fd; + memory_fd.fd = dup(memory_buffer.handle().fd); + if (memory_fd.fd < 0) { + LOG(ERROR) << "Failed to dup() a file descriptor"; + return; + } + memory_fd.auto_close = true; + handles_for_sel_ldr.push_back(memory_fd); +#endif + Send(new NaClProcessMsg_Start(handles_for_sel_ldr)); sockets_for_sel_ldr_.clear(); } diff --git a/chrome/nacl/nacl_thread.cc b/chrome/nacl/nacl_thread.cc index 709b976..c1f9c67 100644 --- a/chrome/nacl/nacl_thread.cc +++ b/chrome/nacl/nacl_thread.cc @@ -4,6 +4,7 @@ #include "chrome/nacl/nacl_thread.h" +#include "base/atomicops.h" #include "base/scoped_ptr.h" #include "chrome/common/notification_service.h" #include "chrome/common/nacl_messages.h" @@ -13,6 +14,42 @@ #include "chrome/renderer/renderer_sandbox_support_linux.h" #endif +#if defined(OS_MACOSX) +namespace { + +// On Mac OS X, shm_open() works in the sandbox but does not give us +// an FD that we can map as PROT_EXEC. Rather than doing an IPC to +// get an executable SHM region when CreateMemoryObject() is called, +// we preallocate one on startup, since NaCl's sel_ldr only needs one +// of them. This saves a round trip. + +base::subtle::Atomic32 g_shm_fd = -1; + +int CreateMemoryObject(size_t size, bool executable) { + if (executable && size > 0) { + int result_fd = base::subtle::NoBarrier_AtomicExchange(&g_shm_fd, -1); + if (result_fd != -1) { + // ftruncate() is disallowed by the Mac OS X sandbox and + // returns EPERM. Luckily, we can get the same effect with + // lseek() + write(). + if (lseek(result_fd, size - 1, SEEK_SET) == -1) { + LOG(ERROR) << "lseek() failed: " << errno; + return -1; + } + if (write(result_fd, "", 1) != 1) { + LOG(ERROR) << "write() failed: " << errno; + return -1; + } + return result_fd; + } + } + // Fall back to NaCl's default implementation. + return -1; +} + +} +#endif + // This is ugly. We need an interface header file for the exported // sel_ldr interfaces. // TODO(gregoryd,sehr): Add an interface header. @@ -48,6 +85,11 @@ void NaClThread::OnStartSelLdr(std::vector<nacl::FileDescriptor> handles) { #if defined(OS_LINUX) nacl::SetCreateMemoryObjectFunc( renderer_sandbox_support::MakeSharedMemorySegmentViaIPCExecutable); +#elif defined(OS_MACOSX) + nacl::SetCreateMemoryObjectFunc(CreateMemoryObject); + CHECK(handles.size() >= 1); + g_shm_fd = nacl::ToNativeHandle(handles[handles.size() - 1]); + handles.pop_back(); #endif scoped_array<NaClHandle> array(new NaClHandle[handles.size()]); for (size_t i = 0; i < handles.size(); i++) { |