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

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: Created 6 years, 11 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 2013 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 HRESULT (WINAPI *SHGetFolderPathFunction)(
31 IN HWND hwnd_owner,
32 IN int folder,
33 IN HANDLE token,
34 IN DWORD flags,
35 OUT LPWSTR path);
36
37 PathIsUNCFunction g_path_is_unc_func;
38 PathAppendFunction g_path_append_func;
39 PathIsPrefixFunction g_path_is_prefix_func;
40 SHGetFolderPathFunction g_get_folder_func;
41
42 // Populates the g_*_func pointers to functions which will be used in
43 // ShouldBypass(). Chrome_elf cannot have a load-time dependency on shell32 or
44 // shlwapi as this would induce a load-time dependency on user32.dll. Instead,
45 // the addresses of the functions we need are retrieved the first time this
46 // method is called, and cached to avoid subsequent calls to GetProcAddress().
47 // It is assumed that the host process will never unload these functions.
48 // Returns true if all the functions needed are present.
49 bool PopulateShellFunctions() {
50 // Early exit if functions have already been populated.
51 if (g_path_is_unc_func && g_path_append_func &&
52 g_path_is_prefix_func && g_get_folder_func) {
53 return true;
54 }
55
56 // Get the addresses of the functions we need and store them for future use.
57 HMODULE shell32 = ::LoadLibrary(L"shell32.dll");
robertshield 2014/01/16 16:10:26 Add a comment that these handles are intentionally
Cait (Slow) 2014/01/17 23:05:41 Done.
58 HMODULE shlwapi = ::LoadLibrary(L"shlwapi.dll");
59
60 if (!shlwapi || !shell32)
61 return false;
62
63 g_path_is_unc_func = reinterpret_cast<PathIsUNCFunction>(
64 ::GetProcAddress(shlwapi, "PathIsUNCW"));
65 g_path_append_func = reinterpret_cast<PathAppendFunction>(
66 ::GetProcAddress(shlwapi, "PathAppendW"));
67 g_path_is_prefix_func = reinterpret_cast<PathIsPrefixFunction>(
68 ::GetProcAddress(shlwapi, "PathIsPrefixW"));
69 g_get_folder_func = reinterpret_cast<SHGetFolderPathFunction>(
70 ::GetProcAddress(shell32, "SHGetFolderPathW"));
71
72 return g_path_is_unc_func && g_path_append_func &&
73 g_path_is_prefix_func && g_get_folder_func;
74 }
75
76 } // namespace
77
78 HANDLE WINAPI CreateFileWRedirect(
79 LPCWSTR file_name,
80 DWORD desired_access,
81 DWORD share_mode,
82 LPSECURITY_ATTRIBUTES security_attributes,
83 DWORD creation_disposition,
84 DWORD flags_and_attributes,
85 HANDLE template_file) {
86 if (ShouldBypass(file_name)) {
87 return CreateFileNTDLL(file_name,
88 desired_access,
89 share_mode,
90 security_attributes,
91 creation_disposition,
92 flags_and_attributes,
93 template_file);
94 }
95 return CreateFile(file_name,
96 desired_access,
97 share_mode,
98 security_attributes,
99 creation_disposition,
100 flags_and_attributes,
101 template_file);
102
103 }
104
105 HANDLE CreateFileNTDLL(
106 LPCWSTR file_name,
107 DWORD desired_access,
108 DWORD share_mode,
109 LPSECURITY_ATTRIBUTES security_attributes,
110 DWORD creation_disposition,
111 DWORD flags_and_attributes,
112 HANDLE template_file) {
113 HANDLE file_handle = INVALID_HANDLE_VALUE;
114 NTSTATUS result = STATUS_UNSUCCESSFUL;
115 IO_STATUS_BLOCK io_status_block = {};
116
117 // Convert from Win32 domain to to NT creation disposition values.
118 switch (creation_disposition) {
119 case CREATE_NEW:
120 creation_disposition = FILE_CREATE;
121 break;
122 case CREATE_ALWAYS:
123 creation_disposition = FILE_OVERWRITE_IF;
124 break;
125 case OPEN_EXISTING:
126 creation_disposition = FILE_OPEN;
127 break;
128 case OPEN_ALWAYS:
129 creation_disposition = FILE_OPEN_IF;
130 break;
131 case TRUNCATE_EXISTING:
132 creation_disposition = FILE_OVERWRITE;
133 break;
134 default:
135 SetLastError(ERROR_INVALID_PARAMETER);
136 return INVALID_HANDLE_VALUE;
137 }
138
139 if (!g_ntdll_lookup["NtCreateFile"] ||
140 !g_ntdll_lookup["RtlInitUnicodeString"]) {
141 return INVALID_HANDLE_VALUE;
142 }
143
144 NtCreateFileFunction create_file =
145 reinterpret_cast<NtCreateFileFunction>(g_ntdll_lookup["NtCreateFile"]);
146
147 RtlInitUnicodeStringFunction init_unicode_string =
148 reinterpret_cast<RtlInitUnicodeStringFunction>(
149 g_ntdll_lookup["RtlInitUnicodeString"]);
150
151 UNICODE_STRING path_unicode_string;
152
153 // Format the path into an NT path. Arguably this should be done with
154 // RtlDosPathNameToNtPathName_U, but afaict this is equivalent for
155 // local paths. Using this with a UNC path name will almost certainly
156 // break in interesting ways.
157 base::string16 filename_string(L"\\??\\");
158 filename_string += file_name;
159
160 init_unicode_string(&path_unicode_string, filename_string.c_str());
161
162 OBJECT_ATTRIBUTES path_attributes = {};
163 InitializeObjectAttributes(&path_attributes,
164 &path_unicode_string,
165 OBJ_CASE_INSENSITIVE,
166 NULL, // No Root Directory
167 NULL); // No Security Descriptor
168
169 // Set create_options, desired_access, and flags_and_attributes to match those
170 // set by kernel32!CreateFile.
171 ULONG create_options = FILE_ATTRIBUTE_DEVICE | FILE_ATTRIBUTE_ARCHIVE;
172 desired_access |= 0x100080;
173 flags_and_attributes &= 0x2FFA7;
174
175 result = create_file(&file_handle,
176 desired_access,
177 &path_attributes,
178 &io_status_block,
179 0, // Allocation size
180 flags_and_attributes,
181 share_mode,
182 creation_disposition,
183 create_options,
184 NULL,
185 0);
186
187 if (result != STATUS_SUCCESS) {
188 if (result == STATUS_OBJECT_NAME_COLLISION &&
189 creation_disposition == FILE_CREATE) {
190 SetLastError(ERROR_FILE_EXISTS);
191 }
192 return INVALID_HANDLE_VALUE;
193 }
194
195 if (creation_disposition == FILE_OPEN_IF) {
196 SetLastError(io_status_block.Information == FILE_OPENED ?
197 ERROR_ALREADY_EXISTS : ERROR_SUCCESS);
198 } else if (creation_disposition == FILE_OVERWRITE_IF) {
199 SetLastError(io_status_block.Information == FILE_OVERWRITTEN ?
200 ERROR_ALREADY_EXISTS : ERROR_SUCCESS);
201 } else {
202 SetLastError(ERROR_SUCCESS);
203 }
204
205 return file_handle;
206 }
207
208 bool ShouldBypass(LPCWSTR file_name) {
209 // If the shell functions are not present, forward the call to kernel32.
210 if (!PopulateShellFunctions())
211 return false;
212
213 // Forward all UNC filepaths to kernel32.
214 if (g_path_is_unc_func(file_name))
215 return false;
216
217 wchar_t local_appdata_path[MAX_PATH];
218
219 // Get the %LOCALAPPDATA% Path and append the location of our UserData
220 // directory to it.
221 HRESULT appdata_result = g_get_folder_func(
222 NULL, CSIDL_LOCAL_APPDATA, NULL, 0, local_appdata_path);
223
224 // If getting the %LOCALAPPDATA% path or appending to it failed, then forward
225 // the call to kernel32.
226 if (!SUCCEEDED(appdata_result) ||
227 !g_path_append_func(local_appdata_path, kAppDataDirName) ||
228 !g_path_append_func(local_appdata_path, kUserDataDirName)) {
229 return false;
230 }
231
232 // Check if we are trying to access something in the UserData dir. If so,
233 // then redirect the call to bypass kernel32.
234 return !!g_path_is_prefix_func(local_appdata_path, file_name);
235 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698