Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
c3c712c1
Commit
c3c712c1
authored
Aug 14, 2009
by
Michael Karcher
Committed by
Alexandre Julliard
Aug 14, 2009
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ntdll/tests: Implement tests for data execution prevention.
parent
cde2f1a0
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
177 additions
and
12 deletions
+177
-12
exception.c
dlls/ntdll/tests/exception.c
+177
-12
No files found.
dlls/ntdll/tests/exception.c
View file @
c3c712c1
...
...
@@ -47,8 +47,18 @@ static PVOID (WINAPI *pRtlAddVectoredExceptionHandler)(ULONG first, PVECTORE
static
ULONG
(
WINAPI
*
pRtlRemoveVectoredExceptionHandler
)(
PVOID
handler
);
static
NTSTATUS
(
WINAPI
*
pNtReadVirtualMemory
)(
HANDLE
,
const
void
*
,
void
*
,
SIZE_T
,
SIZE_T
*
);
static
NTSTATUS
(
WINAPI
*
pNtTerminateProcess
)(
HANDLE
handle
,
LONG
exit_code
);
static
NTSTATUS
(
WINAPI
*
pNtQueryInformationProcess
)(
HANDLE
,
PROCESSINFOCLASS
,
PVOID
,
ULONG
,
PULONG
);
static
NTSTATUS
(
WINAPI
*
pNtSetInformationProcess
)(
HANDLE
,
PROCESSINFOCLASS
,
PVOID
,
ULONG
);
#ifdef __i386__
#ifndef __WINE_WINTRNL_H
#define ProcessExecuteFlags 0x22
#define MEM_EXECUTE_OPTION_DISABLE 0x01
#define MEM_EXECUTE_OPTION_ENABLE 0x02
#define MEM_EXECUTE_OPTION_PERMANENT 0x08
#endif
static
int
my_argc
;
static
char
**
my_argv
;
static
int
test_stage
;
...
...
@@ -183,23 +193,30 @@ static int got_exception;
static
BOOL
have_vectored_api
;
static
void
run_exception_test
(
void
*
handler
,
const
void
*
context
,
const
void
*
code
,
unsigned
int
code_size
)
const
void
*
code
,
unsigned
int
code_size
,
DWORD
access
)
{
struct
{
EXCEPTION_REGISTRATION_RECORD
frame
;
const
void
*
context
;
}
exc_frame
;
void
(
*
func
)(
void
)
=
code_mem
;
DWORD
oldaccess
,
oldaccess2
;
exc_frame
.
frame
.
Handler
=
handler
;
exc_frame
.
frame
.
Prev
=
pNtCurrentTeb
()
->
Tib
.
ExceptionList
;
exc_frame
.
context
=
context
;
memcpy
(
code_mem
,
code
,
code_size
);
if
(
access
)
VirtualProtect
(
code_mem
,
code_size
,
access
,
&
oldaccess
);
pNtCurrentTeb
()
->
Tib
.
ExceptionList
=
&
exc_frame
.
frame
;
func
();
pNtCurrentTeb
()
->
Tib
.
ExceptionList
=
exc_frame
.
frame
.
Prev
;
if
(
access
)
VirtualProtect
(
code_mem
,
code_size
,
oldaccess
,
&
oldaccess2
);
}
static
LONG
CALLBACK
rtlraiseexception_vectored_handler
(
EXCEPTION_POINTERS
*
ExceptionInfo
)
...
...
@@ -397,7 +414,7 @@ static void test_prot_fault(void)
{
got_exception
=
0
;
run_exception_test
(
handler
,
&
exceptions
[
i
],
&
exceptions
[
i
].
code
,
sizeof
(
exceptions
[
i
].
code
));
sizeof
(
exceptions
[
i
].
code
)
,
0
);
if
(
!
i
&&
!
got_exception
)
{
trace
(
"No exception, assuming win9x, no point in testing further
\n
"
);
...
...
@@ -586,7 +603,7 @@ static void test_exceptions(void)
}
/* test handling of debug registers */
run_exception_test
(
dreg_handler
,
NULL
,
&
segfault_code
,
sizeof
(
segfault_code
));
run_exception_test
(
dreg_handler
,
NULL
,
&
segfault_code
,
sizeof
(
segfault_code
)
,
0
);
ctx
.
ContextFlags
=
CONTEXT_DEBUG_REGISTERS
;
res
=
pNtGetContextThread
(
GetCurrentThread
(),
&
ctx
);
...
...
@@ -596,17 +613,17 @@ static void test_exceptions(void)
/* test single stepping behavior */
got_exception
=
0
;
run_exception_test
(
single_step_handler
,
NULL
,
&
single_stepcode
,
sizeof
(
single_stepcode
));
run_exception_test
(
single_step_handler
,
NULL
,
&
single_stepcode
,
sizeof
(
single_stepcode
)
,
0
);
ok
(
got_exception
==
3
,
"expected 3 single step exceptions, got %d
\n
"
,
got_exception
);
/* test alignment exceptions */
got_exception
=
0
;
run_exception_test
(
align_check_handler
,
NULL
,
align_check_code
,
sizeof
(
align_check_code
));
run_exception_test
(
align_check_handler
,
NULL
,
align_check_code
,
sizeof
(
align_check_code
)
,
0
);
ok
(
got_exception
==
0
,
"got %d alignment faults, expected 0
\n
"
,
got_exception
);
/* test direction flag */
got_exception
=
0
;
run_exception_test
(
direction_flag_handler
,
NULL
,
direction_flag_code
,
sizeof
(
direction_flag_code
));
run_exception_test
(
direction_flag_handler
,
NULL
,
direction_flag_code
,
sizeof
(
direction_flag_code
)
,
0
);
ok
(
got_exception
==
1
,
"got %d exceptions, expected 1
\n
"
,
got_exception
);
/* test single stepping over hardware breakpoint */
...
...
@@ -618,11 +635,11 @@ static void test_exceptions(void)
ok
(
res
==
STATUS_SUCCESS
,
"NtSetContextThread faild with %x
\n
"
,
res
);
got_exception
=
0
;
run_exception_test
(
bpx_handler
,
NULL
,
dummy_code
,
sizeof
(
dummy_code
));
run_exception_test
(
bpx_handler
,
NULL
,
dummy_code
,
sizeof
(
dummy_code
)
,
0
);
ok
(
got_exception
==
4
,
"expected 4 exceptions, got %d
\n
"
,
got_exception
);
/* test int3 handling */
run_exception_test
(
int3_handler
,
NULL
,
int3_code
,
sizeof
(
int3_code
));
run_exception_test
(
int3_handler
,
NULL
,
int3_code
,
sizeof
(
int3_code
)
,
0
);
}
static
void
test_debugger
(
void
)
...
...
@@ -828,7 +845,7 @@ static void test_simd_exceptions(void)
/* test if CPU & OS can do sse */
stage
=
1
;
got_exception
=
0
;
run_exception_test
(
simd_fault_handler
,
&
stage
,
sse_check
,
sizeof
(
sse_check
));
run_exception_test
(
simd_fault_handler
,
&
stage
,
sse_check
,
sizeof
(
sse_check
)
,
0
);
if
(
got_exception
)
{
skip
(
"system doesn't support SSE
\n
"
);
return
;
...
...
@@ -838,7 +855,7 @@ static void test_simd_exceptions(void)
stage
=
2
;
got_exception
=
0
;
run_exception_test
(
simd_fault_handler
,
&
stage
,
simd_exception_test
,
sizeof
(
simd_exception_test
));
sizeof
(
simd_exception_test
)
,
0
);
ok
(
got_exception
==
1
,
"got exception: %i, should be 1
\n
"
,
got_exception
);
}
...
...
@@ -904,20 +921,163 @@ static void test_fpu_exceptions(void)
struct
fpu_exception_info
info
;
memset
(
&
info
,
0
,
sizeof
(
info
));
run_exception_test
(
fpu_exception_handler
,
&
info
,
fpu_exception_test_ie
,
sizeof
(
fpu_exception_test_ie
));
run_exception_test
(
fpu_exception_handler
,
&
info
,
fpu_exception_test_ie
,
sizeof
(
fpu_exception_test_ie
)
,
0
);
ok
(
info
.
exception_code
==
EXCEPTION_FLT_STACK_CHECK
,
"Got exception code %#x, expected EXCEPTION_FLT_STACK_CHECK
\n
"
,
info
.
exception_code
);
ok
(
info
.
exception_offset
==
0x19
,
"Got exception offset %#x, expected 0x19
\n
"
,
info
.
exception_offset
);
ok
(
info
.
eip_offset
==
0x1b
,
"Got EIP offset %#x, expected 0x1b
\n
"
,
info
.
eip_offset
);
memset
(
&
info
,
0
,
sizeof
(
info
));
run_exception_test
(
fpu_exception_handler
,
&
info
,
fpu_exception_test_de
,
sizeof
(
fpu_exception_test_de
));
run_exception_test
(
fpu_exception_handler
,
&
info
,
fpu_exception_test_de
,
sizeof
(
fpu_exception_test_de
)
,
0
);
ok
(
info
.
exception_code
==
EXCEPTION_FLT_DIVIDE_BY_ZERO
,
"Got exception code %#x, expected EXCEPTION_FLT_DIVIDE_BY_ZERO
\n
"
,
info
.
exception_code
);
ok
(
info
.
exception_offset
==
0x17
,
"Got exception offset %#x, expected 0x17
\n
"
,
info
.
exception_offset
);
ok
(
info
.
eip_offset
==
0x19
,
"Got EIP offset %#x, expected 0x19
\n
"
,
info
.
eip_offset
);
}
struct
dpe_exception_info
{
BOOL
exception_caught
;
DWORD
exception_info
;
};
static
DWORD
dpe_exception_handler
(
EXCEPTION_RECORD
*
rec
,
EXCEPTION_REGISTRATION_RECORD
*
frame
,
CONTEXT
*
context
,
EXCEPTION_REGISTRATION_RECORD
**
dispatcher
)
{
DWORD
old_prot
;
struct
dpe_exception_info
*
info
=
*
(
struct
dpe_exception_info
**
)(
frame
+
1
);
ok
(
rec
->
ExceptionCode
==
EXCEPTION_ACCESS_VIOLATION
,
"Exception code %08x
\n
"
,
rec
->
ExceptionCode
);
ok
(
rec
->
NumberParameters
==
2
,
"Parameter count: %d
\n
"
,
rec
->
NumberParameters
);
ok
((
LPVOID
)
rec
->
ExceptionInformation
[
1
]
==
code_mem
,
"Exception address: %p, expected %p
\n
"
,
(
LPVOID
)
rec
->
ExceptionInformation
[
1
],
code_mem
);
info
->
exception_info
=
rec
->
ExceptionInformation
[
0
];
info
->
exception_caught
=
TRUE
;
VirtualProtect
(
code_mem
,
1
,
PAGE_EXECUTE_READWRITE
,
&
old_prot
);
return
ExceptionContinueExecution
;
}
static
void
test_dpe_exceptions
(
void
)
{
static
char
single_ret
[]
=
{
0xC3
};
struct
dpe_exception_info
info
;
NTSTATUS
stat
;
BOOL
has_hw_support
;
BOOL
is_permanent
=
FALSE
,
can_test_without
=
TRUE
,
can_test_with
=
TRUE
;
DWORD
val
;
ULONG
len
;
/* Query DEP with len to small */
stat
=
pNtQueryInformationProcess
(
GetCurrentProcess
(),
ProcessExecuteFlags
,
&
val
,
sizeof
val
-
1
,
&
len
);
if
(
stat
==
STATUS_INVALID_INFO_CLASS
)
{
skip
(
"This software platform does not support DEP
\n
"
);
return
;
}
ok
(
stat
==
STATUS_INFO_LENGTH_MISMATCH
,
"buffer too small: %08x
\n
"
,
stat
);
/* Query DEP */
stat
=
pNtQueryInformationProcess
(
GetCurrentProcess
(),
ProcessExecuteFlags
,
&
val
,
sizeof
val
,
&
len
);
ok
(
stat
==
STATUS_SUCCESS
,
"querying DEP: status %08x
\n
"
,
stat
);
if
(
stat
==
STATUS_SUCCESS
)
{
ok
(
len
==
sizeof
val
,
"returned length: %d
\n
"
,
len
);
if
(
val
&
MEM_EXECUTE_OPTION_PERMANENT
)
{
skip
(
"toggling DEP impossible - status locked
\n
"
);
is_permanent
=
TRUE
;
if
(
val
&
MEM_EXECUTE_OPTION_DISABLE
)
can_test_without
=
FALSE
;
else
can_test_with
=
FALSE
;
}
}
if
(
!
is_permanent
)
{
/* Enable DEP */
val
=
MEM_EXECUTE_OPTION_DISABLE
;
stat
=
pNtSetInformationProcess
(
GetCurrentProcess
(),
ProcessExecuteFlags
,
&
val
,
sizeof
val
);
ok
(
stat
==
STATUS_SUCCESS
,
"enabling DEP: status %08x
\n
"
,
stat
);
}
if
(
can_test_with
)
{
/* Try access to locked page with DEP on*/
info
.
exception_caught
=
FALSE
;
run_exception_test
(
dpe_exception_handler
,
&
info
,
single_ret
,
sizeof
(
single_ret
),
PAGE_NOACCESS
);
ok
(
info
.
exception_caught
==
TRUE
,
"Execution of disabled memory suceeded
\n
"
);
ok
(
info
.
exception_info
==
EXCEPTION_READ_FAULT
||
info
.
exception_info
==
EXCEPTION_EXECUTE_FAULT
,
"Access violation type: %08x
\n
"
,
(
unsigned
)
info
.
exception_info
);
has_hw_support
=
info
.
exception_info
==
EXCEPTION_EXECUTE_FAULT
;
trace
(
"DEP hardware support: %s
\n
"
,
has_hw_support
?
"Yes"
:
"No"
);
/* Try execution of data with DEP on*/
info
.
exception_caught
=
FALSE
;
run_exception_test
(
dpe_exception_handler
,
&
info
,
single_ret
,
sizeof
(
single_ret
),
PAGE_READWRITE
);
if
(
has_hw_support
)
{
ok
(
info
.
exception_caught
==
TRUE
,
"Execution of data memory suceeded
\n
"
);
ok
(
info
.
exception_info
==
EXCEPTION_EXECUTE_FAULT
,
"Access violation type: %08x
\n
"
,
(
unsigned
)
info
.
exception_info
);
}
else
ok
(
info
.
exception_caught
==
FALSE
,
"Execution trapped without hardware support
\n
"
);
}
else
skip
(
"DEP is in AlwaysOff state
\n
"
);
if
(
!
is_permanent
)
{
/* Disable DEP */
val
=
MEM_EXECUTE_OPTION_ENABLE
;
stat
=
pNtSetInformationProcess
(
GetCurrentProcess
(),
ProcessExecuteFlags
,
&
val
,
sizeof
val
);
ok
(
stat
==
STATUS_SUCCESS
,
"disabling DEP: status %08x
\n
"
,
stat
);
}
/* page is read without exec here */
if
(
can_test_without
)
{
/* Try execution of data with DEP off */
info
.
exception_caught
=
FALSE
;
run_exception_test
(
dpe_exception_handler
,
&
info
,
single_ret
,
sizeof
(
single_ret
),
PAGE_READWRITE
);
ok
(
info
.
exception_caught
==
FALSE
,
"Execution trapped with DEP turned off
\n
"
);
/* Try access to locked page with DEP off - error code is different than
with hardware DEP on */
info
.
exception_caught
=
FALSE
;
run_exception_test
(
dpe_exception_handler
,
&
info
,
single_ret
,
sizeof
(
single_ret
),
PAGE_NOACCESS
);
ok
(
info
.
exception_caught
==
TRUE
,
"Execution of disabled memory suceeded
\n
"
);
ok
(
info
.
exception_info
==
EXCEPTION_READ_FAULT
,
"Access violation type: %08x
\n
"
,
(
unsigned
)
info
.
exception_info
);
}
else
skip
(
"DEP is in AlwaysOn state
\n
"
);
if
(
!
is_permanent
)
{
/* Turn off DEP permanently */
val
=
MEM_EXECUTE_OPTION_ENABLE
|
MEM_EXECUTE_OPTION_PERMANENT
;
stat
=
pNtSetInformationProcess
(
GetCurrentProcess
(),
ProcessExecuteFlags
,
&
val
,
sizeof
val
);
ok
(
stat
==
STATUS_SUCCESS
,
"disabling DEP permanently: status %08x
\n
"
,
stat
);
}
/* Try to turn off DEP */
val
=
MEM_EXECUTE_OPTION_ENABLE
;
stat
=
pNtSetInformationProcess
(
GetCurrentProcess
(),
ProcessExecuteFlags
,
&
val
,
sizeof
val
);
ok
(
stat
==
STATUS_ACCESS_DENIED
,
"disabling DEP while permanent: status %08x
\n
"
,
stat
);
/* Try to turn on DEP */
val
=
MEM_EXECUTE_OPTION_DISABLE
;
stat
=
pNtSetInformationProcess
(
GetCurrentProcess
(),
ProcessExecuteFlags
,
&
val
,
sizeof
val
);
ok
(
stat
==
STATUS_ACCESS_DENIED
,
"enabling DEP while permanent: status %08x
\n
"
,
stat
);
}
#elif defined(__x86_64__)
#define UNW_FLAG_NHANDLER 0
...
...
@@ -1215,6 +1375,10 @@ START_TEST(exception)
"RtlAddVectoredExceptionHandler"
);
pRtlRemoveVectoredExceptionHandler
=
(
void
*
)
GetProcAddress
(
hntdll
,
"RtlRemoveVectoredExceptionHandler"
);
pNtQueryInformationProcess
=
(
void
*
)
GetProcAddress
(
hntdll
,
"NtQueryInformationProcess"
);
pNtSetInformationProcess
=
(
void
*
)
GetProcAddress
(
hntdll
,
"NtSetInformationProcess"
);
#ifdef __i386__
if
(
!
pNtCurrentTeb
)
...
...
@@ -1271,6 +1435,7 @@ START_TEST(exception)
test_debugger
();
test_simd_exceptions
();
test_fpu_exceptions
();
test_dpe_exceptions
();
#elif defined(__x86_64__)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment