Skip to content

Commit

Permalink
Adding unit tests for non-x86 architectures (#720)
Browse files Browse the repository at this point in the history
* Use `pytest` on top of `unittest` to allow multi-proc execution
  • Loading branch information
hugsy committed Sep 24, 2021
1 parent 1df157e commit 143e60a
Show file tree
Hide file tree
Showing 16 changed files with 226 additions and 100 deletions.
13 changes: 12 additions & 1 deletion .github/workflows/run-tests.yml
Expand Up @@ -16,7 +16,11 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04, ubuntu-18.04]
os:
- ubuntu-20.04
- ubuntu-18.04
# - [self-hosted, linux, ARM64]
# - [self-hosted, linux, ARM]
name: "Run Unit tests on ${{ matrix.os }}"
runs-on: ${{ matrix.os }}
defaults:
Expand All @@ -32,6 +36,11 @@ jobs:
sudo apt-get install -y gdb-multiarch python3-dev python3-pip python3-wheel python3-setuptools git cmake gcc g++ pkg-config libglib2.0-dev gdbserver
sudo python3 -m pip install --upgrade pip
- name: Set architecture specific properties
id: set-arch-properties
run: |
echo "::set-output name=arch::$(uname --processor)"
- name: Get pip cache dir
id: pip-cache
run: |
Expand Down Expand Up @@ -67,5 +76,7 @@ jobs:
make lint
- name: Run Tests
env:
GEF_CI_ARCH: ${{ steps.set-arch-properties.outputs.arch }}
run: |
make test
4 changes: 2 additions & 2 deletions Makefile
Expand Up @@ -4,7 +4,7 @@ PYLINT_ENABLE := F,E,unreachable,duplicate-key,unnecessary-semicolon,global-vari
PYLINT_JOBS := $(NB_CORES)
PYLINT_SUGGEST_FIX := y
PYLINT_PARAMETERS := --disable=$(PYLINT_DISABLE) --enable=$(PYLINT_ENABLE) --jobs=$(PYLINT_JOBS) --suggestion-mode=$(PYLINT_SUGGEST_FIX) --exit-zero

TARGET := $(shell lscpu | head -1 | sed -e 's/Architecture:\s*//g')

test: testbins
@cp gef.py /tmp/gef.py
Expand All @@ -20,7 +20,7 @@ Test%: testbins
@rm -f /tmp/gef-*

