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"
11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chrome_elf/chrome_elf_util.h"
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome_elf/ntdll_cache.h"
1323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "sandbox/win/src/interception_internal.h"
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "sandbox/win/src/nt_internals.h"
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// From ShlObj.h in the Windows SDK.
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#define CSIDL_LOCAL_APPDATA 0x001c
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)typedef BOOL (WINAPI *PathIsUNCFunction)(
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  IN LPCWSTR path);
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)typedef BOOL (WINAPI *PathAppendFunction)(
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  IN LPWSTR path,
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  IN LPCWSTR more);
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)typedef BOOL (WINAPI *PathIsPrefixFunction)(
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  IN LPCWSTR prefix,
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  IN LPCWSTR path);
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)typedef LPCWSTR (WINAPI *PathFindFileName)(
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  IN LPCWSTR path);
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)typedef HRESULT (WINAPI *SHGetFolderPathFunction)(
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  IN HWND hwnd_owner,
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  IN int folder,
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  IN HANDLE token,
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  IN DWORD flags,
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  OUT LPWSTR path);
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)PathIsUNCFunction g_path_is_unc_func;
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)PathAppendFunction g_path_append_func;
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)PathIsPrefixFunction g_path_is_prefix_func;
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)PathFindFileName g_path_find_filename_func;
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)SHGetFolderPathFunction g_get_folder_func;
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
48a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Record the number of calls we've redirected so far.
49a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)int g_redirect_count = 0;
50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Populates the g_*_func pointers to functions which will be used in
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// ShouldBypass(). Chrome_elf cannot have a load-time dependency on shell32 or
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// shlwapi as this would induce a load-time dependency on user32.dll. Instead,
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// the addresses of the functions we need are retrieved the first time this
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// method is called, and cached to avoid subsequent calls to GetProcAddress().
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// It is assumed that the host process will never unload these functions.
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Returns true if all the functions needed are present.
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool PopulateShellFunctions() {
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Early exit if functions have already been populated.
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (g_path_is_unc_func && g_path_append_func &&
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      g_path_is_prefix_func && g_get_folder_func) {
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Get the addresses of the functions we need and store them for future use.
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // These handles are intentionally leaked to ensure that these modules do not
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // get unloaded.
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HMODULE shell32 = ::LoadLibrary(L"shell32.dll");
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HMODULE shlwapi = ::LoadLibrary(L"shlwapi.dll");
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!shlwapi || !shell32)
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  g_path_is_unc_func = reinterpret_cast<PathIsUNCFunction>(
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ::GetProcAddress(shlwapi, "PathIsUNCW"));
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  g_path_append_func = reinterpret_cast<PathAppendFunction>(
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ::GetProcAddress(shlwapi, "PathAppendW"));
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  g_path_is_prefix_func = reinterpret_cast<PathIsPrefixFunction>(
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ::GetProcAddress(shlwapi, "PathIsPrefixW"));
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  g_path_find_filename_func = reinterpret_cast<PathFindFileName>(
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ::GetProcAddress(shlwapi, "PathFindFileNameW"));
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  g_get_folder_func = reinterpret_cast<SHGetFolderPathFunction>(
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ::GetProcAddress(shell32, "SHGetFolderPathW"));
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return g_path_is_unc_func && g_path_append_func && g_path_is_prefix_func &&
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      g_path_find_filename_func && g_get_folder_func;
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Turn off optimization to make sure these calls don't get inlined.
92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#pragma optimize("", off)
93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Wrapper method for kernel32!CreateFile, to avoid setting off caller
94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// mitigation detectors.
95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)HANDLE CreateFileWImpl(LPCWSTR file_name,
96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                       DWORD desired_access,
97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                       DWORD share_mode,
98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                       LPSECURITY_ATTRIBUTES security_attributes,
99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                       DWORD creation_disposition,
100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                       DWORD flags_and_attributes,
101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                       HANDLE template_file) {
102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return CreateFile(file_name,
103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                    desired_access,
104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                    share_mode,
105a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                    security_attributes,
106a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                    creation_disposition,
107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                    flags_and_attributes,
108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                    template_file);
109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)HANDLE WINAPI CreateFileWRedirect(
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LPCWSTR file_name,
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DWORD desired_access,
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DWORD share_mode,
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LPSECURITY_ATTRIBUTES security_attributes,
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DWORD creation_disposition,
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DWORD flags_and_attributes,
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    HANDLE template_file) {
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (ShouldBypass(file_name)) {
121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    ++g_redirect_count;
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return CreateFileNTDLL(file_name,
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           desired_access,
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           share_mode,
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           security_attributes,
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           creation_disposition,
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           flags_and_attributes,
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           template_file);
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
130a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return CreateFileWImpl(file_name,
131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                         desired_access,
132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                         share_mode,
133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                         security_attributes,
134a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                         creation_disposition,
135a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                         flags_and_attributes,
136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                         template_file);
137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#pragma optimize("", on)
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
140a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)int GetRedirectCount() {
141a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return g_redirect_count;
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)HANDLE CreateFileNTDLL(
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LPCWSTR file_name,
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DWORD desired_access,
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DWORD share_mode,
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LPSECURITY_ATTRIBUTES security_attributes,
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DWORD creation_disposition,
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DWORD flags_and_attributes,
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    HANDLE template_file) {
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HANDLE file_handle = INVALID_HANDLE_VALUE;
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NTSTATUS result = STATUS_UNSUCCESSFUL;
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  IO_STATUS_BLOCK io_status_block = {};
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ULONG flags = 0;
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Convert from Win32 domain to to NT creation disposition values.
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  switch (creation_disposition) {
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case CREATE_NEW:
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      creation_disposition = FILE_CREATE;
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case CREATE_ALWAYS:
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      creation_disposition = FILE_OVERWRITE_IF;
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case OPEN_EXISTING:
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      creation_disposition = FILE_OPEN;
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case OPEN_ALWAYS:
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      creation_disposition = FILE_OPEN_IF;
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case TRUNCATE_EXISTING:
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      creation_disposition = FILE_OVERWRITE;
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    default:
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      SetLastError(ERROR_INVALID_PARAMETER);
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return INVALID_HANDLE_VALUE;
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Translate the flags that need no validation:
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!(flags_and_attributes & FILE_FLAG_OVERLAPPED))
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    flags |= FILE_SYNCHRONOUS_IO_NONALERT;
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (flags_and_attributes & FILE_FLAG_WRITE_THROUGH)
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    flags |= FILE_WRITE_THROUGH;
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (flags_and_attributes & FILE_FLAG_RANDOM_ACCESS)
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    flags |= FILE_RANDOM_ACCESS;
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (flags_and_attributes & FILE_FLAG_SEQUENTIAL_SCAN)
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    flags |= FILE_SEQUENTIAL_ONLY;
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (flags_and_attributes & FILE_FLAG_DELETE_ON_CLOSE) {
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    flags |= FILE_DELETE_ON_CLOSE;
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    desired_access |= DELETE;
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (flags_and_attributes & FILE_FLAG_BACKUP_SEMANTICS)
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    flags |= FILE_OPEN_FOR_BACKUP_INTENT;
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  else
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    flags |= FILE_NON_DIRECTORY_FILE;
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (flags_and_attributes & FILE_FLAG_OPEN_REPARSE_POINT)
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    flags |= FILE_OPEN_REPARSE_POINT;
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (flags_and_attributes & FILE_FLAG_OPEN_NO_RECALL)
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    flags |= FILE_OPEN_NO_RECALL;
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
20923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (!g_ntdll_lookup["RtlInitUnicodeString"])
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return INVALID_HANDLE_VALUE;
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
21223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  NtCreateFileFunction create_file;
21323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  char thunk_buffer[sizeof(sandbox::ThunkData)] = {};
21423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
21523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (g_nt_thunk_storage.data[0] != 0) {
21623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    create_file = reinterpret_cast<NtCreateFileFunction>(&g_nt_thunk_storage);
21723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    // Copy the thunk data to a buffer on the stack for debugging purposes.
21823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    memcpy(&thunk_buffer, &g_nt_thunk_storage, sizeof(sandbox::ThunkData));
21923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  } else if (g_ntdll_lookup["NtCreateFile"]) {
22023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    create_file =
22123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        reinterpret_cast<NtCreateFileFunction>(g_ntdll_lookup["NtCreateFile"]);
22223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  } else {
22323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return INVALID_HANDLE_VALUE;
22423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RtlInitUnicodeStringFunction init_unicode_string =
2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      reinterpret_cast<RtlInitUnicodeStringFunction>(
2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          g_ntdll_lookup["RtlInitUnicodeString"]);
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UNICODE_STRING path_unicode_string;
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Format the path into an NT path. Arguably this should be done with
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // RtlDosPathNameToNtPathName_U, but afaict this is equivalent for
2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // local paths. Using this with a UNC path name will almost certainly
2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // break in interesting ways.
2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 filename_string(L"\\??\\");
2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  filename_string += file_name;
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  init_unicode_string(&path_unicode_string, filename_string.c_str());
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  OBJECT_ATTRIBUTES path_attributes = {};
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  InitializeObjectAttributes(&path_attributes,
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             &path_unicode_string,
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             OBJ_CASE_INSENSITIVE,
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             NULL,   // No Root Directory
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             NULL);  // No Security Descriptor
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Set desired_access, and flags_and_attributes to match those
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // set by kernel32!CreateFile.
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  desired_access |= 0x100080;
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  flags_and_attributes &= 0x2FFA7;
2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  result = create_file(&file_handle,
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                       desired_access,
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                       &path_attributes,
2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                       &io_status_block,
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                       0,  // Allocation size
2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                       flags_and_attributes,
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                       share_mode,
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                       creation_disposition,
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                       flags,
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                       NULL,
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                       0);
2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (result != STATUS_SUCCESS) {
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (result == STATUS_OBJECT_NAME_COLLISION &&
2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        creation_disposition == FILE_CREATE) {
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      SetLastError(ERROR_FILE_EXISTS);
2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return INVALID_HANDLE_VALUE;
2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (creation_disposition == FILE_OPEN_IF) {
2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SetLastError(io_status_block.Information == FILE_OPENED ?
2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        ERROR_ALREADY_EXISTS : ERROR_SUCCESS);
2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else if (creation_disposition == FILE_OVERWRITE_IF) {
2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SetLastError(io_status_block.Information == FILE_OVERWRITTEN ?
2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        ERROR_ALREADY_EXISTS : ERROR_SUCCESS);
2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SetLastError(ERROR_SUCCESS);
2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return file_handle;
2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ShouldBypass(LPCWSTR file_path) {
2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Do not redirect in non-browser processes.
288a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (IsNonBrowserProcess())
2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // If the shell functions are not present, forward the call to kernel32.
2925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!PopulateShellFunctions())
2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Forward all UNC filepaths to kernel32.
2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (g_path_is_unc_func(file_path))
2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  wchar_t local_appdata_path[MAX_PATH];
3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Get the %LOCALAPPDATA% Path and append the location of our UserData
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // directory to it.
3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HRESULT appdata_result = g_get_folder_func(
3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NULL, CSIDL_LOCAL_APPDATA, NULL, 0, local_appdata_path);
3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  wchar_t buffer[MAX_PATH] = {};
3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!GetModuleFileNameW(NULL, buffer, MAX_PATH))
3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool is_canary = IsCanary(buffer);
3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // If getting the %LOCALAPPDATA% path or appending to it failed, then forward
3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // the call to kernel32.
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!SUCCEEDED(appdata_result) ||
3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      !g_path_append_func(local_appdata_path, is_canary ?
3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kCanaryAppDataDirName : kAppDataDirName) ||
3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      !g_path_append_func(local_appdata_path, kUserDataDirName)) {
3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LPCWSTR file_name = g_path_find_filename_func(file_path);
3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool in_userdata_dir = !!g_path_is_prefix_func(local_appdata_path, file_path);
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool is_settings_file = wcscmp(file_name, kPreferencesFilename) == 0 ||
3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      wcscmp(file_name, kLocalStateFilename) == 0;
3265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Check if we are trying to access the Preferences in the UserData dir. If
3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // so, then redirect the call to bypass kernel32.
3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return in_userdata_dir && is_settings_file;
3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
331