1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_COMMON_CONFLICTS_MODULE_WATCHER_WIN_H_
#define CHROME_COMMON_CONFLICTS_MODULE_WATCHER_WIN_H_
#include <memory>
#include "base/files/file_path.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/task/sequenced_task_runner.h"
class ModuleWatcherTest;
union LDR_DLL_NOTIFICATION_DATA;
// This class observes modules as they are loaded into a process's address
// space.
//
// This class is safe to be created on any thread. Similarly, it is safe to be
// destroyed on any thread, independent of the thread on which the instance was
// created.
class ModuleWatcher {
public:
// The types of module events that can occur.
enum class ModuleEventType {
// A module was already loaded, but its presence is being observed.
kModuleAlreadyLoaded,
// A module is in the process of being loaded.
kModuleLoaded,
};
// Houses information about a module event, and some module metadata.
struct ModuleEvent {
ModuleEvent() = default;
ModuleEvent(const ModuleEvent& other) = default;
ModuleEvent(ModuleEventType event_type,
const base::FilePath& module_path,
void* module_load_address,
size_t module_size)
: event_type(event_type),
module_path(module_path),
module_load_address(module_load_address),
module_size(module_size) {}
// The type of module event.
ModuleEventType event_type;
// The full path to the module on disk.
base::FilePath module_path;
// The load address of the module. Careful consideration must be made before
// accessing memory at this address. See the comment for
// OnModuleEventCallback.
raw_ptr<void> module_load_address;
// The size of the module in memory.
size_t module_size;
};
// The type of callback that will be invoked for each module event. This
// callback may be run from any thread in the process, and may be invoked
// during initialization (while iterating over already loaded modules) or in
// response to LdrDllNotifications received from the loader. As such, keep the
// amount of work performed here to an absolute minimum.
//
// MODULE_LOADED events are always dispatched directly from the loader while
// under the loader's lock, so the module is guaranteed to be loaded in memory
// (it is safe to access module_load_address).
//
// If the event is of type MODULE_ALREADY_LOADED, then the module data comes
// from a snapshot and it is possible that its |module_load_address| is
// invalid by the time the event is sent.
//
// Note that it is possible for this callback to be invoked after the
// destruction of the watcher.
using OnModuleEventCallback =
base::RepeatingCallback<void(const ModuleEvent& event)>;
// Creates and starts a watcher. This enumerates all loaded modules
// synchronously on the current thread during construction, and provides
// synchronous notifications as modules are loaded. The callback is invoked in
// the context of the thread that is loading a module, and as such may be
// invoked on any thread in the process. Note that it is possible to receive
// two notifications for some modules as the initial loaded module enumeration
// races briefly with the callback mechanism. In this case both a
// MODULE_LOADED and a MODULE_ALREADY_LOADED event will be received for the
// same module. Since the callback is installed first no modules can be
// missed, however. This factory function may be called on any thread.
//
// Only a single instance of a watcher may exist at any moment. This will
// return nullptr when trying to create a second watcher.
static std::unique_ptr<ModuleWatcher> Create(OnModuleEventCallback callback);
ModuleWatcher(const ModuleWatcher&) = delete;
ModuleWatcher& operator=(const ModuleWatcher&) = delete;
// This can be called on any thread. After destruction the |callback|
// provided to the constructor will no longer be invoked with module events.
~ModuleWatcher();
private:
// For unittesting.
friend class ModuleWatcherTest;
// Private to enforce Singleton semantics. See Create above.
ModuleWatcher();
// Initializes the ModuleWatcher instance.
void Initialize(OnModuleEventCallback callback);
// Registers a DllNotification callback with the OS. Modifies
// |dll_notification_cookie_|. Can be called on any thread.
void RegisterDllNotificationCallback();
// Removes the installed DllNotification callback. Modifies
// |dll_notification_cookie_|. Can be called on any thread.
void UnregisterDllNotificationCallback();
// Enumerates all currently loaded modules, synchronously invoking callbacks
// on the current thread. Can be called on any thread.
static void EnumerateAlreadyLoadedModules(
scoped_refptr<base::SequencedTaskRunner> task_runner,
OnModuleEventCallback callback);
// Helper function for retrieving the callback associated with a given
// LdrNotification context.
static OnModuleEventCallback GetCallbackForContext(void* context);
// The loader notification callback. This is actually
// void CALLBACK LoaderNotificationCallback(
// DWORD, const LDR_DLL_NOTIFICATION_DATA*, PVOID)
// Not using CALLBACK/DWORD/PVOID allows skipping the windows.h header from
// this file.
static void __stdcall LoaderNotificationCallback(
unsigned long notification_reason,
const LDR_DLL_NOTIFICATION_DATA* notification_data,
void* context);
// Used to bind the |callback_| to a WeakPtr.
void RunCallback(const ModuleEvent& event);
// The current callback. Can end up being invoked on any thread.
OnModuleEventCallback callback_;
// Used by the DllNotification mechanism.
raw_ptr<void> dll_notification_cookie_ = nullptr;
base::WeakPtrFactory<ModuleWatcher> weak_ptr_factory_{this};
};
#endif // CHROME_COMMON_CONFLICTS_MODULE_WATCHER_WIN_H_
|