OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/browser/nacl_host/pnacl_file_host.h" |
| 6 |
| 7 #include <stdio.h> |
| 8 |
| 9 #include "base/bind.h" |
| 10 #include "base/file_path.h" |
| 11 #include "base/file_util.h" |
| 12 #include "base/memory/ref_counted.h" |
| 13 #include "base/path_service.h" |
| 14 #include "base/platform_file.h" |
| 15 #include "chrome/common/chrome_paths.h" |
| 16 #include "chrome/common/render_messages.h" |
| 17 #include "chrome/browser/renderer_host/chrome_render_message_filter.h" |
| 18 #include "content/public/browser/browser_thread.h" |
| 19 #include "native_client/src/shared/imc/nacl_imc.h" |
| 20 |
| 21 using content::BrowserThread; |
| 22 |
| 23 namespace { |
| 24 |
| 25 // Need the DuplicateHandle good to send the handle over to the |
| 26 // plugin process. |
| 27 // TODO(jvoung): share some code with nacl_process_host if possible. |
| 28 bool SendHandleToNaClPlugin( |
| 29 base::ProcessHandle target_processh, |
| 30 nacl::Handle sourceh, |
| 31 bool close_source, |
| 32 nacl::FileDescriptor* handle_for_plugin) { |
| 33 #if defined(OS_WIN) |
| 34 HANDLE channel; |
| 35 int flags = DUPLICATE_SAME_ACCESS; |
| 36 if (close_source) |
| 37 flags |= DUPLICATE_CLOSE_SOURCE; |
| 38 if (!DuplicateHandle(GetCurrentProcess(), |
| 39 reinterpret_cast<HANDLE>(sourceh), |
| 40 target_processh, |
| 41 &channel, |
| 42 0, // Unused given DUPLICATE_SAME_ACCESS. |
| 43 FALSE, |
| 44 flags)) { |
| 45 LOG(ERROR) << "DuplicateHandle() failed"; |
| 46 return false; |
| 47 } |
| 48 *handle_for_plugin = reinterpret_cast<nacl::FileDescriptor>(channel); |
| 49 #else |
| 50 nacl::FileDescriptor channel; |
| 51 channel.fd = sourceh; |
| 52 channel.auto_close = close_source; |
| 53 *handle_for_plugin = channel; |
| 54 #endif |
| 55 return true; |
| 56 } |
| 57 |
| 58 void NotifyRendererOfError( |
| 59 ChromeRenderMessageFilter* chrome_render_message_filter, |
| 60 IPC::Message* reply_msg) { |
| 61 reply_msg->set_reply_error(); |
| 62 chrome_render_message_filter->Send(reply_msg); |
| 63 } |
| 64 |
| 65 // This only ever runs on the BrowserThread::FILE thread. |
| 66 // TODO(jvoung): assert that. |
| 67 void DoOpenPnaclFile( |
| 68 ChromeRenderMessageFilter* chrome_render_message_filter, |
| 69 std::string filename, |
| 70 IPC::Message* reply_msg) { |
| 71 FilePath full_filepath; |
| 72 |
| 73 // Do some validation. |
| 74 if (!pnacl_file_host::PnaclCanOpenFile(filename, &full_filepath)) { |
| 75 LOG(ERROR) << "Failed to validate Pnacl filename: " << filename; |
| 76 NotifyRendererOfError(chrome_render_message_filter, reply_msg); |
| 77 return; |
| 78 } |
| 79 |
| 80 base::PlatformFile file_to_open; |
| 81 if (!pnacl_file_host::PnaclDoOpenFile(full_filepath, &file_to_open)) { |
| 82 NotifyRendererOfError(chrome_render_message_filter, reply_msg); |
| 83 } |
| 84 |
| 85 |
| 86 // Send the reply! |
| 87 // Do any DuplicateHandle magic that is necessary first. |
| 88 nacl::FileDescriptor target_desc; |
| 89 SendHandleToNaClPlugin(chrome_render_message_filter->peer_handle(), |
| 90 file_to_open, |
| 91 true /* Close source */, |
| 92 &target_desc); |
| 93 ChromeViewHostMsg_GetReadonlyPnaclFD::WriteReplyParams( |
| 94 reply_msg, target_desc); |
| 95 chrome_render_message_filter->Send(reply_msg); |
| 96 } |
| 97 |
| 98 } // namespace |
| 99 |
| 100 namespace pnacl_file_host { |
| 101 |
| 102 void GetReadonlyPnaclFd( |
| 103 ChromeRenderMessageFilter* chrome_render_message_filter, |
| 104 const std::string& filename, |
| 105 IPC::Message* reply_msg) { |
| 106 fprintf(stderr, "In GetReadonlyPnaclFd: %s\n", filename.c_str()); |
| 107 |
| 108 if (!BrowserThread::PostTask( |
| 109 BrowserThread::FILE, FROM_HERE, |
| 110 base::Bind(&DoOpenPnaclFile, |
| 111 make_scoped_refptr(chrome_render_message_filter), |
| 112 filename, |
| 113 reply_msg))) { |
| 114 NotifyRendererOfError(chrome_render_message_filter, reply_msg); |
| 115 } |
| 116 } |
| 117 |
| 118 bool PnaclCanOpenFile(const std::string& filename, |
| 119 FilePath *file_to_open) { |
| 120 // Do some validation. |
| 121 // The file must use only ASCII characters. |
| 122 if (!IsStringASCII(filename)) { |
| 123 LOG(ERROR) << "not ASCII: " << filename; |
| 124 return false; |
| 125 } |
| 126 |
| 127 if (filename.find('%') != std::string::npos || |
| 128 filename.find('$') != std::string::npos) { |
| 129 LOG(ERROR) << "Has funny symbols " << filename; |
| 130 return false; |
| 131 } |
| 132 |
| 133 #if defined(OS_WIN) |
| 134 FilePath file_to_find(ASCIIToUTF16(filename)); |
| 135 #elif defined(OS_POSIX) |
| 136 FilePath file_to_find(filename); |
| 137 #endif |
| 138 |
| 139 if (file_to_find.empty() || file_util::IsDot(file_to_find)) { |
| 140 LOG(ERROR) << "Empty or dot " << file_to_find.LossyDisplayName(); |
| 141 return false; |
| 142 } |
| 143 |
| 144 // Disallow peeking outside of the pnacl component directory. |
| 145 if (file_to_find.ReferencesParent() || file_to_find.IsAbsolute()) { |
| 146 LOG(ERROR) << "ReferencesParent or IsAbsolute: " |
| 147 << file_to_find.LossyDisplayName(); |
| 148 return false; |
| 149 } |
| 150 |
| 151 // Disallow special shell characters, just in case... |
| 152 |
| 153 FilePath pnacl_dir; |
| 154 if (!PathService::Get(chrome::DIR_PNACL_COMPONENT, &pnacl_dir)) { |
| 155 LOG(ERROR) << "No DIR_PNACL_COMPONENT"; |
| 156 return false; |
| 157 } |
| 158 if (pnacl_dir.empty()) { |
| 159 LOG(ERROR) << "pnacl_dir is empty: " << pnacl_dir.LossyDisplayName(); |
| 160 return false; |
| 161 } |
| 162 |
| 163 FilePath full_path = pnacl_dir.Append(file_to_find); |
| 164 *file_to_open = full_path; |
| 165 return true; |
| 166 } |
| 167 |
| 168 bool PnaclDoOpenFile(const FilePath& file_to_open, |
| 169 base::PlatformFile* out_file) { |
| 170 base::PlatformFileError error_code; |
| 171 *out_file = base::CreatePlatformFile(file_to_open, |
| 172 base::PLATFORM_FILE_OPEN | |
| 173 base::PLATFORM_FILE_READ | |
| 174 base::PLATFORM_FILE_SHARE_DELETE, |
| 175 NULL, |
| 176 &error_code); |
| 177 if (error_code != base::PLATFORM_FILE_OK) { |
| 178 LOG(ERROR) << "Failed to open Pnacl file \"" |
| 179 << file_to_open.LossyDisplayName() |
| 180 << "\": " << error_code; |
| 181 return false; |
| 182 } |
| 183 return true; |
| 184 } |
| 185 |
| 186 } // namespace pnacl_file_host |
OLD | NEW |