Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-cw
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-cw
Commits
b7b8929f
Commit
b7b8929f
authored
Jan 28, 2010
by
Alexandre Julliard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ntdll: Support delayed freeing of heap blocks to catch use-after-free bugs.
parent
a75ae793
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
73 additions
and
9 deletions
+73
-9
heap.c
dlls/ntdll/heap.c
+73
-9
No files found.
dlls/ntdll/heap.c
View file @
b7b8929f
...
...
@@ -82,6 +82,7 @@ typedef struct
/* Value for arena 'magic' field */
#define ARENA_INUSE_MAGIC 0x455355
#define ARENA_PENDING_MAGIC 0xbedead
#define ARENA_FREE_MAGIC 0x45455246
#define ARENA_LARGE_MAGIC 0x6752614c
...
...
@@ -151,6 +152,8 @@ typedef struct tagHEAP
struct
list
large_list
;
/* Large blocks list */
SIZE_T
grow_size
;
/* Size of next subheap for growing heap */
DWORD
magic
;
/* Magic number */
DWORD
pending_pos
;
/* Position in pending free requests ring */
ARENA_INUSE
**
pending_free
;
/* Ring buffer for pending free requests */
RTL_CRITICAL_SECTION
critSection
;
/* Critical section for serialization */
FREE_LIST_ENTRY
*
freeList
;
/* Free lists */
}
HEAP
;
...
...
@@ -159,6 +162,7 @@ typedef struct tagHEAP
#define HEAP_DEF_SIZE 0x110000
/* Default heap size = 1Mb + 64Kb */
#define COMMIT_MASK 0xffff
/* bitmask for commit/decommit granularity */
#define MAX_FREE_PENDING 1024
/* max number of free requests to delay */
/* some undocumented flags (names are made up) */
#define HEAP_PAGE_ALLOCS 0x01000000
...
...
@@ -275,7 +279,8 @@ static void subheap_notify_free_all(SUBHEAP const *subheap)
else
{
ARENA_INUSE
const
*
pArena
=
(
ARENA_INUSE
const
*
)
ptr
;
if
(
pArena
->
magic
!=
ARENA_INUSE_MAGIC
)
ERR
(
"bad inuse_magic @%p
\n
"
,
pArena
);
if
(
pArena
->
magic
!=
ARENA_INUSE_MAGIC
&&
pArena
->
magic
!=
ARENA_PENDING_MAGIC
)
ERR
(
"bad inuse_magic @%p
\n
"
,
pArena
);
notify_free
(
pArena
+
1
);
ptr
+=
sizeof
(
*
pArena
)
+
(
pArena
->
size
&
ARENA_SIZE_MASK
);
}
...
...
@@ -362,7 +367,9 @@ static void HEAP_Dump( HEAP *heap )
else
{
ARENA_INUSE
*
pArena
=
(
ARENA_INUSE
*
)
ptr
;
DPRINTF
(
"%p %08x used %08x
\n
"
,
pArena
,
pArena
->
magic
,
pArena
->
size
&
ARENA_SIZE_MASK
);
DPRINTF
(
"%p %08x %s %08x
\n
"
,
pArena
,
pArena
->
magic
,
pArena
->
magic
==
ARENA_INUSE_MAGIC
?
"used"
:
"pend"
,
pArena
->
size
&
ARENA_SIZE_MASK
);
ptr
+=
sizeof
(
*
pArena
)
+
(
pArena
->
size
&
ARENA_SIZE_MASK
);
arenaSize
+=
sizeof
(
ARENA_INUSE
);
usedSize
+=
pArena
->
size
&
ARENA_SIZE_MASK
;
...
...
@@ -607,11 +614,25 @@ static void HEAP_CreateFreeBlock( SUBHEAP *subheap, void *ptr, SIZE_T size )
*/
static
void
HEAP_MakeInUseBlockFree
(
SUBHEAP
*
subheap
,
ARENA_INUSE
*
pArena
)
{
HEAP
*
heap
=
subheap
->
heap
;
ARENA_FREE
*
pFree
;
SIZE_T
size
=
(
pArena
->
size
&
ARENA_SIZE_MASK
)
+
sizeof
(
*
pArena
);
SIZE_T
size
;
if
(
heap
->
pending_free
)
{
ARENA_INUSE
*
prev
=
heap
->
pending_free
[
heap
->
pending_pos
];
heap
->
pending_free
[
heap
->
pending_pos
]
=
pArena
;
heap
->
pending_pos
=
(
heap
->
pending_pos
+
1
)
%
MAX_FREE_PENDING
;
pArena
->
magic
=
ARENA_PENDING_MAGIC
;
mark_block_free
(
pArena
+
1
,
pArena
->
size
&
ARENA_SIZE_MASK
,
heap
->
flags
);
if
(
!
prev
)
return
;
pArena
=
prev
;
subheap
=
HEAP_FindSubHeap
(
heap
,
pArena
);
}
/* Check if we can merge with previous block */
size
=
(
pArena
->
size
&
ARENA_SIZE_MASK
)
+
sizeof
(
*
pArena
);
if
(
pArena
->
size
&
ARENA_FLAG_PREV_FREE
)
{
pFree
=
*
((
ARENA_FREE
**
)
pArena
-
1
);
...
...
@@ -1168,7 +1189,7 @@ static BOOL HEAP_ValidateInUseArena( const SUBHEAP *subheap, const ARENA_INUSE *
}
/* Check magic number */
if
(
pArena
->
magic
!=
ARENA_INUSE_MAGIC
)
if
(
pArena
->
magic
!=
ARENA_INUSE_MAGIC
&&
pArena
->
magic
!=
ARENA_PENDING_MAGIC
)
{
if
(
quiet
==
NOISY
)
{
ERR
(
"Heap %p: invalid in-use arena magic %08x for %p
\n
"
,
subheap
->
heap
,
pArena
->
magic
,
pArena
);
...
...
@@ -1238,7 +1259,24 @@ static BOOL HEAP_ValidateInUseArena( const SUBHEAP *subheap, const ARENA_INUSE *
return
FALSE
;
}
/* Check unused bytes */
if
(
flags
&
HEAP_TAIL_CHECKING_ENABLED
)
if
(
pArena
->
magic
==
ARENA_PENDING_MAGIC
)
{
DWORD
*
ptr
=
(
DWORD
*
)(
pArena
+
1
);
DWORD
*
end
=
(
DWORD
*
)((
char
*
)
ptr
+
size
);
while
(
ptr
<
end
)
{
if
(
*
ptr
!=
ARENA_FREE_FILLER
)
{
ERR
(
"Heap %p: free block %p overwritten at %p by %08x
\n
"
,
subheap
->
heap
,
(
ARENA_INUSE
*
)
pArena
+
1
,
ptr
,
*
ptr
);
if
(
!*
ptr
)
{
HEAP_Dump
(
subheap
->
heap
);
DbgBreakPoint
();
}
return
FALSE
;
}
ptr
++
;
}
}
else
if
(
flags
&
HEAP_TAIL_CHECKING_ENABLED
)
{
const
unsigned
char
*
data
=
(
const
unsigned
char
*
)(
pArena
+
1
)
+
size
-
pArena
->
unused_bytes
;
...
...
@@ -1366,6 +1404,8 @@ static BOOL validate_block_pointer( HEAP *heap, SUBHEAP **ret_subheap, const ARE
ret
=
HEAP_ValidateInUseArena
(
subheap
,
arena
,
QUIET
);
else
if
((
ULONG_PTR
)
arena
%
ALIGNMENT
!=
ARENA_OFFSET
)
WARN
(
"Heap %p: unaligned arena pointer %p
\n
"
,
subheap
->
heap
,
arena
);
else
if
(
arena
->
magic
==
ARENA_PENDING_MAGIC
)
WARN
(
"Heap %p: block %p used after free
\n
"
,
subheap
->
heap
,
arena
+
1
);
else
if
(
arena
->
magic
!=
ARENA_INUSE_MAGIC
)
WARN
(
"Heap %p: invalid in-use arena magic %08x for %p
\n
"
,
subheap
->
heap
,
arena
->
magic
,
arena
);
else
if
(
arena
->
size
&
ARENA_FLAG_FREE
)
...
...
@@ -1435,8 +1475,11 @@ void heap_set_debug_flags( HANDLE handle )
}
else
{
mark_block_tail
(
(
char
*
)(
arena
+
1
)
+
size
-
arena
->
unused_bytes
,
arena
->
unused_bytes
,
flags
);
if
(
arena
->
magic
==
ARENA_PENDING_MAGIC
)
mark_block_free
(
arena
+
1
,
size
,
flags
);
else
mark_block_tail
(
(
char
*
)(
arena
+
1
)
+
size
-
arena
->
unused_bytes
,
arena
->
unused_bytes
,
flags
);
ptr
+=
sizeof
(
ARENA_INUSE
)
+
size
;
}
}
...
...
@@ -1446,6 +1489,19 @@ void heap_set_debug_flags( HANDLE handle )
mark_block_tail
(
(
char
*
)(
large
+
1
)
+
large
->
data_size
,
large
->
block_size
-
sizeof
(
*
large
)
-
large
->
data_size
,
flags
);
}
if
((
heap
->
flags
&
HEAP_GROWABLE
)
&&
!
heap
->
pending_free
&&
((
flags
&
HEAP_FREE_CHECKING_ENABLED
)
||
RUNNING_ON_VALGRIND
))
{
void
*
ptr
=
NULL
;
SIZE_T
size
=
MAX_FREE_PENDING
*
sizeof
(
*
heap
->
pending_free
);
if
(
!
NtAllocateVirtualMemory
(
NtCurrentProcess
(),
&
ptr
,
4
,
&
size
,
MEM_COMMIT
,
PAGE_READWRITE
))
{
heap
->
pending_free
=
ptr
;
heap
->
pending_pos
=
0
;
}
}
}
...
...
@@ -1550,6 +1606,12 @@ HANDLE WINAPI RtlDestroyHeap( HANDLE heap )
NtFreeVirtualMemory
(
NtCurrentProcess
(),
&
addr
,
&
size
,
MEM_RELEASE
);
}
subheap_notify_free_all
(
&
heapPtr
->
subheap
);
if
(
heapPtr
->
pending_free
)
{
size
=
0
;
addr
=
heapPtr
->
pending_free
;
NtFreeVirtualMemory
(
NtCurrentProcess
(),
&
addr
,
&
size
,
MEM_RELEASE
);
}
size
=
0
;
addr
=
heapPtr
->
subheap
.
base
;
NtFreeVirtualMemory
(
NtCurrentProcess
(),
&
addr
,
&
size
,
MEM_RELEASE
);
...
...
@@ -2052,7 +2114,8 @@ NTSTATUS WINAPI RtlWalkHeap( HANDLE heap, PVOID entry_ptr )
goto
HW_end
;
}
if
(((
ARENA_INUSE
*
)
ptr
-
1
)
->
magic
==
ARENA_INUSE_MAGIC
)
if
(((
ARENA_INUSE
*
)
ptr
-
1
)
->
magic
==
ARENA_INUSE_MAGIC
||
((
ARENA_INUSE
*
)
ptr
-
1
)
->
magic
==
ARENA_PENDING_MAGIC
)
{
ARENA_INUSE
*
pArena
=
(
ARENA_INUSE
*
)
ptr
-
1
;
ptr
+=
pArena
->
size
&
ARENA_SIZE_MASK
;
...
...
@@ -2100,7 +2163,8 @@ NTSTATUS WINAPI RtlWalkHeap( HANDLE heap, PVOID entry_ptr )
entry
->
lpData
=
pArena
+
1
;
entry
->
cbData
=
pArena
->
size
&
ARENA_SIZE_MASK
;
entry
->
cbOverhead
=
sizeof
(
ARENA_INUSE
);
entry
->
wFlags
=
PROCESS_HEAP_ENTRY_BUSY
;
entry
->
wFlags
=
(
pArena
->
magic
==
ARENA_PENDING_MAGIC
)
?
PROCESS_HEAP_UNCOMMITTED_RANGE
:
PROCESS_HEAP_ENTRY_BUSY
;
/* FIXME: can't handle PROCESS_HEAP_ENTRY_MOVEABLE
and PROCESS_HEAP_ENTRY_DDESHARE yet */
}
...
...
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