1 // Copyright 2018 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/chrome_cleaner/os/scoped_disable_wow64_redirection.h"
6 
7 #include "base/files/file_path.h"
8 #include "base/lazy_instance.h"
9 #include "base/logging.h"
10 #include "base/scoped_native_library.h"
11 
12 namespace chrome_cleaner {
13 namespace {
14 
15 // A helper class encapsulating run-time-linked function calls to Wow64 APIs.
16 class Wow64Functions {
17  public:
Wow64Functions()18   Wow64Functions()
19       : kernel32_lib_(base::FilePath(L"kernel32")),
20         is_wow_64_process_(nullptr),
21         wow_64_disable_wow_64_fs_redirection_(nullptr),
22         wow_64_revert_wow_64_fs_redirection_(nullptr) {
23     if (kernel32_lib_.is_valid()) {
24       is_wow_64_process_ = reinterpret_cast<IsWow64Process>(
25           kernel32_lib_.GetFunctionPointer("IsWow64Process"));
26       wow_64_disable_wow_64_fs_redirection_ =
27           reinterpret_cast<Wow64DisableWow64FSRedirection>(
28               kernel32_lib_.GetFunctionPointer(
29                   "Wow64DisableWow64FsRedirection"));
30       wow_64_revert_wow_64_fs_redirection_ =
31           reinterpret_cast<Wow64RevertWow64FSRedirection>(
32               kernel32_lib_.GetFunctionPointer(
33                   "Wow64RevertWow64FsRedirection"));
34     } else {
35       PLOG(ERROR) << "Cannot open library 'kernel32'.";
36     }
37   }
38 
is_valid() const39   bool is_valid() const {
40     return is_wow_64_process_ && wow_64_disable_wow_64_fs_redirection_ &&
41            wow_64_revert_wow_64_fs_redirection_;
42   }
43 
IsWow64() const44   bool IsWow64() const {
45     BOOL result = 0;
46     if (!is_wow_64_process_(GetCurrentProcess(), &result))
47       PLOG(WARNING) << "IsWow64Process";
48     return !!result;
49   }
50 
DisableFsRedirection(PVOID * previous_state)51   bool DisableFsRedirection(PVOID* previous_state) {
52     return !!wow_64_disable_wow_64_fs_redirection_(previous_state);
53   }
54 
RevertFsRedirection(PVOID previous_state)55   bool RevertFsRedirection(PVOID previous_state) {
56     return !!wow_64_revert_wow_64_fs_redirection_(previous_state);
57   }
58 
59  private:
60   typedef BOOL(WINAPI* IsWow64Process)(HANDLE, PBOOL);
61   typedef BOOL(WINAPI* Wow64DisableWow64FSRedirection)(PVOID*);
62   typedef BOOL(WINAPI* Wow64RevertWow64FSRedirection)(PVOID);
63 
64   base::ScopedNativeLibrary kernel32_lib_;
65 
66   IsWow64Process is_wow_64_process_;
67   Wow64DisableWow64FSRedirection wow_64_disable_wow_64_fs_redirection_;
68   Wow64RevertWow64FSRedirection wow_64_revert_wow_64_fs_redirection_;
69 
70   DISALLOW_COPY_AND_ASSIGN(Wow64Functions);
71 };
72 
73 // Global Wow64Function instance used by ScopedDisableWow64Redirection below.
74 base::LazyInstance<Wow64Functions>::Leaky g_wow_64_functions =
75     LAZY_INSTANCE_INITIALIZER;
76 
77 }  // namespace
78 
ScopedDisableWow64Redirection()79 ScopedDisableWow64Redirection::ScopedDisableWow64Redirection()
80     : active_(false), previous_state_(nullptr) {
81   Wow64Functions* wow64 = g_wow_64_functions.Pointer();
82   if (wow64->is_valid() && wow64->IsWow64()) {
83     if (wow64->DisableFsRedirection(&previous_state_))
84       active_ = true;
85     else
86       PLOG(WARNING) << "Wow64DisableWow64FSRedirection";
87   }
88 }
89 
~ScopedDisableWow64Redirection()90 ScopedDisableWow64Redirection::~ScopedDisableWow64Redirection() {
91   if (active_) {
92     // The Wow64 redirection needs to be reverted. In case of a failure, the
93     // process is in an invalid state where every access to the system folder
94     // will occurs to the wrong folder. This is unlikely to happen.
95     CHECK(g_wow_64_functions.Get().RevertFsRedirection(previous_state_));
96   }
97 }
98 
99 }  // namespace chrome_cleaner
100