chrome_create_file.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file. 45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome_elf/create_file/chrome_create_file.h" 65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <string> 85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/string16.h" 105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome_elf/chrome_elf_constants.h" 115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome_elf/ntdll_cache.h" 125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "sandbox/win/src/nt_internals.h" 135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace { 155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// From ShlObj.h in the Windows SDK. 175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#define CSIDL_LOCAL_APPDATA 0x001c 185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)typedef BOOL (WINAPI *PathIsUNCFunction)( 205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) IN LPCWSTR path); 215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)typedef BOOL (WINAPI *PathAppendFunction)( 235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) IN LPWSTR path, 245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) IN LPCWSTR more); 255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)typedef BOOL (WINAPI *PathIsPrefixFunction)( 275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) IN LPCWSTR prefix, 285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) IN LPCWSTR path); 295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)typedef LPCWSTR (WINAPI *PathFindFileName)( 315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) IN LPCWSTR path); 325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)typedef HRESULT (WINAPI *SHGetFolderPathFunction)( 345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) IN HWND hwnd_owner, 355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) IN int folder, 365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) IN HANDLE token, 375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) IN DWORD flags, 385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) OUT LPWSTR path); 395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)PathIsUNCFunction g_path_is_unc_func; 415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)PathAppendFunction g_path_append_func; 425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)PathIsPrefixFunction g_path_is_prefix_func; 435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)PathFindFileName g_path_find_filename_func; 445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)SHGetFolderPathFunction g_get_folder_func; 455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Populates the g_*_func pointers to functions which will be used in 475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// ShouldBypass(). Chrome_elf cannot have a load-time dependency on shell32 or 485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// shlwapi as this would induce a load-time dependency on user32.dll. Instead, 495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// the addresses of the functions we need are retrieved the first time this 505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// method is called, and cached to avoid subsequent calls to GetProcAddress(). 515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// It is assumed that the host process will never unload these functions. 525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Returns true if all the functions needed are present. 535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool PopulateShellFunctions() { 545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Early exit if functions have already been populated. 555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (g_path_is_unc_func && g_path_append_func && 565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) g_path_is_prefix_func && g_get_folder_func) { 575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return true; 585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Get the addresses of the functions we need and store them for future use. 615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // These handles are intentionally leaked to ensure that these modules do not 625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // get unloaded. 635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) HMODULE shell32 = ::LoadLibrary(L"shell32.dll"); 645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) HMODULE shlwapi = ::LoadLibrary(L"shlwapi.dll"); 655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!shlwapi || !shell32) 675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) g_path_is_unc_func = reinterpret_cast<PathIsUNCFunction>( 705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ::GetProcAddress(shlwapi, "PathIsUNCW")); 715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) g_path_append_func = reinterpret_cast<PathAppendFunction>( 725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ::GetProcAddress(shlwapi, "PathAppendW")); 735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) g_path_is_prefix_func = reinterpret_cast<PathIsPrefixFunction>( 745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ::GetProcAddress(shlwapi, "PathIsPrefixW")); 755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) g_path_find_filename_func = reinterpret_cast<PathFindFileName>( 765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ::GetProcAddress(shlwapi, "PathFindFileNameW")); 775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) g_get_folder_func = reinterpret_cast<SHGetFolderPathFunction>( 785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ::GetProcAddress(shell32, "SHGetFolderPathW")); 795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return g_path_is_unc_func && g_path_append_func && g_path_is_prefix_func && 815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) g_path_find_filename_func && g_get_folder_func; 825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} // namespace 855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)HANDLE WINAPI CreateFileWRedirect( 875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) LPCWSTR file_name, 885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DWORD desired_access, 895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DWORD share_mode, 905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) LPSECURITY_ATTRIBUTES security_attributes, 915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DWORD creation_disposition, 925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DWORD flags_and_attributes, 935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) HANDLE template_file) { 945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (ShouldBypass(file_name)) { 955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return CreateFileNTDLL(file_name, 965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) desired_access, 975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) share_mode, 985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) security_attributes, 995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) creation_disposition, 1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) flags_and_attributes, 1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) template_file); 1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return CreateFile(file_name, 1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) desired_access, 1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) share_mode, 1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) security_attributes, 1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) creation_disposition, 1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) flags_and_attributes, 1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) template_file); 1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)HANDLE CreateFileNTDLL( 1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) LPCWSTR file_name, 1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DWORD desired_access, 1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DWORD share_mode, 1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) LPSECURITY_ATTRIBUTES security_attributes, 1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DWORD creation_disposition, 1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DWORD flags_and_attributes, 1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) HANDLE template_file) { 1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) HANDLE file_handle = INVALID_HANDLE_VALUE; 1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NTSTATUS result = STATUS_UNSUCCESSFUL; 1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) IO_STATUS_BLOCK io_status_block = {}; 1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ULONG flags = 0; 1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Convert from Win32 domain to to NT creation disposition values. 1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) switch (creation_disposition) { 1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case CREATE_NEW: 1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) creation_disposition = FILE_CREATE; 1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case CREATE_ALWAYS: 1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) creation_disposition = FILE_OVERWRITE_IF; 1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case OPEN_EXISTING: 1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) creation_disposition = FILE_OPEN; 1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case OPEN_ALWAYS: 1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) creation_disposition = FILE_OPEN_IF; 1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case TRUNCATE_EXISTING: 1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) creation_disposition = FILE_OVERWRITE; 1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) default: 1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SetLastError(ERROR_INVALID_PARAMETER); 1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return INVALID_HANDLE_VALUE; 1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Translate the flags that need no validation: 1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!(flags_and_attributes & FILE_FLAG_OVERLAPPED)) 1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) flags |= FILE_SYNCHRONOUS_IO_NONALERT; 1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (flags_and_attributes & FILE_FLAG_WRITE_THROUGH) 1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) flags |= FILE_WRITE_THROUGH; 1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (flags_and_attributes & FILE_FLAG_RANDOM_ACCESS) 1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) flags |= FILE_RANDOM_ACCESS; 1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (flags_and_attributes & FILE_FLAG_SEQUENTIAL_SCAN) 1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) flags |= FILE_SEQUENTIAL_ONLY; 1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (flags_and_attributes & FILE_FLAG_DELETE_ON_CLOSE) { 1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) flags |= FILE_DELETE_ON_CLOSE; 1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) desired_access |= DELETE; 1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (flags_and_attributes & FILE_FLAG_BACKUP_SEMANTICS) 1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) flags |= FILE_OPEN_FOR_BACKUP_INTENT; 1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) else 1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) flags |= FILE_NON_DIRECTORY_FILE; 1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (flags_and_attributes & FILE_FLAG_OPEN_REPARSE_POINT) 1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) flags |= FILE_OPEN_REPARSE_POINT; 1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (flags_and_attributes & FILE_FLAG_OPEN_NO_RECALL) 1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) flags |= FILE_OPEN_NO_RECALL; 1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!g_ntdll_lookup["NtCreateFile"] || 1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) !g_ntdll_lookup["RtlInitUnicodeString"]) { 1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return INVALID_HANDLE_VALUE; 1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NtCreateFileFunction create_file = 1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) reinterpret_cast<NtCreateFileFunction>(g_ntdll_lookup["NtCreateFile"]); 1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RtlInitUnicodeStringFunction init_unicode_string = 1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) reinterpret_cast<RtlInitUnicodeStringFunction>( 1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) g_ntdll_lookup["RtlInitUnicodeString"]); 1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) UNICODE_STRING path_unicode_string; 1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Format the path into an NT path. Arguably this should be done with 1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // RtlDosPathNameToNtPathName_U, but afaict this is equivalent for 1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // local paths. Using this with a UNC path name will almost certainly 1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // break in interesting ways. 1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16 filename_string(L"\\??\\"); 1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) filename_string += file_name; 1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) init_unicode_string(&path_unicode_string, filename_string.c_str()); 2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) OBJECT_ATTRIBUTES path_attributes = {}; 2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) InitializeObjectAttributes(&path_attributes, 2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) &path_unicode_string, 2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) OBJ_CASE_INSENSITIVE, 2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NULL, // No Root Directory 2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NULL); // No Security Descriptor 2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Set desired_access, and flags_and_attributes to match those 2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // set by kernel32!CreateFile. 2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) desired_access |= 0x100080; 2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) flags_and_attributes &= 0x2FFA7; 2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) result = create_file(&file_handle, 2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) desired_access, 2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) &path_attributes, 2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) &io_status_block, 2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 0, // Allocation size 2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) flags_and_attributes, 2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) share_mode, 2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) creation_disposition, 2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) flags, 2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NULL, 2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 0); 2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (result != STATUS_SUCCESS) { 2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (result == STATUS_OBJECT_NAME_COLLISION && 2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) creation_disposition == FILE_CREATE) { 2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SetLastError(ERROR_FILE_EXISTS); 2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return INVALID_HANDLE_VALUE; 2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (creation_disposition == FILE_OPEN_IF) { 2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SetLastError(io_status_block.Information == FILE_OPENED ? 2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ERROR_ALREADY_EXISTS : ERROR_SUCCESS); 2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else if (creation_disposition == FILE_OVERWRITE_IF) { 2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SetLastError(io_status_block.Information == FILE_OVERWRITTEN ? 2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ERROR_ALREADY_EXISTS : ERROR_SUCCESS); 2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else { 2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SetLastError(ERROR_SUCCESS); 2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return file_handle; 2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool IsCanary(LPWSTR exe_path) { 2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) wchar_t* found = wcsstr(exe_path, L"Google\\Chrome SxS"); 2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return !!found; 2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ShouldBypass(LPCWSTR file_path) { 2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Do not redirect in non-browser processes. 2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) wchar_t* command_line = ::GetCommandLine(); 2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (command_line && wcsstr(command_line, L"--type")) 2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // If the shell functions are not present, forward the call to kernel32. 2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!PopulateShellFunctions()) 2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Forward all UNC filepaths to kernel32. 2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (g_path_is_unc_func(file_path)) 2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) wchar_t local_appdata_path[MAX_PATH]; 2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Get the %LOCALAPPDATA% Path and append the location of our UserData 2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // directory to it. 2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) HRESULT appdata_result = g_get_folder_func( 2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NULL, CSIDL_LOCAL_APPDATA, NULL, 0, local_appdata_path); 2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) wchar_t buffer[MAX_PATH] = {}; 2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!GetModuleFileNameW(NULL, buffer, MAX_PATH)) 2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bool is_canary = IsCanary(buffer); 2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // If getting the %LOCALAPPDATA% path or appending to it failed, then forward 2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // the call to kernel32. 2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!SUCCEEDED(appdata_result) || 2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) !g_path_append_func(local_appdata_path, is_canary ? 2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) kCanaryAppDataDirName : kAppDataDirName) || 2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) !g_path_append_func(local_appdata_path, kUserDataDirName)) { 2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) LPCWSTR file_name = g_path_find_filename_func(file_path); 2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bool in_userdata_dir = !!g_path_is_prefix_func(local_appdata_path, file_path); 2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bool is_settings_file = wcscmp(file_name, kPreferencesFilename) == 0 || 2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) wcscmp(file_name, kLocalStateFilename) == 0; 2925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Check if we are trying to access the Preferences in the UserData dir. If 2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // so, then redirect the call to bypass kernel32. 2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return in_userdata_dir && is_settings_file; 2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 297