typedef HRESULT WINAPI (GetThreadDescription_ftype) (HANDLE, PWSTR *);
static GetThreadDescription_ftype *GetThreadDescription;
+InitializeProcThreadAttributeList_ftype *InitializeProcThreadAttributeList;
+UpdateProcThreadAttribute_ftype *UpdateProcThreadAttribute;
+DeleteProcThreadAttributeList_ftype *DeleteProcThreadAttributeList;
+
/* Note that 'debug_events' must be locally defined in the relevant
functions. */
#define DEBUG_EVENTS(fmt, ...) \
return result;
}
-/* Helper template for the CreateProcess wrappers. */
+/* Flags to pass to UpdateProcThreadAttribute. */
+#define relocate_aslr_flags ((0x2 << 8) | (0x2 << 16))
+
+/* Attribute to pass to UpdateProcThreadAttribute. */
+#define mitigation_policy 0x00020007
+
+/* Pick one of the symbols as a sentinel. */
+#ifdef PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_OFF
+
+static_assert ((PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_OFF
+ | PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_ALWAYS_OFF)
+ == relocate_aslr_flags,
+ "check that ASLR flag values are correct");
+
+static_assert (PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY == mitigation_policy,
+ "check that mitigation policy value is correct");
+
+#endif
+
+/* Helper template for the CreateProcess wrappers.
+
+ FUNC is the type of the underlying CreateProcess call. CHAR is the
+ character type to use, and INFO is the "startupinfo" type to use.
+
+ DO_CREATE_PROCESS is the underlying CreateProcess function to use;
+ the remaining arguments are passed to it. */
template<typename FUNC, typename CHAR, typename INFO>
BOOL
create_process_wrapper (FUNC *do_create_process, const CHAR *image,
CHAR *command_line, DWORD flags,
void *environment, const CHAR *cur_dir,
+ bool no_randomization,
INFO *startup_info,
PROCESS_INFORMATION *process_info)
{
+ if (no_randomization && disable_randomization_available ())
+ {
+ static bool tried_and_failed;
+
+ if (!tried_and_failed)
+ {
+ /* Windows 8 is required for the real declaration, but to
+ allow building on earlier versions of Windows, we declare
+ the type locally. */
+ struct gdb_extended_info
+ {
+ INFO StartupInfo;
+ gdb_lpproc_thread_attribute_list lpAttributeList;
+ };
+
+ gdb_extended_info info_ex {};
+
+ if (startup_info != nullptr)
+ info_ex.StartupInfo = *startup_info;
+ info_ex.StartupInfo.cb = sizeof (info_ex);
+ SIZE_T size = 0;
+ /* Ignore the result here. The documentation says the first
+ call always fails, by design. */
+ InitializeProcThreadAttributeList (nullptr, 1, 0, &size);
+ info_ex.lpAttributeList
+ = (PPROC_THREAD_ATTRIBUTE_LIST) alloca (size);
+ InitializeProcThreadAttributeList (info_ex.lpAttributeList,
+ 1, 0, &size);
+
+ gdb::optional<BOOL> return_value;
+ DWORD attr_flags = relocate_aslr_flags;
+ if (!UpdateProcThreadAttribute (info_ex.lpAttributeList, 0,
+ mitigation_policy,
+ &attr_flags,
+ sizeof (attr_flags),
+ nullptr, nullptr))
+ tried_and_failed = true;
+ else
+ {
+ BOOL result = do_create_process (image, command_line,
+ nullptr, nullptr,
+ TRUE,
+ (flags
+ | EXTENDED_STARTUPINFO_PRESENT),
+ environment,
+ cur_dir,
+ (STARTUPINFO *) &info_ex,
+ process_info);
+ if (result)
+ return_value = result;
+ else if (GetLastError () == ERROR_INVALID_PARAMETER)
+ tried_and_failed = true;
+ else
+ return_value = FALSE;
+ }
+
+ DeleteProcThreadAttributeList (info_ex.lpAttributeList);
+
+ if (return_value.has_value ())
+ return *return_value;
+ }
+ }
+
return do_create_process (image,
command_line, /* command line */
nullptr, /* Security */
BOOL
create_process (const char *image, char *command_line, DWORD flags,
void *environment, const char *cur_dir,
+ bool no_randomization,
STARTUPINFOA *startup_info,
PROCESS_INFORMATION *process_info)
{
return create_process_wrapper (CreateProcessA, image, command_line, flags,
- environment, cur_dir,
+ environment, cur_dir, no_randomization,
startup_info, process_info);
}
BOOL
create_process (const wchar_t *image, wchar_t *command_line, DWORD flags,
void *environment, const wchar_t *cur_dir,
+ bool no_randomization,
STARTUPINFOW *startup_info,
PROCESS_INFORMATION *process_info);
{
return create_process_wrapper (CreateProcessW, image, command_line, flags,
- environment, cur_dir,
+ environment, cur_dir, no_randomization,
startup_info, process_info);
}
/* See windows-nat.h. */
+bool
+disable_randomization_available ()
+{
+ return (InitializeProcThreadAttributeList != nullptr
+ && UpdateProcThreadAttribute != nullptr
+ && DeleteProcThreadAttributeList != nullptr);
+}
+
+/* See windows-nat.h. */
+
bool
initialize_loadable ()
{
#endif
GPA (hm, GenerateConsoleCtrlEvent);
GPA (hm, GetThreadDescription);
+
+ GPA (hm, InitializeProcThreadAttributeList);
+ GPA (hm, UpdateProcThreadAttribute);
+ GPA (hm, DeleteProcThreadAttributeList);
}
/* Set variables to dummy versions of these processes if the function
extern BOOL wait_for_debug_event (DEBUG_EVENT *event, DWORD timeout);
-/* Wrappers for CreateProcess. */
+/* Wrappers for CreateProcess. These exist primarily so that the
+ "disable randomization" feature can be implemented in a single
+ place. */
extern BOOL create_process (const char *image, char *command_line,
DWORD flags, void *environment,
const char *cur_dir,
+ bool no_randomization,
STARTUPINFOA *startup_info,
PROCESS_INFORMATION *process_info);
#ifdef __CYGWIN__
extern BOOL create_process (const wchar_t *image, wchar_t *command_line,
DWORD flags, void *environment,
const wchar_t *cur_dir,
+ bool no_randomization,
STARTUPINFOW *startup_info,
PROCESS_INFORMATION *process_info);
#endif /* __CYGWIN__ */
#define DebugActiveProcessStop dyn_DebugActiveProcessStop
#define DebugBreakProcess dyn_DebugBreakProcess
#define DebugSetProcessKillOnExit dyn_DebugSetProcessKillOnExit
+#undef EnumProcessModules
#define EnumProcessModules dyn_EnumProcessModules
+#undef EnumProcessModulesEx
#define EnumProcessModulesEx dyn_EnumProcessModulesEx
+#undef GetModuleInformation
#define GetModuleInformation dyn_GetModuleInformation
+#undef GetModuleFileNameExA
#define GetModuleFileNameExA dyn_GetModuleFileNameExA
+#undef GetModuleFileNameExW
#define GetModuleFileNameExW dyn_GetModuleFileNameExW
#define LookupPrivilegeValueA dyn_LookupPrivilegeValueA
#define OpenProcessToken dyn_OpenProcessToken
#define Wow64SetThreadContext dyn_Wow64SetThreadContext
#define Wow64GetThreadSelectorEntry dyn_Wow64GetThreadSelectorEntry
#define GenerateConsoleCtrlEvent dyn_GenerateConsoleCtrlEvent
+#define InitializeProcThreadAttributeList dyn_InitializeProcThreadAttributeList
+#define UpdateProcThreadAttribute dyn_UpdateProcThreadAttribute
+#define DeleteProcThreadAttributeList dyn_DeleteProcThreadAttributeList
typedef BOOL WINAPI (AdjustTokenPrivileges_ftype) (HANDLE, BOOL,
PTOKEN_PRIVILEGES,
typedef BOOL WINAPI (GenerateConsoleCtrlEvent_ftype) (DWORD, DWORD);
extern GenerateConsoleCtrlEvent_ftype *GenerateConsoleCtrlEvent;
+/* We use a local typedef for this type to avoid depending on
+ Windows 8. */
+typedef void *gdb_lpproc_thread_attribute_list;
+
+typedef BOOL WINAPI (InitializeProcThreadAttributeList_ftype)
+ (gdb_lpproc_thread_attribute_list lpAttributeList,
+ DWORD dwAttributeCount, DWORD dwFlags, PSIZE_T lpSize);
+extern InitializeProcThreadAttributeList_ftype *InitializeProcThreadAttributeList;
+
+typedef BOOL WINAPI (UpdateProcThreadAttribute_ftype)
+ (gdb_lpproc_thread_attribute_list lpAttributeList,
+ DWORD dwFlags, DWORD_PTR Attribute, PVOID lpValue, SIZE_T cbSize,
+ PVOID lpPreviousValue, PSIZE_T lpReturnSize);
+extern UpdateProcThreadAttribute_ftype *UpdateProcThreadAttribute;
+
+typedef void WINAPI (DeleteProcThreadAttributeList_ftype)
+ (gdb_lpproc_thread_attribute_list lpAttributeList);
+extern DeleteProcThreadAttributeList_ftype *DeleteProcThreadAttributeList;
+
+/* Return true if it's possible to disable randomization on this
+ host. */
+
+extern bool disable_randomization_available ();
+
/* Load any functions which may not be available in ancient versions
of Windows. */