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