Skip to content

Commit 8df5ee8

Browse files
committed
Add memcheck, a memory usage error checker
1 parent 3cd437c commit 8df5ee8

File tree

6 files changed

+1323
-1
lines changed

6 files changed

+1323
-1
lines changed

makefile

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#PLUGINS+=plugins/instruction_mix.c
88
#PLUGINS+=plugins/strace.c
99
#PLUGINS+=plugins/symbol_example.c
10+
#PLUGINS+=plugins/memcheck/memcheck.S plugins/memcheck/memcheck.c plugins/memcheck/naive_stdlib.c
1011

1112
OPTS= -DDBM_LINK_UNCOND_IMM
1213
OPTS+=-DDBM_INLINE_UNCOND_IMM
@@ -22,7 +23,7 @@ OPTS+=-DDBM_TRACES #-DTB_AS_TRACE_HEAD #-DBLXI_AS_TRACE_HEAD
2223
CFLAGS+=-D_GNU_SOURCE -g -std=gnu99 -O2
2324
CFLAGS+=-DGIT_VERSION=\"$(shell git describe --abbrev=8 --dirty --always)\"
2425

25-
LDFLAGS+=-static -ldl -Wl,-Ttext-segment=$(or $(TEXT_SEGMENT),0xa8000000)
26+
LDFLAGS+=-static -ldl
2627
LIBS=-lelf -lpthread -lz
2728
HEADERS=*.h makefile
2829
INCLUDES=-I/usr/include/libelf
@@ -33,6 +34,7 @@ SOURCES+=elf/elf_loader.o elf/symbol_parser.o
3334
ARCH=$(shell $(CC) -dumpmachine | awk -F '-' '{print $$1}')
3435
ifeq ($(findstring arm, $(ARCH)), arm)
3536
CFLAGS += -march=armv7-a -mfpu=neon
37+
LDFLAGS += -Wl,-Ttext-segment=$(or $(TEXT_SEGMENT),0xa8000000)
3638
HEADERS += api/emit_arm.h api/emit_thumb.h
3739
PIE = pie/pie-arm-encoder.o pie/pie-arm-decoder.o pie/pie-arm-field-decoder.o
3840
PIE += pie/pie-thumb-encoder.o pie/pie-thumb-decoder.o pie/pie-thumb-field-decoder.o
@@ -41,6 +43,7 @@ ifeq ($(findstring arm, $(ARCH)), arm)
4143
endif
4244
ifeq ($(ARCH),aarch64)
4345
HEADERS += api/emit_a64.h
46+
LDFLAGS += -Wl,-Ttext-segment=$(or $(TEXT_SEGMENT),0x7000000000)
4447
PIE += pie/pie-a64-field-decoder.o pie/pie-a64-encoder.o pie/pie-a64-decoder.o
4548
SOURCES += scanner_a64.c
4649
SOURCES += api/emit_a64.c
@@ -68,6 +71,9 @@ $(or $(OUTPUT_FILE),dbm): $(HEADERS) $(SOURCES) $(PLUGINS)
6871
cachesim:
6972
PLUGINS="plugins/cachesim/cachesim.c plugins/cachesim/cachesim.S plugins/cachesim/cachesim_model.c" OUTPUT_FILE=mambo_cachesim make
7073

74+
memcheck:
75+
PLUGINS="plugins/memcheck/memcheck.S plugins/memcheck/memcheck.c plugins/memcheck/naive_stdlib.c" OUTPUT_FILE=mambo_memcheck make
76+
7177
clean:
7278
rm -f dbm elf/elf_loader.o elf/symbol_parser.o
7379

