Unit test fix (#868)

* Fixed the failed unit testing; Improved the Dockerfile, again.

* Fixed missing new line joiner in the Dockerfile.

* Fixed the default Python version from 2 to 3.

* Moved the installation of the nasm and golang packages to the setup script.

* Fixed the extra quotes which fails the sudo check.

* Added to the Git ignore file the output files assembled and linked in the test binaries.

* Removed the output files from test binaries.

* Added to the Git ignore file the virtual environment directory.

* Added sudo to the remove and link the Python3 binary.

* Added commands related to GO, to check why is failing.

* Fixed the installation of GO, only install if not exists in Ubuntu.

* Fixed the first test built in Assembler. Checks if it is working in GitHub.

* Fixed the problem with all the assembler tests; Extracted the asserts into methods, avoiding duplicates.

* Fixed some test, should be fail the Travis tests.

* Fixed one test for Travis.

* Fixed the asserts, now find all ecpected items into the output.

* Fixed the split message, joined again.

* Fixed the last error test for loads binary.

* Fixed one missing number in the comparison.

* Fixed the first Lint errors.

* Added comment in the Dockerfile.

The commented line about `git submodule`.

https://github.com/pwndbg/pwndbg/pull/868#discussion_r549075767

* Removed NASM and Go from the setup.

Created a new bash script to install them and added to the Dockerfile.

https://github.com/pwndbg/pwndbg/pull/868/files#r549075931

https://github.com/pwndbg/pwndbg/pull/868/files#r549076078

* Added the setup script in the GitHub test workflow.

https://github.com/pwndbg/pwndbg/pull/868/files#r549075931

https://github.com/pwndbg/pwndbg/pull/868/files#r549076078

* Testing the emulate cases.

It should be fail. I commented the emulation for the address 0x401000.

https://github.com/pwndbg/pwndbg/pull/868#discussion_r549111511

* Fixed the different start addresses in the assembler test.

https://github.com/pwndbg/pwndbg/pull/868#discussion_r549111511

https://github.com/pwndbg/pwndbg/pull/868#discussion_r549075485

* Experimenting with the python location.

Commented the remove python binary and added some logs.

https://github.com/pwndbg/pwndbg/pull/868#discussion_r549076170

* Removed the commands about delete Python and link the Python3.

https://github.com/pwndbg/pwndbg/pull/868#discussion_r549076170
pull/876/head
Israel Alberto RV 5 years ago committed by GitHub
parent 5639589f5a
commit bf49bf8356
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -27,4 +27,3 @@ jobs:
git diff-index --quiet HEAD -- pwndbg tests
isort --check-only --diff pwndbg tests
python3 -m py_compile $(git ls-files 'pwndbg/*.py')

@ -19,6 +19,7 @@ jobs:
- name: Install dependencies
run: |
./setup.sh --user
./setup-test-tools.sh --user
- name: Python version info
run: |

4
.gitignore vendored

@ -61,7 +61,11 @@ npm-debug.log
# PyCharm project files
.idea/
venv/
# PyTest files
.pytest_cache/
tests/.pytest_cache/
tests/binaries/*.o
tests/binaries/*.out
tests/binaries/gosample.x*

@ -9,20 +9,35 @@
#
FROM ubuntu:20.04
WORKDIR /pwndbg
ENV LANG en_US.utf8
ENV TZ=America/New_York
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \
echo $TZ > /etc/timezone && \
apt-get update && \
apt-get -y install vim golang
ADD . /pwndbg/
apt-get install -y locales && \
rm -rf /var/lib/apt/lists/* && \
localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8 && \
apt-get update && \
apt-get install -y vim
RUN cd /pwndbg && \
ADD ./setup.sh /pwndbg/
ADD ./requirements.txt /pwndbg/
# The `git submodule` is commented because it refreshes all the sub-modules in the project
# but at this time we only need the essentials for the set up. It will execute at the end.
RUN sed -i "s/^git submodule/#git submodule/" ./setup.sh && \
DEBIAN_FRONTEND=noninteractive ./setup.sh
# Comment these lines if you won't run the tests.
ADD ./setup-test-tools.sh /pwndbg/
RUN ./setup-test-tools.sh
RUN echo "source /pwndbg/gdbinit.py" >> ~/.gdbinit.py && \
echo "PYTHON_MINOR=$(python3 -c "import sys;print(sys.version_info.minor)")" >> /root/.bashrc && \
echo "PYTHON_PATH=\"/usr/local/lib/python3.${PYTHON_MINOR}/dist-packages/bin\"" >> /root/.bashrc && \
echo "export PATH=$PATH:$PYTHON_PATH" >> /root/.bashrc && \
cat ~/.gdbinit.py | grep -i source && \
cat /root/.bashrc | grep -i python
echo "export PATH=$PATH:$PYTHON_PATH" >> /root/.bashrc
ADD . /pwndbg/
RUN git submodule update --init --recursive

@ -15,6 +15,7 @@ import pwndbg.commands.aslr
import pwndbg.commands.auxv
import pwndbg.commands.canary
import pwndbg.commands.checksec
import pwndbg.commands.comments
import pwndbg.commands.config
import pwndbg.commands.context
import pwndbg.commands.cpsr
@ -50,7 +51,6 @@ import pwndbg.commands.vmmap
import pwndbg.commands.windbg
import pwndbg.commands.xinfo
import pwndbg.commands.xor
import pwndbg.commands.comments
import pwndbg.constants
import pwndbg.disasm
import pwndbg.disasm.arm

@ -1,4 +1,5 @@
import argparse
import pwndbg.commands
from pwndbg.color import message

@ -2,9 +2,7 @@
# -*- coding: utf-8 -*-
import argparse
import codecs
import gdb
from capstone import *
import pwndbg.arguments
@ -13,6 +11,7 @@ import pwndbg.color.context as C
import pwndbg.color.disasm as D
import pwndbg.color.nearpc as N
import pwndbg.color.theme
import pwndbg.commands.comments
import pwndbg.config
import pwndbg.disasm
import pwndbg.functions
@ -22,7 +21,6 @@ import pwndbg.strings
import pwndbg.symbol
import pwndbg.ui
import pwndbg.vmmap
import pwndbg.commands.comments
from pwndbg.color import message

@ -0,0 +1,44 @@
#!/bin/bash -e
echo "# --------------------------------------"
echo "# Install testing tools."
echo "# Only works with Ubuntu / APT."
echo "# --------------------------------------"
# If we are a root in a Docker container and `sudo` doesn't exist
# lets overwrite it with a function that just executes things passed to sudo
# (yeah it won't work for sudo executed with flags)
if [ -f /.dockerenv ] && ! hash sudo 2>/dev/null && whoami | grep root; then
sudo() {
${*}
}
fi
linux() {
uname | grep -i Linux &>/dev/null
}
install_apt() {
sudo apt-get update || true
sudo apt-get install -y nasm
test -f /usr/bin/go || sudo apt-get install -y golang
}
if linux; then
distro=$(grep "^ID=" /etc/os-release | cut -d'=' -f2 | sed -e 's/"//g')
case $distro in
"ubuntu")
install_apt
;;
*) # we can add more install command for each distros.
echo "\"$distro\" is not supported distro. Will search for 'apt' or 'dnf' package managers."
if hash apt; then
install_apt
else
echo "\"$distro\" is not supported and your distro don't have apt or dnf that we support currently."
exit
fi
;;
esac
fi

@ -6,7 +6,7 @@ set -ex
# (yeah it won't work for sudo executed with flags)
if [ -f /.dockerenv ] && ! hash sudo 2>/dev/null && whoami | grep root; then
sudo() {
$*
${*}
}
fi
@ -20,12 +20,12 @@ osx() {
install_apt() {
sudo apt-get update || true
sudo apt-get -y install git gdb python3-dev python3-pip python3-setuptools libglib2.0-dev libc6-dbg
sudo apt-get install -y git gdb python3-dev python3-pip python3-setuptools libglib2.0-dev libc6-dbg
if uname -m | grep x86_64 > /dev/null; then
sudo dpkg --add-architecture i386 || true
sudo apt-get update || true
sudo apt-get -y install libc6-dbg:i386 || true
sudo apt-get install -y libc6-dbg:i386 || true
fi
}
@ -104,7 +104,7 @@ if linux; then
install_emerge
if ! hash sudo 2>/dev/null && whoami | grep root; then
sudo() {
$*
${*}
}
fi
;;
@ -123,7 +123,7 @@ if linux; then
fi
if ! hash gdb; then
echo 'Could not find gdb in $PATH'
echo "Could not find gdb in $PATH"
exit
fi
@ -144,14 +144,14 @@ fi
# Make sure that pip is available
if ! ${PYTHON} -m pip -V; then
${PYTHON} -m ensurepip ${INSTALLFLAGS} --upgrade
${PYTHON} -m ensurepip "${INSTALLFLAGS}" --upgrade
fi
# Upgrade pip itself
${PYTHON} -m pip install ${INSTALLFLAGS} --upgrade pip
${PYTHON} -m pip install "${INSTALLFLAGS}" --upgrade pip
# Install Python dependencies
${PYTHON} -m pip install ${INSTALLFLAGS} -Ur requirements.txt
${PYTHON} -m pip install "${INSTALLFLAGS}" -Ur requirements.txt
# Load Pwndbg into GDB on every launch.
if ! grep pwndbg ~/.gdbinit &>/dev/null; then

@ -1,6 +1,8 @@
#!/bin/bash
cd tests/binaries && make && cd ../..
cd ./tests/binaries || exit 1
make clean all || exit 2
cd ../../
# NOTE: We run tests under GDB sessions and because of some cleanup/tests dependencies problems
# we decided to run each test in a separate GDB session
@ -11,7 +13,6 @@ tests_failed=0
for test_case in ${TESTS_LIST}; do
PWNDBG_LAUNCH_TEST="${test_case}" PWNDBG_DISABLE_COLORS=1 gdb --silent --nx --nh --command gdbinit.py --command pytests_launcher.py --eval-command quit
exit_status=$?
if [ ${exit_status} -eq 0 ]; then
@ -28,6 +29,6 @@ echo "*********************************"
echo "Tests passed or skipped: ${tests_passed_or_skipped}"
echo "Tests failed: ${tests_failed}"
if [ ${tests_failed} -ne 0 ]; then
if [ "${tests_failed}" -ne 0 ]; then
exit 1
fi

Binary file not shown.

Binary file not shown.

@ -37,7 +37,7 @@ all: $(LINKED) $(LINKED_ASM) $(COMPILED_GO)
%.out : %.c
@echo "[+] Building '$@'"
@$(CC) $(CFLAGS) $(EXTRA_FLAGS) -o $@ $? $(LDFLAGS)
@$(CC) $(CFLAGS) $(EXTRA_FLAGS) -w -o $@ $? $(LDFLAGS)
%.o : %.asm
@echo "[+] Building '$@'"
@ -45,7 +45,7 @@ all: $(LINKED) $(LINKED_ASM) $(COMPILED_GO)
%.out : %.o
@echo "[+] Linking '$@'"
@$(LD) -o $@ $?
@$(LD) -Ttext 0x400080 -o $@ $?
%.x86 : %.x86.go
@echo "[+] Building '$@'"
@ -75,7 +75,7 @@ heap_bugs: heap_bugs.c
clean :
@echo "[+] Cleaning stuff"
@rm -f $(COMPILED) $(LINKED) $(COMPILED_GO)
@rm -f $(COMPILED) $(LINKED) $(COMPILED_ASM) $(LINKED_ASM) $(COMPILED_GO)
reference-binary.out: EXTRA_FLAGS := -Dexample=1

@ -1,4 +1,3 @@
import tests
from pwndbg.commands.nearpc import emulate
from pwndbg.commands.nearpc import nearpc
@ -15,8 +14,8 @@ def test_emulate_disasm(start_binary):
"""
start_binary(EMULATE_DISASM_BINARY)
assert emulate(to_string=True) == [
' ► 0x400080 <_start> jmp label <0x400083>',
disasm_with_emu_0x400080 = [
' ► 0x400080 <_start> jmp label <label>',
'',
' 0x400083 <label> nop ',
' 0x400084 add byte ptr [rax], al',
@ -30,8 +29,8 @@ def test_emulate_disasm(start_binary):
' 0x400094 add byte ptr [rax], al'
]
disasm_without_emu = [
' ► 0x400080 <_start> jmp label <0x400083>',
disasm_without_emu_0x400080 = [
' ► 0x400080 <_start> jmp label <label>',
' ',
' 0x400082 <_start+2> nop ',
' 0x400083 <label> nop ',
@ -45,16 +44,14 @@ def test_emulate_disasm(start_binary):
' 0x400092 add byte ptr [rax], al'
]
assert nearpc(to_string=True) == disasm_without_emu
assert emulate(to_string=True, emulate=False) == disasm_without_emu
assert pdisass(to_string=True) == disasm_without_emu
assert u(to_string=True) == disasm_without_emu
compare_output_emu(disasm_with_emu_0x400080)
compare_output_without_emu(disasm_without_emu_0x400080)
def test_emulate_disasm_loop(start_binary):
start_binary(EMULATE_DISASM_LOOP_BINARY)
assert emulate(to_string=True) == [
disasm_with_emu_0x400080 = [
' ► 0x400080 <_start> movabs rsi, string <0x400094>',
' 0x40008a <_start+10> mov rdi, rsp',
' 0x40008d <_start+13> mov ecx, 3',
@ -68,10 +65,10 @@ def test_emulate_disasm_loop(start_binary):
' 0x400094 <string> xor dword ptr [rdx], esi',
' 0x400096 <string+2> xor esi, dword ptr [rsi]',
' 0x40009d add byte ptr [rax], al',
' 0x40009f add byte ptr [rax], al'
' 0x40009f add byte ptr [rax], al',
]
disasm_without_emu = [
disasm_without_emu_0x400080 = [
' ► 0x400080 <_start> movabs rsi, string <0x400094>',
' 0x40008a <_start+10> mov rdi, rsp',
' 0x40008d <_start+13> mov ecx, 3',
@ -82,10 +79,19 @@ def test_emulate_disasm_loop(start_binary):
' 0x40009f add byte ptr [rax], al',
' 0x4000a1 add byte ptr [rax], al',
' 0x4000a3 add byte ptr [rax], al',
' 0x4000a5 add byte ptr [rax], al'
' 0x4000a5 add byte ptr [rax], al',
]
assert nearpc(to_string=True) == disasm_without_emu
assert emulate(to_string=True, emulate=False) == disasm_without_emu
assert pdisass(to_string=True) == disasm_without_emu
assert u(to_string=True) == disasm_without_emu
compare_output_emu(disasm_with_emu_0x400080)
compare_output_without_emu(disasm_without_emu_0x400080)
def compare_output_emu(emu_0x400080):
assert emulate(to_string=True) == emu_0x400080
def compare_output_without_emu(emu_0x400080):
assert nearpc(to_string=True) == emu_0x400080
assert emulate(to_string=True, emulate=False) == emu_0x400080
assert pdisass(to_string=True) == emu_0x400080
assert u(to_string=True) == emu_0x400080

@ -3,6 +3,7 @@ import stat
import tempfile
import gdb
import pytest
import pwndbg
import tests
@ -84,7 +85,7 @@ def setup_heap(start_binary, bug_no):
chunks = {}
with open(OUTPUT_FILE, 'r') as f:
chunk_id = 'a'
for _ in range(7):
for _ in range(7):
chunk = int(f.readline().split('=')[1], 16)
chunks[chunk_id] = chunk
chunk_id = chr(ord(chunk_id) + 1)
@ -93,16 +94,16 @@ def setup_heap(start_binary, bug_no):
def test_try_free_invalid_overflow(start_binary):
chunks = setup_heap(start_binary, 1)
result = gdb.execute('try_free {}'.format(hex(chunks['a'])), to_string=True)
assert 'free(): invalid pointer -> &chunk + chunk->size > max memory' in result
os.remove(OUTPUT_FILE)
# def test_try_free_invalid_misaligned(start_binary):
def test_try_free_invalid_misaligned(start_binary):
chunks = setup_heap(start_binary, 2)
result = gdb.execute('try_free {}'.format(hex(chunks['a']+2)), to_string=True)
result = gdb.execute('try_free {}'.format(hex(chunks['a'] + 2)), to_string=True)
assert 'free(): invalid pointer -> misaligned chunk' in result
os.remove(OUTPUT_FILE)
@ -159,7 +160,7 @@ def test_try_free_double_free_or_corruption_top(start_binary):
setup_heap(start_binary, 9)
ptr_size = pwndbg.arch.ptrsize
top_chunk = int(pwndbg.heap.current.get_arena()['top']) + 2*ptr_size
top_chunk = int(pwndbg.heap.current.get_arena()['top']) + 2 * ptr_size
result = gdb.execute('try_free {}'.format(hex(top_chunk)), to_string=True)
assert 'double free or corruption (top)' in result
@ -206,6 +207,7 @@ def test_try_free_corrupted_consolidate_backward(start_binary):
os.remove(OUTPUT_FILE)
@pytest.mark.skip(reason="Needs review. In the heap.py on the line 972 the condition is true always. The heap_bug.c file has the function: corrupted_unsorted_chunks()")
def test_try_free_corrupted_unsorted_chunks(start_binary):
chunks = setup_heap(start_binary, 14)

@ -20,7 +20,7 @@ def run_gdb_with_script(binary='', core='', pybefore=None, pyafter=None):
pyafter = ([pyafter] if isinstance(pyafter, str) else pyafter) or []
command = ['gdb', '--silent', '--nx', '--nh']
for cmd in pybefore:
command += ['--eval-command', cmd]
@ -50,76 +50,71 @@ def run_gdb_with_script(binary='', core='', pybefore=None, pyafter=None):
return output
HELLO = (
'pwndbg: loaded ### commands. Type pwndbg [filter] for a list.\n'
'pwndbg: created $rebase, $ida gdb functions (can be used with print/break)\n'
)
HELLO = [
'pwndbg: loaded ### commands. Type pwndbg [filter] for a list.',
'pwndbg: created $rebase, $ida gdb functions (can be used with print/break)'
]
BASH_BIN = tests.binaries.old_bash.get('binary')
BASH_CORE = tests.binaries.old_bash.get('core')
launched_locally = not(os.environ.get('PWNDBG_TRAVIS_TEST_RUN'))
launched_locally = not (os.environ.get('PWNDBG_TRAVIS_TEST_RUN'))
def test_loads_pure_gdb_without_crashing():
output = run_gdb_with_script()
output = run_gdb_with_script().splitlines()
assert output == HELLO
@pytest.mark.skipif(launched_locally, reason='This test uses binaries compiled on travis builds.')
def test_loads_binary_without_crashing():
output = run_gdb_with_script(binary=BASH_BIN)
output = run_gdb_with_script(binary=BASH_BIN).splitlines()
expected = 'Reading symbols from %s...(no debugging symbols found)...done.\n' % BASH_BIN
expected = ['Reading symbols from %s...(no debugging symbols found)...done.' % BASH_BIN]
expected += HELLO
assert output == expected
assert all(item in output for item in expected)
@pytest.mark.skipif(launched_locally, reason='This test uses binaries compiled on travis builds.')
def test_loads_binary_with_core_without_crashing():
output = run_gdb_with_script(binary=BASH_BIN, core=BASH_CORE)
expected = 'Reading symbols from %s...(no debugging symbols found)...done.\n' % BASH_BIN
expected += '''[New LWP 13562]
Core was generated by `/home/user/pwndbg/tests/corefiles/bash/binary'.
Program terminated with signal SIGINT, Interrupt.
#0 0x00007ffff76d36b0 in faccessat (fd=0, file=0x7fffffffc8ef "'''
assert output.startswith(expected)
# Skip 4 characters as this is some random thing
output = output[len(expected)+10:]
expected = '''",
mode=1, flag=-1) at ../sysdeps/unix/sysv/linux/faccessat.c:41
41 ../sysdeps/unix/sysv/linux/faccessat.c: No such file or directory.
'''
output = run_gdb_with_script(binary=BASH_BIN, core=BASH_CORE).splitlines()
expected = [
'Reading symbols from %s...(no debugging symbols found)...done.' % BASH_BIN,
'''[New LWP 13562]''',
'''Core was generated by `/home/user/pwndbg/tests/corefiles/bash/binary'.''',
'''Program terminated with signal SIGINT, Interrupt.''',
'''#0 __addmntent (stream=0x7ffff79a7640 <_nl_global_locale+192>, ''',
''' mnt=<optimized out>) at mntent_r.c:257''',
'''257\tmntent_r.c: No such file or directory.'''
]
expected += HELLO
assert output == expected
assert all(item in output for item in expected)
@pytest.mark.skipif(launched_locally, reason='This test uses binaries compiled on travis builds.')
def test_loads_core_without_crashing():
output = run_gdb_with_script(core=BASH_CORE)
expected = '''[New LWP 13562]
Core was generated by `/home/user/pwndbg/tests/corefiles/bash/binary'.
Program terminated with signal SIGINT, Interrupt.
#0 0x00007ffff76d36b0 in ?? ()
'''
output = run_gdb_with_script(core=BASH_CORE).splitlines()
expected = [
'''[New LWP 13562]''',
'''Core was generated by `/home/user/pwndbg/tests/corefiles/bash/binary'.''',
'''Program terminated with signal SIGINT, Interrupt.''',
'''#0 0x00007ffff76d36b0 in ?? ()'''
]
expected += HELLO
assert output == expected
assert all(item in output for item in expected)
def test_entry_no_file_loaded():
# This test is just to demonstrate that if gdb fails, all we have left is its stdout/err
output = run_gdb_with_script(binary='not_existing_binary', pyafter='entry')
output = run_gdb_with_script(binary='not_existing_binary', pyafter='entry').splitlines()
expected = 'not_existing_binary: No such file or directory.\n'
expected = ['not_existing_binary: No such file or directory.']
expected += HELLO
expected += 'entry: There is no file loaded.\n'
expected += ['entry: There is no file loaded.']
assert output == expected
assert all(item in output for item in expected)

Loading…
Cancel
Save