blob: 664b8333d13a6047345bae2e89305a6c293221b6 [file] [edit]
/* **********************************************************
* Copyright (c) 2011-2017 Google, Inc. All rights reserved.
* Copyright (c) 2007-2010 VMware, Inc. All rights reserved.
* **********************************************************/
/* Dr. Memory: the memory debugger
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License, and no later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "dr_api.h"
#include "drmemory.h"
#include "syscall.h"
#include "syscall_os.h"
#include "syscall_windows.h"
#include "slowpath.h"
#include "frontend.h"
#include <stddef.h> /* offsetof */
#include "handlecheck.h"
#include "drsyscall.h"
#include "../wininc/ndk_dbgktypes.h"
#include "../wininc/ndk_iotypes.h"
#include "../wininc/ndk_extypes.h"
#include "../wininc/afd_shared.h"
#include "../wininc/msafdlib.h"
#include "../wininc/winioctl.h"
#include "../wininc/tcpioctl.h"
#include "../wininc/iptypes_undocumented.h"
#include "../wininc/ntalpctyp.h"
static int
syscall_handle_type(drsys_syscall_type_t drsys_type, drsys_sysnum_t sysnum);
/***************************************************************************
* SYSTEM CALLS FOR WINDOWS
*/
/* Syscalls that need special processing. The address of each is kept
* in the syscall_info_t entry so we don't need separate lookup.
*/
static drsys_sysnum_t sysnum_CreateThread = {-1,0};
static drsys_sysnum_t sysnum_CreateThreadEx = {-1,0};
/* For handle leak checking */
static drsys_sysnum_t sysnum_Close = {-1,0};
static drsys_sysnum_t sysnum_UserDestroyAcceleratorTable = {-1,0};
static drsys_sysnum_t sysnum_UserDestroyCursor = {-1,0};
static drsys_sysnum_t sysnum_UserDestroyInputContext = {-1,0};
static drsys_sysnum_t sysnum_UserDestroyMenu = {-1,0};
static drsys_sysnum_t sysnum_UserDestroyWindow = {-1,0};
static drsys_sysnum_t sysnum_UserReleaseDC = {-1,0};
static drsys_sysnum_t sysnum_GdiDeleteObjectApp = {-1,0};
static drsys_sysnum_t sysnum_GdiDeleteColorSpace = {-1,0};
static drsys_sysnum_t sysnum_GdiDeleteColorTransform = {-1,0};
static drsys_sysnum_t sysnum_GdiDeleteClientObj = {-1,0};
static drsys_sysnum_t sysnum_GdiDdReleaseDC= {-1, 0};
/* i#1112: NtDuplicateObject may delete a handle */
static drsys_sysnum_t sysnum_DuplicateObject = {-1, 0};
/* i#988: system calls that return existing handles */
static drsys_sysnum_t sysnum_UserSetClipboardData = {-1, 0};
static drsys_sysnum_t sysnum_UserRemoveProp = {-1, 0};
static drsys_sysnum_t sysnum_UserFindExistingCursorIcon = {-1, 0};
static drsys_sysnum_t sysnum_UserGetThreadDesktop = {-1, 0};
static drsys_sysnum_t sysnum_GetThreadDesktop = {-1, 0}; /* i#487 */
static drsys_sysnum_t sysnum_UserGetAncestor = {-1, 0};
static drsys_sysnum_t sysnum_GdiExtSelectClipRgn = {-1, 0};
static drsys_sysnum_t sysnum_GdiSelectBrush = {-1, 0};
static drsys_sysnum_t sysnum_GdiSelectPen = {-1, 0};
static drsys_sysnum_t sysnum_GdiSelectBitmap = {-1, 0};
static drsys_sysnum_t sysnum_GdiSelectFont = {-1, 0};
/* i#1386: mismatch between system call type and handle type */
/* syscall added above:
* sysnum_UserReleaseDC
* sysnum_UserGetThreadDesktop
*/
/* To support handle usage check in the future, we may want to record
* the type information of an handle used as a syscall argument,
* e.g., the user syscall NtUserCloseWindowStation takes in kernel handle.
*/
static drsys_sysnum_t sysnum_UserGetDC = {-1, 0};
static drsys_sysnum_t sysnum_UserGetProcessWindowStation = {-1, 0};
static drsys_sysnum_t sysnum_UserCreateWindowStation = {-1, 0};
static drsys_sysnum_t sysnum_UserOpenWindowStation = {-1, 0};
static drsys_sysnum_t sysnum_UserCloseWindowStation = {-1, 0};
static drsys_sysnum_t sysnum_UserGetWindowDC = {-1, 0};
static drsys_sysnum_t sysnum_UserCloseDesktop = {-1, 0};
static drsys_sysnum_t sysnum_UserCreateDesktop = {-1, 0};
static drsys_sysnum_t sysnum_UserCreateDesktopEx = {-1, 0};
static drsys_sysnum_t sysnum_UserOpenDesktop = {-1, 0};
static drsys_sysnum_t sysnum_UserOpenInputDesktop = {-1, 0};
static drsys_sysnum_t sysnum_UserOpenThreadDesktop = {-1, 0};
static bool
opc_is_in_syscall_wrapper(uint opc)
{
return (opc == OP_mov_imm || opc == OP_lea || opc == OP_xor /*wow64*/ ||
opc == OP_int || opc == OP_call_ind ||
/* 64-bit Windows:
* ntdll!NtMapViewOfSection:
* 77941590 4c8bd1 mov r10,rcx
* 77941593 b825000000 mov eax,25h
* 77941598 0f05 syscall
*/
/* 64-bit Windows 10 TH2 has a jne:
* 00007ff8`34e763c8 f604250803fe7f01 test byte ptr [SharedUserData+0x308 (00000000`7ffe0308)],1
* 00007ff8`34e763d0 7503 jne ntdll!NtAllocateVirtualMemory+0x15 (00007ff8`34e763d5)
* 00007ff8`34e763d2 0f05 syscall
* 00007ff8`34e763d4 c3 ret
* 00007ff8`34e763d5 cd2e int 2Eh
* 00007ff8`34e763d7 c3 ret
*/
IF_X64(opc == OP_mov_ld || opc == OP_test || opc == OP_jne_short ||)
/* w/ DR Ki hooks before dr_init we have to walk over the
* native_exec_syscall hooks */
opc == OP_jmp);
}
/* takes in any Nt syscall wrapper entry point */
byte *
vsyscall_pc(void *drcontext, byte *entry)
{
byte *vpc = NULL;
byte *pc = entry;
uint opc;
instr_t instr;
ASSERT(entry != NULL, "invalid entry");
instr_init(drcontext, &instr);
do {
instr_reset(drcontext, &instr);
pc = decode(drcontext, pc, &instr);
ASSERT(instr_valid(&instr), "unknown system call sequence");
opc = instr_get_opcode(&instr);
/* stop at call to vsyscall, at syscall instruction itself,
* or at Windows8+ co-located sysenter callee (i#1367)
*/
if (opc == OP_call_ind || opc == OP_call || instr_is_syscall(&instr))
break;
ASSERT(opc_is_in_syscall_wrapper(opc), "unknown system call sequence");
/* safety check: should only get 11 or 12 bytes in */
if (pc - entry > 20) {
ASSERT(false, "unknown system call sequence");
instr_free(drcontext, &instr);
return NULL;
}
if (opc == OP_mov_imm && opnd_is_reg(instr_get_dst(&instr, 0)) &&
opnd_get_reg(instr_get_dst(&instr, 0)) == REG_EDX &&
/* win10 wow64 also has call* edx: exclude it */
!is_wow64_process()) {
ASSERT(opnd_is_immed_int(instr_get_src(&instr, 0)), "internal error");
vpc = (byte *) opnd_get_immed_int(instr_get_src(&instr, 0));
}
/* stop at call to vsyscall or at int/sysenter/syscall itself */
} while (true);
/* vpc should only exist if have call* */
ASSERT(vpc == NULL || opc == OP_call_ind, "internal error");
instr_free(drcontext, &instr);
return vpc;
}
void
syscall_os_init(void *drcontext, app_pc ntdll_base)
{
get_sysnum("NtCreateThread", &sysnum_CreateThread, false/*reqd*/);
get_sysnum("NtCreateThreadEx", &sysnum_CreateThreadEx,
get_windows_version() <= DR_WINDOWS_VERSION_2003);
get_sysnum("NtClose", &sysnum_Close, false/*reqd*/);
get_sysnum("NtUserDestroyAcceleratorTable",
&sysnum_UserDestroyAcceleratorTable,
get_windows_version() <= DR_WINDOWS_VERSION_2000);
get_sysnum("NtUserDestroyCursor", &sysnum_UserDestroyCursor,
get_windows_version() <= DR_WINDOWS_VERSION_2000);
get_sysnum("NtUserDestroyInputContext", &sysnum_UserDestroyInputContext,
false/*reqd*/);
get_sysnum("NtUserDestroyMenu", &sysnum_UserDestroyMenu, false/*reqd*/);
get_sysnum("NtUserDestroyWindow", &sysnum_UserDestroyWindow, false/*reqd*/);
if (!get_sysnum("NtUserCallOneParam.RELEASEDC",
&sysnum_UserReleaseDC,
get_windows_version() <= DR_WINDOWS_VERSION_2000 ||
get_windows_version() > DR_WINDOWS_VERSION_10_1703)) {
get_sysnum("NtUserReleaseDC", &sysnum_UserReleaseDC,
get_windows_version() <= DR_WINDOWS_VERSION_10_1703);
}
get_sysnum("NtGdiDeleteObjectApp", &sysnum_GdiDeleteObjectApp,
get_windows_version() <= DR_WINDOWS_VERSION_2000);
get_sysnum("NtGdiDeleteColorSpace", &sysnum_GdiDeleteColorSpace,
get_windows_version() <= DR_WINDOWS_VERSION_2000);
get_sysnum("NtGdiDeleteColorTransform", &sysnum_GdiDeleteColorTransform,
get_windows_version() <= DR_WINDOWS_VERSION_2000);
get_sysnum("NtGdiDeleteClientObj", &sysnum_GdiDeleteClientObj,
get_windows_version() <= DR_WINDOWS_VERSION_2000);
get_sysnum("NtGdiDdReleaseDC", &sysnum_GdiDdReleaseDC,
get_windows_version() <= DR_WINDOWS_VERSION_2000);
get_sysnum("NtDuplicateObject", &sysnum_DuplicateObject, false/*reqd*/);
/* i#988: system calls that return existing handles */
get_sysnum("NtUserSetClipboardData", &sysnum_UserSetClipboardData,
get_windows_version() <= DR_WINDOWS_VERSION_2000);
get_sysnum("NtUserRemoveProp", &sysnum_UserRemoveProp,
get_windows_version() <= DR_WINDOWS_VERSION_2000);
get_sysnum("NtUserFindExistingCursorIcon",
&sysnum_UserFindExistingCursorIcon,
get_windows_version() <= DR_WINDOWS_VERSION_2000);
get_sysnum("NtUserGetThreadDesktop", &sysnum_UserGetThreadDesktop,
get_windows_version() <= DR_WINDOWS_VERSION_2000);
get_sysnum("GetThreadDesktop", &sysnum_GetThreadDesktop, true/*ok to fail*/);
get_sysnum("NtUserGetAncestor", &sysnum_UserGetAncestor, false/*reqd*/);
get_sysnum("NtGdiExtSelectClipRgn", &sysnum_GdiExtSelectClipRgn,
get_windows_version() <= DR_WINDOWS_VERSION_2000);
get_sysnum("NtGdiSelectBrush", &sysnum_GdiSelectBrush, true/*ok to fail*/);
get_sysnum("NtGdiSelectPen", &sysnum_GdiSelectPen,
get_windows_version() <= DR_WINDOWS_VERSION_2000);
get_sysnum("NtGdiSelectBitmap", &sysnum_GdiSelectBitmap,
get_windows_version() <= DR_WINDOWS_VERSION_2000);
get_sysnum("NtGdiSelectFont", &sysnum_GdiSelectFont,
get_windows_version() <= DR_WINDOWS_VERSION_2000);
/* i#1386: mismatch between system call type and handle type */
get_sysnum("NtUserGetDC", &sysnum_UserGetDC, false/*reqd*/);
get_sysnum("NtUserGetProcessWindowStation", &sysnum_UserGetProcessWindowStation,
false/*reqd*/);
get_sysnum("NtUserCreateWindowStation", &sysnum_UserCreateWindowStation,
get_windows_version() <= DR_WINDOWS_VERSION_2000);
get_sysnum("NtUserOpenWindowStation", &sysnum_UserOpenWindowStation,
get_windows_version() <= DR_WINDOWS_VERSION_2000);
get_sysnum("NtUserCloseWindowStation", &sysnum_UserCloseWindowStation,
false/*reqd*/);
get_sysnum("NtUserGetWindowDC", &sysnum_UserGetWindowDC, false/*reqd*/);
get_sysnum("NtUserCloseDesktop", &sysnum_UserCloseDesktop, false/*reqd*/);
get_sysnum("NtUserCreateDesktop", &sysnum_UserCreateDesktop,
true/*ok to fail*/);
get_sysnum("NtUserCreateDesktopEx", &sysnum_UserCreateDesktopEx,
true/*ok to fail*/);
get_sysnum("NtUserOpenDesktop", &sysnum_UserOpenDesktop,
get_windows_version() <= DR_WINDOWS_VERSION_2000);
get_sysnum("NtUserOpenInputDesktop", &sysnum_UserOpenInputDesktop,
false/*reqd*/);
get_sysnum("NtUserOpenThreadDesktop", &sysnum_UserOpenThreadDesktop,
true/*ok to faile*/);
syscall_wingdi_init(drcontext, ntdll_base);
if (options.check_handle_leaks)
handlecheck_init();
}
void
syscall_os_exit(void)
{
/* must be called before systable delete */
if (options.check_handle_leaks)
handlecheck_exit();
syscall_wingdi_exit();
}
void
syscall_os_thread_init(void *drcontext)
{
syscall_wingdi_thread_init(drcontext);
}
void
syscall_os_thread_exit(void *drcontext)
{
syscall_wingdi_thread_exit(drcontext);
}
void
syscall_os_module_load(void *drcontext, const module_data_t *info, bool loaded)
{
}
static void
handle_post_CreateThread(void *drcontext, drsys_sysnum_t sysnum, cls_syscall_t *pt,
dr_mcontext_t *mc)
{
if (options.shadowing && NT_SUCCESS(dr_syscall_get_result(drcontext))) {
/* Even on XP+ where csrss frees the stack, the stack alloc happens
* in-process and we see it. The TEB alloc, however, is done by
* the kernel, and kernel32!CreateRemoteThread writes to the TEB
* prior to the thread resuming, so we handle it here.
* We also process the TEB in set_thread_initial_structures() in
* case someone creates a thread remotely, or in-process but custom
* so it's not suspended at this point.
*/
HANDLE thread_handle;
/* If not suspended, let set_thread_initial_structures() handle it to
* avoid races: though since setting as defined the only race would be
* the thread exiting
*/
if (syscall_get_param(drcontext, 7)/*bool suspended*/ &&
is_current_process((HANDLE)syscall_get_param(drcontext, 3)) &&
safe_read((byte *)syscall_get_param(drcontext, 0), sizeof(thread_handle),
&thread_handle)) {
TEB *teb = get_TEB_from_handle(thread_handle);
LOG(1, "TEB for new thread: "PFX"\n", teb);
set_teb_initial_shadow(teb);
}
}
}
static void
handle_post_CreateThreadEx(void *drcontext, drsys_sysnum_t sysnum, cls_syscall_t *pt,
dr_mcontext_t *mc)
{
if (options.shadowing &&
is_current_process((HANDLE)syscall_get_param(drcontext, 3)) &&
NT_SUCCESS(dr_syscall_get_result(drcontext))) {
HANDLE thread_handle;
create_thread_info_t info;
/* See notes in handle_post_CreateThread() */
if (syscall_get_param(drcontext, 6)/*bool suspended*/ &&
safe_read((byte *)syscall_get_param(drcontext, 0), sizeof(thread_handle),
&thread_handle)) {
TEB *teb = get_TEB_from_handle(thread_handle);
LOG(1, "TEB for new thread: "PFX"\n", teb);
set_teb_initial_shadow(teb);
}
}
}
static bool
syscall_could_leak_handle(drsys_sysnum_t sysnum)
{
if (drsys_sysnums_equal(&sysnum, &sysnum_DuplicateObject))
return true;
return false;
}
static HANDLE
syscall_get_src_proc_handle(void *drcontext, drsys_sysnum_t sysnum)
{
if (drsys_sysnums_equal(&sysnum, &sysnum_DuplicateObject))
return (HANDLE) syscall_get_param(drcontext, 0);
return NT_CURRENT_PROCESS;
}
static HANDLE
syscall_get_tgt_proc_handle(void *drcontext, drsys_sysnum_t sysnum)
{
if (drsys_sysnums_equal(&sysnum, &sysnum_DuplicateObject))
return (HANDLE) syscall_get_param(drcontext, 2);
return NT_CURRENT_PROCESS;
}
/* This is only called from os_shared_post_syscall with check_handle_leaks
* on successful system calls.
* If we add any arg iteration w/o check_handle_leaks or failed system call,
* we must change os_shared_post_syscall too.
*/
static bool
post_syscall_iter_arg_cb(drsys_arg_t *arg, void *user_data)
{
ASSERT(!arg->pre, "we only iterate on post-syscall");
if (options.check_handle_leaks && arg->type == DRSYS_TYPE_HANDLE) {
drsys_syscall_type_t syscall_type = DRSYS_SYSCALL_TYPE_KERNEL;
if (drsys_syscall_type(arg->syscall, &syscall_type) != DRMF_SUCCESS)
WARN("WARNING: failed to get syscall type\n");
if (arg->mode == DRSYS_PARAM_OUT) {
HANDLE handle;
if (arg->value == (ptr_uint_t)NULL &&
syscall_could_leak_handle(arg->sysnum)) {
handlecheck_report_leak_on_syscall
((dr_mcontext_t *)user_data, arg,
syscall_get_tgt_proc_handle(arg->drcontext, arg->sysnum));
} else if (safe_read((void *)arg->value, sizeof(HANDLE), &handle)) {
/* assuming any handle arg written by the syscall
* is newly created.
*/
handlecheck_create_handle
(arg->drcontext,
syscall_get_tgt_proc_handle(arg->drcontext, arg->sysnum),
handle,
syscall_handle_type(syscall_type, arg->sysnum),
arg->sysnum, NULL, arg->mc);
} else {
DODEBUG({
const char *sysname = "<unknown>";
drsys_syscall_name(arg->syscall, &sysname);
LOG(SYSCALL_VERBOSE,
"fail to read handle from syscall %x.%x %s",
arg->sysnum.number, arg->sysnum.secondary, sysname);
});
}
} else if (TEST(DRSYS_PARAM_RETVAL, arg->mode)) {
/* i#988-c#7,c#8: handle in return may not be newly created,
* in which case, we won't iterate the args.
*/
handlecheck_create_handle
(arg->drcontext,
syscall_get_tgt_proc_handle(arg->drcontext, arg->sysnum),
(HANDLE)arg->value,
syscall_handle_type(syscall_type, arg->sysnum),
arg->sysnum, NULL, arg->mc);
}
}
return true; /* keep going */
}
/* i#1112: DuplicateHandle can close a handle created by DuplicateHandle by
* setting the following parameters:
* - Set arg0 hSourceProcessHandle to the target process from the
* DuplicateHandle call that created the handle.
* - Set arg1 hSourceHandle to the duplicated handle to close.
* - Set arg3 lpTargetHandle to NULL.
* - Set arg6 dwOptions to DUPLICATE_CLOSE_SOURCE.
* here we check arg6 to see if the syscall closes the handle.
*/
static bool
syscall_duplicate_handle_deletes_handle(void *drcontext,
drsys_sysnum_t sysnum)
{
ptr_uint_t arg6;
ASSERT(drsys_sysnums_equal(&sysnum, &sysnum_DuplicateObject),
"syscall is not NtDuplicateObject");
if (drsys_pre_syscall_arg(drcontext, 6, &arg6) == DRMF_SUCCESS &&
TEST(DUPLICATE_CLOSE_SOURCE, arg6))
return true;
return false;
}
/* Checks whether a syscall deletes a handle.
* Returns which arg holds the handle for deletion.
* Returns -1 if the syscall does not delete a handle.
* It must be called from pre/post syscall event where syscall
* arguments are available for query.
*/
static int
syscall_deletes_handle(void *drcontext, drsys_sysnum_t sysnum)
{
if (drsys_sysnums_equal(&sysnum, &sysnum_Close) ||
drsys_sysnums_equal(&sysnum, &sysnum_UserDestroyAcceleratorTable) ||
drsys_sysnums_equal(&sysnum, &sysnum_UserDestroyCursor) ||
drsys_sysnums_equal(&sysnum, &sysnum_UserDestroyInputContext) ||
drsys_sysnums_equal(&sysnum, &sysnum_UserDestroyMenu) ||
drsys_sysnums_equal(&sysnum, &sysnum_UserDestroyWindow) ||
drsys_sysnums_equal(&sysnum, &sysnum_UserReleaseDC) ||
drsys_sysnums_equal(&sysnum, &sysnum_UserCloseDesktop) ||
drsys_sysnums_equal(&sysnum, &sysnum_UserCloseWindowStation) ||
drsys_sysnums_equal(&sysnum, &sysnum_GdiDeleteObjectApp) ||
drsys_sysnums_equal(&sysnum, &sysnum_GdiDeleteColorSpace) ||
drsys_sysnums_equal(&sysnum, &sysnum_GdiDeleteColorTransform) ||
drsys_sysnums_equal(&sysnum, &sysnum_GdiDeleteClientObj) ||
drsys_sysnums_equal(&sysnum, &sysnum_GdiDdReleaseDC))
return 0;
if (drsys_sysnums_equal(&sysnum, &sysnum_DuplicateObject) &&
syscall_duplicate_handle_deletes_handle(drcontext, sysnum))
return 1;
return -1;
}
/* Checks whether a system call creates a new handle.
* It must be called from pre/post syscall event where syscall
* arguments are available for query.
*/
static bool
syscall_creates_handle(void *drcontext, drsys_sysnum_t sysnum)
{
ptr_uint_t arg;
/* i#988: syscalls return existing handles */
if (drsys_sysnums_equal(&sysnum, &sysnum_UserRemoveProp) ||
drsys_sysnums_equal(&sysnum, &sysnum_UserFindExistingCursorIcon) ||
drsys_sysnums_equal(&sysnum, &sysnum_UserGetAncestor) ||
drsys_sysnums_equal(&sysnum, &sysnum_GetThreadDesktop) ||
drsys_sysnums_equal(&sysnum, &sysnum_UserGetThreadDesktop) ||
/* i#988-c#12: GdiSelect* system calls return existing handles */
drsys_sysnums_equal(&sysnum, &sysnum_GdiExtSelectClipRgn) ||
drsys_sysnums_equal(&sysnum, &sysnum_GdiSelectBrush) ||
drsys_sysnums_equal(&sysnum, &sysnum_GdiSelectPen) ||
drsys_sysnums_equal(&sysnum, &sysnum_GdiSelectBitmap) ||
drsys_sysnums_equal(&sysnum, &sysnum_GdiSelectFont))
return false;
/* i#988-c#7: If the arg1 hMem is not NULL and the function succeeds,
* the return value is the handle to the data passed in, so it does
* not really create a new handle.
*/
if (drsys_sysnums_equal(&sysnum, &sysnum_UserSetClipboardData) &&
drsys_pre_syscall_arg(drcontext, 1, &arg) == DRMF_SUCCESS &&
arg != (ptr_uint_t)NULL)
return false;
return true;
}
/***************************************************************************
* TOP LEVEL
*/
bool
os_shared_pre_syscall(void *drcontext, cls_syscall_t *pt, drsys_sysnum_t sysnum,
dr_mcontext_t *mc, drsys_syscall_t *syscall)
{
if (options.check_handle_leaks) {
int idx = syscall_deletes_handle(drcontext, sysnum);
if (idx != -1) {
/* i#974: multiple threads may create/delete handles in parallel,
* so we remove the handle from table at pre-syscall by simply
* assuming the syscall will succeed, and add it back if it fails.
*/
drsys_syscall_type_t syscall_type = DRSYS_SYSCALL_TYPE_KERNEL;
if (drsys_syscall_type(syscall, &syscall_type) != DRMF_SUCCESS)
WARN("WARNING: failed to get syscall type\n");
pt->handle_info =
handlecheck_delete_handle(drcontext,
syscall_get_src_proc_handle(drcontext, sysnum),
(HANDLE) syscall_get_param(drcontext, idx),
syscall_handle_type(syscall_type, sysnum),
sysnum, NULL, mc);
}
}
return wingdi_shared_process_syscall(true/*pre*/, drcontext, sysnum, pt, mc, syscall);
}
void
os_shared_post_syscall(void *drcontext, cls_syscall_t *pt, drsys_sysnum_t sysnum,
dr_mcontext_t *mc, drsys_syscall_t *syscall)
{
/* FIXME PR 456501: watch CreateProcess, CreateProcessEx, and
* CreateUserProcess. Convert process handle to pid and section
* handle to file path, and write both as a FORKEXEC line in
* f_fork.
*/
if (drsys_sysnums_equal(&sysnum, &sysnum_CreateThread) ||
drsys_sysnums_equal(&sysnum, &sysnum_CreateThreadEx)) {
if (NT_SUCCESS(dr_syscall_get_result(drcontext)) &&
is_current_process((HANDLE)syscall_get_param(drcontext, 3)/*3rd for both*/)) {
HANDLE thread_handle;
thread_id_t child = INVALID_THREAD_ID;
if (safe_read((byte *)syscall_get_param(drcontext, 0), sizeof(thread_handle),
&thread_handle))
child = get_tid_from_handle(thread_handle);
if (child != INVALID_THREAD_ID)
report_child_thread(drcontext, child);
else
WARN("WARNING: unable to determine child thread it\n");
}
if (drsys_sysnums_equal(&sysnum, &sysnum_CreateThread))
handle_post_CreateThread(drcontext, sysnum, pt, mc);
else if (drsys_sysnums_equal(&sysnum, &sysnum_CreateThreadEx))
handle_post_CreateThreadEx(drcontext, sysnum, pt, mc);
}
/* for handle leak checks */
if (options.check_handle_leaks) {
drsys_syscall_type_t syscall_type = DRSYS_SYSCALL_TYPE_KERNEL;
bool success = false;
int idx;
if (drsys_cur_syscall_result(drcontext, &success, NULL, NULL) != DRMF_SUCCESS)
WARN("WARNING: failed to get syscall success\n");
if (drsys_syscall_type(syscall, &syscall_type) != DRMF_SUCCESS)
WARN("WARNING: failed to get syscall type\n");
idx = syscall_deletes_handle(drcontext, sysnum);
if (idx != -1) {
/* i#1112: NtDuplicateObject closes the source handle when
* DUPLICATE_CLOSE_SOURCE is set, regardless of any error
* status returned
*/
bool res;
res = (drsys_sysnums_equal(&sysnum, &sysnum_DuplicateObject) &&
syscall_duplicate_handle_deletes_handle(drcontext, sysnum)) ?
true : success;
/* XXX: really we should iterate the args and look for the handle,
* but for now I'm keeping the prior code.
*/
handlecheck_delete_handle_post_syscall
(drcontext, (HANDLE)syscall_get_param(drcontext, idx),
sysnum, mc,
syscall_handle_type(syscall_type, sysnum), pt->handle_info, res);
pt->handle_info = NULL;
}
/* find the OUT params, including return value */
if (success &&
syscall_creates_handle(drcontext, sysnum) &&
drsys_iterate_args(drcontext, post_syscall_iter_arg_cb, mc) !=
DRMF_SUCCESS)
LOG(1, "unknown system call args for #%d\n", sysnum.number);
}
wingdi_shared_process_syscall(false/*!pre*/, drcontext, sysnum, pt, mc, syscall);
}
bool
os_process_syscall_memarg(drsys_arg_t *arg)
{
return wingdi_process_syscall_arg(arg);
}
/***************************************************************************
* handle check related system call routines
*/
static int
syscall_handle_type(drsys_syscall_type_t drsys_type, drsys_sysnum_t sysnum)
{
if (drsys_type == DRSYS_SYSCALL_TYPE_USER) {
if (drsys_sysnums_equal(&sysnum, &sysnum_UserGetDC) ||
drsys_sysnums_equal(&sysnum, &sysnum_UserReleaseDC) ||
drsys_sysnums_equal(&sysnum, &sysnum_UserGetWindowDC))
return HANDLE_TYPE_GDI;
if (drsys_sysnums_equal(&sysnum, &sysnum_UserGetProcessWindowStation) ||
drsys_sysnums_equal(&sysnum, &sysnum_UserCreateWindowStation) ||
drsys_sysnums_equal(&sysnum, &sysnum_UserOpenWindowStation) ||
drsys_sysnums_equal(&sysnum, &sysnum_UserCloseWindowStation) ||
drsys_sysnums_equal(&sysnum, &sysnum_UserCloseDesktop) ||
drsys_sysnums_equal(&sysnum, &sysnum_UserCreateDesktop) ||
drsys_sysnums_equal(&sysnum, &sysnum_UserCreateDesktopEx) ||
drsys_sysnums_equal(&sysnum, &sysnum_UserOpenDesktop) ||
drsys_sysnums_equal(&sysnum, &sysnum_UserOpenInputDesktop) ||
drsys_sysnums_equal(&sysnum, &sysnum_UserOpenThreadDesktop) ||
drsys_sysnums_equal(&sysnum, &sysnum_GetThreadDesktop) ||
drsys_sysnums_equal(&sysnum, &sysnum_UserGetThreadDesktop))
return HANDLE_TYPE_KERNEL;
return HANDLE_TYPE_USER;
}
else if (drsys_type == DRSYS_SYSCALL_TYPE_GRAPHICS)
return HANDLE_TYPE_GDI;
else
return HANDLE_TYPE_KERNEL;
}