plugins/memcheck/README.md

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
MAMBO memcheck
2+
==============
3+
4+
This instrumentation plugin for [MAMBO](https://github.com/beehive-lab/mambo) detects memory usage errors such as out-of-bounds accesses and invalid `free()` calls with relatively low performance overhead. This is still experimental software, please report any problems using [github's issue tracker](https://github.com/beehive-lab/mambo/issues).
5+
6+
7+
Publication:
8+
------------
9+
10+
* [Cosmin Gorgovan, Guillermo Callaghan, and Mikel Luján. Balancing Performance and Productivity for the Development of Dynamic Binary Instrumentation Tools - A Case Study on Arm Systems. In Proceedings of the 29th International Conference on Compiler Construction (CC ’20)](https://dl.acm.org/doi/abs/10.1145/3377555.3377895) **Free download** [via research.manchester.ac.uk](https://www.research.manchester.ac.uk/portal/en/publications/balancing-performance-and-productivity-for-the-development-of-dynamic-binary-instrumentation-tools--a-case-study-on-arm-systems(80e57c1b-9e38-4a15-942d-eb240888b12b).html).
11+
12+
13+
Building:
14+
---------
15+
16+
git clone -b memcheck --recurse-submodules https://github.com/beehive-lab/mambo.git
17+
cd mambo
18+
make memcheck
19+
20+
21+
Usage:
22+
------
23+
24+
To run an application under MAMBO memcheck, simply prefix the command with a call to `mambo_memcheck`. For example to execute `lscpu`, from the mambo source directory run:
25+
26+
./mambo_memcheck /usr/bin/lscpu
27+
28+
or
29+
30+
./mambo_memcheck `which lscpu`
31+
32+
When an application runs under MAMBO memcheck, the first output should be its git version, e.g.:
33+
34+
$ ./mambo_memcheck `which lscpu`
35+
36+
-- MAMBO memcheck 29f87421 --
37+
38+
Architecture: aarch64
39+
CPU op-mode(s): 32-bit, 64-bit
40+
[...]
41+
42+
Please include the git version in any bug reports.
43+
44+
You can also copy `mambo_memcheck` somewhere in your `PATH`, for example `/usr/local/bin`.
45+
46+
47+
Example output from a buggy application:
48+
---------------
49+
50+
$ mambo_memcheck ~/test
51+
52+
-- MAMBO memcheck 29f87421 --
53+
54+
==memcheck== Invalid store (size 4) to 0x3ffce462c8
55+
==memcheck== at [main]+0x60 (0x3ffffac978) in /home/cosmin/test
56+
==memcheck== Backtrace:
57+
==memcheck== at [__libc_start_main]+0xe4 (0x3ffd06c12c) in /usr/lib/libc-2.30.so
58+
==memcheck== at [(null)]+0x7e4 (0x3ffffac7e4) in /home/cosmin/test
59+
60+
==memcheck== Invalid load (size 4) from 0x3ffce462cc
61+
==memcheck== at [main]+0x80 (0x3ffffac998) in /home/cosmin/test
62+
==memcheck== Backtrace:
63+
==memcheck== at [__libc_start_main]+0xe4 (0x3ffd06c12c) in /usr/lib/libc-2.30.so
64+
==memcheck== at [(null)]+0x7e4 (0x3ffffac7e4) in /home/cosmin/test
65+
66+
==memcheck== double free for 0x3ffce466e0
67+
68+
69+
Advanced configuration
70+
----------------------
71+
72+
One of the more challenging aspects of this software is avoiding noisy false positive errors, e.g. harmless out-of-bounds reads in the hand written assembly code from glibc. We have implemented a number of techniques to avoid reporting such errors, which are documented and can be enabled or disabled in [memcheck.h](memcheck.h).

plugins/memcheck/memcheck.S

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
/*
2+
This file is part of MAMBO, a low-overhead dynamic binary modification tool:
3+
https://github.com/beehive-lab/mambo
4+
5+
Copyright 2017-2020 The University of Manchester
6+
7+
Licensed under the Apache License, Version 2.0 (the "License");
8+
you may not use this file except in compliance with the License.
9+
You may obtain a copy of the License at
10+
11+
http://www.apache.org/licenses/LICENSE-2.0
12+
13+
Unless required by applicable law or agreed to in writing, software
14+
distributed under the License is distributed on an "AS IS" BASIS,
15+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
See the License for the specific language governing permissions and
17+
limitations under the License.
18+
*/
19+
20+
#include "memcheck.h"
21+
22+
#ifdef __arm__
23+
.syntax unified
24+
#endif
25+
26+
// 1 to 3 arguments need to be preserved
27+
// (es-1) (X18/R3) is a pointer to <in_malloc>
28+
.global memcheck_malloc_pre
29+
.func
30+
memcheck_malloc_pre:
31+
#ifdef __aarch64__
32+
LDR X4, [X18]
33+
ADD X4, X4, #1
34+
STR X4, [X18]
35+
RET
36+
#elif __arm__
37+
LDR R12, [R3]
38+
ADD R12, R12, #1
39+
STR R12, [R3]
40+
BX LR
41+
#endif
42+
.endfunc
43+
44+
45+
// X0/R0 - address
46+
// (es-1) (X18/R3) is a pointer to <in_malloc>
47+
// (es) (X19/R4) - size
48+
.global memcheck_malloc_post
49+
.func
50+
memcheck_malloc_post:
51+
#ifdef __aarch64__
52+
LDR X2, [X18]
53+
SUB X2, X2, #1
54+
STR X2, [X18]
55+
56+
CBZ X0, mmp_ret
57+
58+
#ifdef COMPACT_SHADOW
59+
STP X0, X30, [SP, #-16]!
60+
MOV X1, X19
61+
BL memcheck_alloc_hook
62+
LDP X0, X30, [SP], #16
63+
#else
64+
MOV X1, #0x200000000
65+
STR X19, [X1, X0]
66+
STR X19, [X0]
67+
68+
MOV W4, #1
69+
MOV X2, #0x100000000
70+
MOV X3, X19
71+
ADD X2, X0, X2
72+
73+
mmp_loop:
74+
CBZ X3, mmp_ret
75+
STRB W4, [X2], #1
76+
SUB X3, X3, #1
77+
B mmp_loop
78+
#endif
79+
80+
mmp_ret:
81+
RET
82+
83+
#elif __arm__
84+
LDR R2, [R3]
85+
SUB R2, R2, #1
86+
STR R2, [R3]
87+
88+
CMP R0, #0
89+
BEQ mmp_ret
90+
91+
PUSH {R0, LR}
92+
MOV R1, R4
93+
BL memcheck_alloc_hook
94+
POP {R0, LR}
95+
96+
mmp_ret:
97+
BX LR
98+
#endif
99+
.endfunc
100+
101+
102+
// X0/R0 - address
103+
// (es-1) (X18/R3) is a pointer to <in_malloc>
104+
.global memcheck_free_pre
105+
.func
106+
memcheck_free_pre:
107+
#ifdef __aarch64__
108+
LDR X3, [X18]
109+
ADD X3, X3, #1
110+
STR X3, [X18]
111+
112+
#ifdef COMPACT_SHADOW
113+
STR X0, [SP, #-32]!
114+
STP X1, X30, [SP, #16]
115+
BL memcheck_free_hook
116+
LDP X1, X30, [SP, #16]
117+
LDR X0, [SP], #32
118+
#else
119+
MOV X2, #0x200000000
120+
LDR X2, [X2, X0]
121+
122+
MOV X3, #0x100000000
123+
ADD X3, X3, X0
124+
125+
mfp_l:
126+
CBZ X2, mfp_l_exit
127+
STRB WZR, [X3], #1
128+
SUB X2, X2, #1
129+
B mfp_l
130+
131+
mfp_l_exit:
132+
#endif
133+
RET
134+
135+
#elif __arm__
136+
LDR R2, [R3]
137+
ADD R2, R2, #1
138+
STR R2, [R3]
139+
140+
/* We don't really need to preserve the value of R2 here,
141+
but by pushing it we maintain stack alignment */
142+
PUSH {R0-R2, LR}
143+
BL memcheck_free_hook
144+
POP {R0-R2, PC}
145+
#endif
146+
.endfunc
147+
148+
149+
// (es-1) (X18/R3) is a pointer to <in_malloc>
150+
.global memcheck_free_post
151+
.func
152+
memcheck_free_post:
153+
#ifdef __aarch64__
154+
LDR X2, [X18]
155+
SUB X2, X2, #1
156+
STR X2, [X18]
157+
RET
158+
#elif __arm__
159+
LDR R2, [R3]
160+
SUB R2, R2, #1
161+
STR R2, [R3]
162+
BX LR
163+
#endif
164+
.endfunc
165+
166+
167+
// X0/R0 - access address
168+
// X1/R1 - access size | IS_STORE
169+
// X2/R2 - SPC
170+
// X3/R3 is a pointer to <in_malloc>
171+
// X4/R4 and LR are also pushed
172+
.global memcheck_unalloc
173+
.func
174+
#ifdef __arm__
175+
.thumb_func
176+
#endif
177+
memcheck_unalloc:
178+
#ifdef __aarch64__
179+
LDR X3, [X3]
180+
CBNZ X3, skip_err
181+
182+
STR X30, [SP, #-16]!
183+
184+
BL push_x4_x21
185+
MRS X19, NZCV
186+
MRS X20, FPCR
187+
MRS X21, FPSR
188+
BL push_neon
189+
190+
MOV X3, X29 // frame pointer
191+
BL memcheck_print_error
192+
193+
BL pop_neon
194+
MSR NZCV, X19
195+
MSR FPCR, X20
196+
MSR FPSR, X21
197+
BL pop_x4_x21
198+
199+
LDR X30, [SP], #16
200+
201+
skip_err:
202+
RET
203+
204+
#elif __arm__
205+
LDR R3, [R3]
206+
CBNZ R3, skip_err
207+
208+
PUSH {R5-R6, R9, R12, LR}
209+
VPUSH {d16-d31}
210+
VPUSH {d0-d7}
211+
212+
MRS r4, CPSR
213+
VMRS r5, FPSCR
214+
215+
// align the SP
216+
MOV R6, SP
217+
BIC R3, R6, #7
218+
MOV SP, R3
219+
220+
MOV R3, R11 // frame pointer
221+
BL memcheck_print_error
222+
223+
MOV SP, R6
224+
225+
VMSR FPSCR, r5
226+
MSR CPSR, r4
227+
228+
VPOP {d0-d7}
229+
VPOP {d16-d31}
230+
POP {R5-R6, R9, R12, LR}
231+
232+
skip_err:
233+
BX LR
234+
#endif
235+
.endfunc
236+
237+
238+
.global memcheck_ret
239+
.func
240+
memcheck_ret:
241+
#ifdef __aarch64__
242+
RET
243+
#elif __arm__
244+
BX LR
245+
#endif

0 commit comments

Comments
 (0)