testbins: tests/binaries/*.c
@$(MAKE) -j $(NB_CORES) -C tests/binaries all
@$(MAKE) -j $(NB_CORES) -C tests/binaries TARGET=$(TARGET) all

lint:
python3 -m pylint $(PYLINT_PARAMETERS) gef.py
Expand Down
15 changes: 9 additions & 6 deletions gef.py
Expand Up @@ -2124,9 +2124,12 @@ def mprotect_asm(cls, addr, size, perm):
_NR_mprotect = 125
insns = [
"push {r0-r2, r7}",
"mov r0, {:d}".format(addr),
"mov r1, {:d}".format(size),
"mov r2, {:d}".format(perm),
"mov r1, {:d}".format(addr & 0xffff),
"mov r0, {:d}".format((addr & 0xffff0000) >> 16),
"lsl r0, r0, 16",
"add r0, r0, r1",
"mov r1, {:d}".format(size & 0xffff),
"mov r2, {:d}".format(perm & 0xff),
"mov r7, {:d}".format(_NR_mprotect),
"svc 0",
"pop {r0-r2, r7}",
Expand All @@ -2136,7 +2139,7 @@ def mprotect_asm(cls, addr, size, perm):

class AARCH64(ARM):
arch = "ARM64"
mode = "ARM"
mode = ""

all_registers = [
"$x0", "$x1", "$x2", "$x3", "$x4", "$x5", "$x6", "$x7",
Expand Down Expand Up @@ -4741,7 +4744,7 @@ def __init__(self):
def do_invoke(self, argv, *args, **kwargs):
"""Default value for print-format command."""
args = kwargs["arguments"]
args.bitlen = args.bitlen or current_arch.ptrsize
args.bitlen = args.bitlen or current_arch.ptrsize * 2

valid_bitlens = self.format_matrix.keys()
if args.bitlen not in valid_bitlens:
Expand Down Expand Up @@ -7694,7 +7697,7 @@ class AssembleCommand(GenericCommand):
# Format: ARCH = [MODES] with MODE = (NAME, HAS_LITTLE_ENDIAN, HAS_BIG_ENDIAN)
"ARM": [("ARM", True, True), ("THUMB", True, True),
("ARMV8", True, True), ("THUMBV8", True, True)],
"ARM64": [("AARCH64", True, False)],
"ARM64": [("0", True, False)],
"MIPS": [("MIPS32", True, True), ("MIPS64", True, True)],
"PPC": [("PPC32", False, True), ("PPC64", True, True)],
"SPARC": [("SPARC32", True, True), ("SPARC64", False, True)],
Expand Down
2 changes: 1 addition & 1 deletion tests/binaries/Makefile
Expand Up @@ -7,7 +7,7 @@ LDFLAGS =
EXTRA_FLAGS =
BINDIR = /tmp

ifeq ($(TARGET), x86)
ifeq ($(TARGET), i686)
CFLAGS += -m32
endif

Expand Down
3 changes: 2 additions & 1 deletion tests/binaries/bss.c
Expand Up @@ -8,12 +8,13 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "utils.h"

char msg[0x100];

int main(int argc, char** argv, char** envp)
{
strncpy(msg, "Hello world!", sizeof(msg));
__builtin_trap();
DebugBreak();
return EXIT_SUCCESS;
}
8 changes: 5 additions & 3 deletions tests/binaries/heap-fastbins.c
Expand Up @@ -10,20 +10,22 @@
* to test the fastbins the tcache has to be disabled through the environment in GDB:
* `set environment GLIBC_TUNABLES glibc.malloc.tcache_count=0`
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
#include "utils.h"

int main()
{
void* p1 = malloc(0x10);
void* p2 = malloc(0x20);
void* p3 = malloc(0x30);
memset(p1, 'A', 0x10);
memset(p2, 'B', 0x20);
memset(p3, 'C', 0x30);
free(p2);
__builtin_trap();
DebugBreak();
(void)p1;
(void)p3;
return EXIT_SUCCESS;
Expand Down
3 changes: 2 additions & 1 deletion tests/binaries/heap-non-main.c
Expand Up @@ -6,13 +6,14 @@
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "utils.h"

void *thread()
{
void* p1 = malloc(0x18);
void* p2 = malloc(0x18);
free(p1);
__builtin_trap();
DebugBreak();
(void)p2;

return NULL;
Expand Down
3 changes: 2 additions & 1 deletion tests/binaries/heap-tcache.c
Expand Up @@ -2,6 +2,7 @@
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include "utils.h"

void *thread1(void *vargp)
{
Expand Down Expand Up @@ -33,6 +34,6 @@ int main()
pthread_create(&thread_id1, NULL, thread1, NULL);
pthread_create(&thread_id2, NULL, thread2, NULL);
sleep(1);
__builtin_trap();
DebugBreak();
exit(0);
}
6 changes: 4 additions & 2 deletions tests/binaries/heap.c
Expand Up @@ -12,12 +12,14 @@
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include "utils.h"

void* p1 = NULL;

int main(int argc, char** argv, char** envp)
{
void* p1 = malloc(0x20);
__builtin_trap();
p1 = malloc(0x20);
DebugBreak();
(void)p1;
return EXIT_SUCCESS;
}
4 changes: 2 additions & 2 deletions tests/binaries/memwatch.c
@@ -1,12 +1,12 @@
#include<stdio.h>
#include<stdlib.h>

#include "utils.h"
int myglobal = 1;

int main(int argc, char** argv)
{
// breakpoints hardcoded for convenience
myglobal = strtoll(argv[1], NULL, 16);
__builtin_trap();
DebugBreak();
return 0;
}
3 changes: 2 additions & 1 deletion tests/binaries/nested.c
@@ -1,4 +1,5 @@
void f10(){ __builtin_trap(); }
#include "utils.h"
void f10(){ DebugBreak(); }
void f9(){ f10(); }
void f8(){ f9(); }
void f7(){ f8(); }
Expand Down
3 changes: 2 additions & 1 deletion tests/binaries/nested2.c
@@ -1,2 +1,3 @@
int f1(int i){ if(i==10) {__builtin_trap(); return 0;} return f1(++i); }
#include "utils.h"
int f1(int i){ if(i==10) {DebugBreak(); return 0;} return f1(++i); }
int main(){ return f1(0); }
4 changes: 3 additions & 1 deletion tests/binaries/set-permission.c
Expand Up @@ -14,6 +14,8 @@
#include <unistd.h>
#include <sys/mman.h>

#include "utils.h"

int main(int argc, char** argv, char** envp)
{
void *p = mmap((void *)0x1337000,
Expand All @@ -26,7 +28,7 @@ int main(int argc, char** argv, char** envp)
if( p == (void *)-1)
return EXIT_FAILURE;

__builtin_trap();
DebugBreak();

return EXIT_SUCCESS;
}
36 changes: 36 additions & 0 deletions tests/binaries/utils.h
@@ -0,0 +1,36 @@
#include <signal.h>

/**
* Provide an cross-architecture way to break into the debugger.
* On some architectures, we resort to `raise(SIGINT)` which is not
* optimal, as it adds an extra frame to the stack.
*/

/* Intel x64 */
#if defined(__x86_64__)
#define DebugBreak() __asm__("int $3")

/* Intel x32 */
#elif defined(__i386) || defined(i386) || defined(__i386__)
#define DebugBreak() __asm__("int $3")

/* AARCH64 */
#elif defined(__aarch64__)
#define DebugBreak() { raise( SIGINT ) ; }

/* ARM */
#elif defined(__arm__) || defined(__arm)
#define DebugBreak() { raise( SIGINT ) ; }

/* MIPS */
#elif defined(mips) || defined(__mips__) || defined(__mips)
#define DebugBreak() __builtin_trap()

/* PowerPC */
#elif defined(__powerpc) || defined(__powerpc__) || defined(__powerpc64__) || defined(__POWERPC__) || defined(__ppc__) || defined(__PPC__) || defined(_ARCH_PPC)
#define DebugBreak() __builtin_trap()

/* the rest */
#else
#error "Unsupported architecture"
#endif

0 comments on commit 143e60a

Please sign in to comment.