Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: chrome_elf/create_file/chrome_create_file.cc

Issue 138593004: Use an alternate mechanism for CreateFile calls in Chrome (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: CreateFile and tests only, gyp changes in separate CL Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2014 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_elf/create_file/chrome_create_file.h"
6
7 #include <string>
8
9 #include "base/strings/string16.h"
10 #include "chrome_elf/chrome_elf_constants.h"
11 #include "chrome_elf/ntdll_cache.h"
12 #include "sandbox/win/src/nt_internals.h"
13
14 namespace {
15
16 // From ShlObj.h in the Windows SDK.
17 #define CSIDL_LOCAL_APPDATA 0x001c
18
19 typedef BOOL (WINAPI *PathIsUNCFunction)(
20 IN LPCWSTR path);
21
22 typedef BOOL (WINAPI *PathAppendFunction)(
23 IN LPWSTR path,
24 IN LPCWSTR more);
25
26 typedef BOOL (WINAPI *PathIsPrefixFunction)(
27 IN LPCWSTR prefix,
28 IN LPCWSTR path);
29
30 typedef LPCWSTR (WINAPI *PathFindFileName)(
31 IN LPCWSTR path);
32
33 typedef HRESULT (WINAPI *SHGetFolderPathFunction)(
34 IN HWND hwnd_owner,
35 IN int folder,
36 IN HANDLE token,
37 IN DWORD flags,
38 OUT LPWSTR path);
39
40 PathIsUNCFunction g_path_is_unc_func;
41 PathAppendFunction g_path_append_func;
42 PathIsPrefixFunction g_path_is_prefix_func;
43 PathFindFileName g_path_find_filename_func;
44 SHGetFolderPathFunction g_get_folder_func;
45
46 // Populates the g_*_func pointers to functions which will be used in
47 // ShouldBypass(). Chrome_elf cannot have a load-time dependency on shell32 or
48 // shlwapi as this would induce a load-time dependency on user32.dll. Instead,
49 // the addresses of the functions we need are retrieved the first time this
50 // method is called, and cached to avoid subsequent calls to GetProcAddress().
51 // It is assumed that the host process will never unload these functions.
52 // Returns true if all the functions needed are present.
53 bool PopulateShellFunctions() {
54 // Early exit if functions have already been populated.
55 if (g_path_is_unc_func && g_path_append_func &&
56 g_path_is_prefix_func && g_get_folder_func) {
57 return true;
58 }
59
60 // Get the addresses of the functions we need and store them for future use.
61 // These handles are intentionally leaked to ensure that these modules do not
62 // get unloaded.
63 HMODULE shell32 = ::LoadLibrary(L"shell32.dll");
64 HMODULE shlwapi = ::LoadLibrary(L"shlwapi.dll");
65
66 if (!shlwapi || !shell32)
67 return false;
68
69 g_path_is_unc_func = reinterpret_cast<PathIsUNCFunction>(
70 ::GetProcAddress(shlwapi, "PathIsUNCW"));
71 g_path_append_func = reinterpret_cast<PathAppendFunction>(
72 ::GetProcAddress(shlwapi, "PathAppendW"));
73 g_path_is_prefix_func = reinterpret_cast<PathIsPrefixFunction>(
74 ::GetProcAddress(shlwapi, "PathIsPrefixW"));
75 g_path_find_filename_func = reinterpret_cast<PathFindFileName>(
76 ::GetProcAddress(shlwapi, "PathFindFileNameW"));
77 g_get_folder_func = reinterpret_cast<SHGetFolderPathFunction>(
78 ::GetProcAddress(shell32, "SHGetFolderPathW"));
79
80 return g_path_is_unc_func && g_path_append_func && g_path_is_prefix_func &&
81 g_path_find_filename_func && g_get_folder_func;
82 }
83
84 } // namespace
85
86 HANDLE WINAPI CreateFileWRedirect(
87 LPCWSTR file_name,
88 DWORD desired_access,
89 DWORD share_mode,
90 LPSECURITY_ATTRIBUTES security_attributes,
91 DWORD creation_disposition,
92 DWORD flags_and_attributes,
93 HANDLE template_file) {
94 if (ShouldBypass(file_name)) {
95 return CreateFileNTDLL(file_name,
96 desired_access,
97 share_mode,
98 security_attributes,
99 creation_disposition,
100 flags_and_attributes,
101 template_file);
102 }
103 return CreateFile(file_name,
104 desired_access,
105 share_mode,
106 security_attributes,
107 creation_disposition,
108 flags_and_attributes,
109 template_file);
110
111 }
112
113 HANDLE CreateFileNTDLL(
114 LPCWSTR file_name,
115 DWORD desired_access,
116 DWORD share_mode,
117 LPSECURITY_ATTRIBUTES security_attributes,
118 DWORD creation_disposition,
119 DWORD flags_and_attributes,
120 HANDLE template_file) {
121 HANDLE file_handle = INVALID_HANDLE_VALUE;
122 NTSTATUS result = STATUS_UNSUCCESSFUL;
123 IO_STATUS_BLOCK io_status_block = {};
124 ULONG flags = 0;
125
126 // Convert from Win32 domain to to NT creation disposition values.
127 switch (creation_disposition) {
128 case CREATE_NEW:
129 creation_disposition = FILE_CREATE;
130 break;
131 case CREATE_ALWAYS:
132 creation_disposition = FILE_OVERWRITE_IF;
133 break;
134 case OPEN_EXISTING:
135 creation_disposition = FILE_OPEN;
136 break;
137 case OPEN_ALWAYS:
138 creation_disposition = FILE_OPEN_IF;
139 break;
140 case TRUNCATE_EXISTING:
141 creation_disposition = FILE_OVERWRITE;
142 break;
143 default:
144 SetLastError(ERROR_INVALID_PARAMETER);
145 return INVALID_HANDLE_VALUE;
146 }
147
148 // Translate the flags that need no validation:
149 if (!(flags_and_attributes & FILE_FLAG_OVERLAPPED))
150 flags |= FILE_SYNCHRONOUS_IO_NONALERT;
151
152 if (flags_and_attributes & FILE_FLAG_WRITE_THROUGH)
153 flags |= FILE_WRITE_THROUGH;
154
155 if (flags_and_attributes & FILE_FLAG_RANDOM_ACCESS)
156 flags |= FILE_RANDOM_ACCESS;
157
158 if (flags_and_attributes & FILE_FLAG_SEQUENTIAL_SCAN)
159 flags |= FILE_SEQUENTIAL_ONLY;
160
161 if (flags_and_attributes & FILE_FLAG_DELETE_ON_CLOSE) {
162 flags |= FILE_DELETE_ON_CLOSE;
163 desired_access |= DELETE;
164 }
165
166 if (flags_and_attributes & FILE_FLAG_BACKUP_SEMANTICS)
167 flags |= FILE_OPEN_FOR_BACKUP_INTENT;
168 else
169 flags |= FILE_NON_DIRECTORY_FILE;
170
171
172 if (flags_and_attributes & FILE_FLAG_OPEN_REPARSE_POINT)
173 flags |= FILE_OPEN_REPARSE_POINT;
174
175 if (flags_and_attributes & FILE_FLAG_OPEN_NO_RECALL)
176 flags |= FILE_OPEN_NO_RECALL;
177
178 if (!g_ntdll_lookup["NtCreateFile"] ||
179 !g_ntdll_lookup["RtlInitUnicodeString"]) {
180 return INVALID_HANDLE_VALUE;
181 }
182
183 NtCreateFileFunction create_file =
184 reinterpret_cast<NtCreateFileFunction>(g_ntdll_lookup["NtCreateFile"]);
185
186 RtlInitUnicodeStringFunction init_unicode_string =
187 reinterpret_cast<RtlInitUnicodeStringFunction>(
188 g_ntdll_lookup["RtlInitUnicodeString"]);
189
190 UNICODE_STRING path_unicode_string;
191
192 // Format the path into an NT path. Arguably this should be done with
193 // RtlDosPathNameToNtPathName_U, but afaict this is equivalent for
194 // local paths. Using this with a UNC path name will almost certainly
195 // break in interesting ways.
196 base::string16 filename_string(L"\\??\\");
197 filename_string += file_name;
198
199 init_unicode_string(&path_unicode_string, filename_string.c_str());
200
201 OBJECT_ATTRIBUTES path_attributes = {};
202 InitializeObjectAttributes(&path_attributes,
203 &path_unicode_string,
204 OBJ_CASE_INSENSITIVE,
205 NULL, // No Root Directory
206 NULL); // No Security Descriptor
207
208 // Set desired_access, and flags_and_attributes to match those
209 // set by kernel32!CreateFile.
210 desired_access |= 0x100080;
211 flags_and_attributes &= 0x2FFA7;
212
213 result = create_file(&file_handle,
214 desired_access,
215 &path_attributes,
216 &io_status_block,
217 0, // Allocation size
218 flags_and_attributes,
219 share_mode,
220 creation_disposition,
221 flags,
222 NULL,
223 0);
224
225 if (result != STATUS_SUCCESS) {
226 if (result == STATUS_OBJECT_NAME_COLLISION &&
227 creation_disposition == FILE_CREATE) {
228 SetLastError(ERROR_FILE_EXISTS);
229 }
230 return INVALID_HANDLE_VALUE;
231 }
232
233 if (creation_disposition == FILE_OPEN_IF) {
234 SetLastError(io_status_block.Information == FILE_OPENED ?
235 ERROR_ALREADY_EXISTS : ERROR_SUCCESS);
236 } else if (creation_disposition == FILE_OVERWRITE_IF) {
237 SetLastError(io_status_block.Information == FILE_OVERWRITTEN ?
238 ERROR_ALREADY_EXISTS : ERROR_SUCCESS);
239 } else {
240 SetLastError(ERROR_SUCCESS);
241 }
242
243 return file_handle;
244 }
245
246 bool ShouldBypass(LPCWSTR file_path) {
247 // If the shell functions are not present, forward the call to kernel32.
248 if (!PopulateShellFunctions())
249 return false;
250
251 // Forward all UNC filepaths to kernel32.
252 if (g_path_is_unc_func(file_path))
253 return false;
254
255 wchar_t local_appdata_path[MAX_PATH];
256
257 // Get the %LOCALAPPDATA% Path and append the location of our UserData
258 // directory to it.
259 HRESULT appdata_result = g_get_folder_func(
260 NULL, CSIDL_LOCAL_APPDATA, NULL, 0, local_appdata_path);
261
262 // If getting the %LOCALAPPDATA% path or appending to it failed, then forward
263 // the call to kernel32.
264 if (!SUCCEEDED(appdata_result) ||
265 !g_path_append_func(local_appdata_path, kAppDataDirName) ||
266 !g_path_append_func(local_appdata_path, kUserDataDirName)) {
267 return false;
268 }
269
270 LPCWSTR file_name = g_path_find_filename_func(file_path);
271
272 bool in_userdata_dir = !!g_path_is_prefix_func(local_appdata_path, file_path);
273 bool is_settings_file = wcscmp(file_name, kPreferencesFilename) == 0 ||
274 wcscmp(file_name, kLocalStateFilename) == 0;
275
276 // Check if we are trying to access the Preferences in the UserData dir. If
277 // so, then redirect the call to bypass kernel32.
278 return in_userdata_dir && is_settings_file;
279 }
OLDNEW
« no previous file with comments | « chrome_elf/create_file/chrome_create_file.h ('k') | chrome_elf/create_file/chrome_create_file_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698