Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Update Panda Debian Package to be more closely follow Debian Package standards #1546

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/publish_docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:

- name: Build package
working-directory: panda/debian
run: ./setup.sh Ubuntu ${{ matrix.ubuntu_version }}
run: ./setup.sh Ubuntu ${{ matrix.ubuntu_version }} ${{ needs.create_release.outputs.v-version }}

- name: Upload wheel and debian packages to release
uses: softprops/action-gh-release@v2
Expand Down
3 changes: 2 additions & 1 deletion hw/avatar/configurable_machine.c
Original file line number Diff line number Diff line change
Expand Up @@ -438,8 +438,9 @@ static void set_entry_point(QDict *conf, THISCPU *cpuu)
cpuu->env.active_tc.PC = entry;

#elif defined(TARGET_PPC)
cpuu->env.nip = entry;
//Not implemented yet
fprintf(stderr, "Not yet implemented- can't start execution at 0x%x\n", entry);
//fprintf(stderr, "Not yet implemented- can't start execution at 0x%x\n", entry);
#endif

}
Expand Down
3 changes: 2 additions & 1 deletion panda/debian/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
panda.deb
*.deb
*.whl
26 changes: 21 additions & 5 deletions panda/debian/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
ARG PACKAGE_VERSION=""

# First run the main Dockerfile to build the base image and name it panda. Then we run here
# to generate a debian package

FROM debian:buster-slim
FROM debian:bookworm-slim

# Install necessary tools for packaging
RUN apt-get -qq update && \
Expand All @@ -13,14 +15,28 @@ COPY --from=panda /tmp/base_dep.txt /tmp
COPY --from=panda /tmp/build_dep.txt /tmp

# Set up /package-root with files from panda we'll package
COPY --from=panda /usr/local/bin/panda* /usr/local/bin/libpanda* /usr/local/bin/qemu-img /package-root/usr/local/bin/
COPY --from=panda /usr/local/etc/panda /package-root/usr/local/etc/panda
COPY --from=panda /usr/local/lib/panda /package-root/usr/local/lib/panda
COPY --from=panda /usr/local/share/panda /package-root/usr/local/share/panda
COPY --from=panda /usr/local/bin/panda* /usr/bin/libpanda* /usr/bin/qemu-img /package-root/usr/bin/
COPY --from=panda /usr/local/etc/panda /package-root/etc/
COPY --from=panda /usr/local/lib/panda /package-root/usr/lib/
COPY --from=panda /usr/local/share/panda /package-root/usr/share/

# Copy documentation over, we should have a better Changelog if we go for official release?
COPY ./LICENSE /package-root/usr/share/doc/panda
COPY ./README.md /package-root/usr/share/doc/panda

# Create DEBIAN directory and control file
COPY control /package-root/DEBIAN/control

# Generate MD5 checksums for all files and save to DEBIAN/md5sums
RUN cd /package-root && \
find . -type f ! -path './DEBIAN/*' -exec md5sum {} + | sed 's| \./| |' > /package-root/DEBIAN/md5sums

# Update control file with the correct version, and place installed size
ARG PACKAGE_VERSION
RUN INSTALLED_SIZE=$(du -sk /package-root | cut -f1) && \
sed -i "s/^Installed-Size:.*/Installed-Size: ${INSTALLED_SIZE}/" /package-root/DEBIAN/control
RUN sed -i "s/^Version:.*/Version: ${PACKAGE_VERSION}/" /package-root/DEBIAN/control

# Update control file with dependencies
# Build time. We only select dependencies that are not commented out or blank
RUN dependencies=$(grep '^[a-zA-Z]' /tmp/build_dep.txt | tr '\n' ',' | sed 's/,,\+/,/g'| sed 's/,$//') && \
Expand Down
14 changes: 10 additions & 4 deletions panda/debian/control
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
Package: pandare
Version: 3.1.0
Architecture: all
Package: panda
Source: MITLL
Version: <version-placeholder>
Architecture: amd64
BUILD_DEPENDS_LIST
DEPENDS_LIST
Maintainer: Andrew Fasano <fasano@mit.edu>
Maintainer: Luke Craig <luke.craig@ll.mit.edu>
Installed-Size: <size-in-kb>
Section: devel
Priority: optional
Multi-Arch: same
Homepage: https://panda.re/
Description: dynamic analysis platform
Platform for Architecture Neutral Dynamic Analysis (PANDA) is a processor
emulator designed to support analyses of guest code. PANDA supports record-
Expand Down
22 changes: 19 additions & 3 deletions panda/debian/setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,33 @@ if [[ $# -eq 1 ]]; then
echo " To build a package for current Ubuntu version:"
echo " $0"
echo " To build a package for a specific OS/version (only Ubuntu supported for now):"
echo " $0 <OS> <version>"
echo " $0 <OS> <ubuntu-version> <tag-version>"
exit 1
fi

if [[ $# -eq 2 ]]; then
version=$2

else
version=$(lsb_release -r | awk '{print $2}')
fi

if [[ $# -eq 3 ]]; then
tag_version=$3
else
tag_version='v3.1.0'
fi

# Remove leading 'v' if present, e. g. v1.5.1 -> 1.5.1
if [[ "$tag_version" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
tag_version=${tag_version:1}
fi

# Check if the version follows the format X.Y.Z, e. g. 1.5.1 or 1.9.1
if [[ ! "$tag_version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "ERROR: Version must be in the format X.Y.Z, provided tag version: $tag_version"
exit 1
fi

# Check if the given version is supported
if [[ ! -f "../dependencies/ubuntu_${version}_base.txt" ]]; then
echo "ERROR: Ubuntu ${version} is not supported, no dependencies file found"
Expand All @@ -53,7 +69,7 @@ docker run --rm -v $(pwd):/out panda bash -c "cp /panda/panda/python/core/dist/*
DOCKER_BUILDKIT=1 docker build --target panda -t panda --build-arg BASE_IMAGE="ubuntu:${version}" ../..

# Now build the packager container from that
docker build -t packager .
docker build -t packager --build-arg PACKAGE_VERSION="${tag_version}" .

# Copy deb file out of container to host
docker run --rm -v $(pwd):/out packager bash -c "cp /pandare.deb /out"
Expand Down
2 changes: 1 addition & 1 deletion panda/plugins/osi_linux/osi_linux.h
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ static inline char *read_dentry_name(CPUState *env, target_ptr_t dentry) {
#endif
OG_printf("Pcomp length %d\n", pcomp_length);
if (pcomp_length == (uint32_t)-1) { // Not sure why this happens, but it does
printf("Warning: OSI_linux Unhandled pcomp value, ignoring\n");
OG_printf("Warning: OSI_linux Unhandled pcomp value, ignoring\n");
break;
}

Expand Down
143 changes: 98 additions & 45 deletions panda/python/core/pandare/arch.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def _determine_bits(self):
endianness = "big"
elif self.panda.arch_name == "mips64el":
bits = 64
endianness = "big"
endianness = "little"

assert (bits is not None), f"Missing num_bits logic for {self.panda.arch_name}"
assert (endianness is not None), f"Missing endianness logic for {self.panda.arch_name}"
Expand Down Expand Up @@ -369,7 +369,7 @@ def __init__(self, panda):
regnames = ["X0", "X1", "X2", "X3", "X4", "X5", "X6", "X7",
"XR", "X9", "X10", "X11", "X12", "X13", "X14",
"X15", "IP0", "IP1", "PR", "X19", "X20", "X21",
"X22", "X23", "X24", "X25", "X26", "X27", "X27",
"X22", "X23", "X24", "X25", "X26", "X27",
"X28", "FP", "LR", "SP"]

self.reg_sp = regnames.index("SP")
Expand Down Expand Up @@ -601,6 +601,7 @@ def set_retval(self, cpu, val, convention='default', failure=False):

return super().set_retval(cpu, val, convention)


class Mips64Arch(MipsArch):
'''
Register names and accessors for MIPS64. Inherits from MipsArch for everything
Expand Down Expand Up @@ -629,67 +630,71 @@ def __init__(self, panda):
# note names must be stored uppercase for get/set reg to work case-insensitively
self.registers = {regnames[idx].upper(): idx for idx in range(len(regnames)) }

class X86Arch(PandaArch):
class PowerPCArch(PandaArch):
'''
Register names and accessors for x86
Register names and accessors for ppc
'''

def __init__(self, panda):
def __init__(self, panda):
super().__init__(panda)
regnames = ['EAX', 'ECX', 'EDX', 'EBX', 'ESP', 'EBP', 'ESI', 'EDI']
# XXX Note order is A C D B, because that's how qemu does it . See target/i386/cpu.h

# Note we don't set self.call_conventions because stack-based arg get/set is
# not yet supported
self.reg_retval = {"default": "EAX",
"syscall": "EAX",
"linux_kernel": "EAX"}

self.call_conventions = {"cdecl": [f"stack_{x}" for x in range(20)], # 20: arbitrary but big
"syscall": ["EAX", "EBX", "ECX", "EDX", "ESI", "EDI", "EBP"],
"linux_kernel": ["EAX", "EDX", "ECX", "stack_3", "stack_4", "stack_5", "stack_6"]}
self.call_conventions['default'] = self.call_conventions['cdecl']

self.reg_sp = regnames.index('ESP')
self.registers = {regnames[idx]: idx for idx in range(len(regnames)) }

regnames = ["r0", "sp", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11",
"r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", "r22",
"r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"]
self.reg_sp = regnames.index('sp')
self.registers = {regnames[idx].upper(): idx for idx in range(len(regnames)) }
self.registers_crf = ["CR0", "CR1", "CR2", "CR3", "CR4", "CR5", "CR6", "CR7"]

def get_pc(self, cpu):
'''
Overloaded function to return the x86 current program counter
Overloaded function to return the ppc current program counter
'''
return cpu.env_ptr.eip
return cpu.env_ptr.nip

def set_pc(self, cpu, val):
'''
Overloaded function to set the x86 program counter
Overloaded function to set the ppc program counter
'''
cpu.env_ptr.eip = val
cpu.env_ptr.nip = val

def _get_reg_val(self, cpu, reg):
'''
Return an x86 register
Return a ppc register
'''
return cpu.env_ptr.regs[reg]
return cpu.env_ptr.gpr[reg]

def _set_reg_val(self, cpu, reg, val):
'''
Set an x86 register
Set an x86_64 register
'''
cpu.env_ptr.regs[reg] = val
cpu.env_ptr.gpr[reg] = val

def get_reg(self, cpu, reg):

reg = reg.upper()
env = cpu.env_ptr
if reg == "LR":
return env.lr
elif reg == "CTR":
return env.ctr
elif reg in self.registers_crf:
return env.crf[self.registers_crf.index(reg)]
else:
return super().get_reg(cpu, reg)


def set_reg(self, cpu, reg, val):
reg = reg.upper()
env = cpu.env_ptr

if reg == "LR":
env.lr = val
elif reg == "CTR":
env.ctr = val
elif reg in self.registers_crf:
env.crf[self.registers_crf.index(reg)] = val
else:
super().set_reg(cpu, reg, val)

def get_return_value(self, cpu):
'''
.. Deprecated:: use get_retval
'''
return self.get_retval(cpu)

def get_return_address(self,cpu):
'''
looks up where ret will go
'''
esp = self.get_reg(cpu,"ESP")
return self.panda.virtual_memory_read(cpu,esp,4,fmt='int')

class X86_64Arch(PandaArch):
'''
Expand Down Expand Up @@ -722,6 +727,7 @@ def __init__(self, panda):
self.reg_names_short = ['AX', 'CX', 'DX', 'BX', 'SP', 'BP', 'SI', 'DI']
self.reg_names_byte = ['AL', 'CL', 'DL', 'BL', 'AH', 'CH', 'DH', 'BH']
self.seg_names = ['ES', 'CS', 'SS', 'DS', 'FS', 'GS']
self.reg_names_mmr = ['LDT', 'TR', 'GDT', 'IDT']

def _get_segment_register(self, env, seg_name):
seg_idx = self.seg_names.index(seg_name)
Expand Down Expand Up @@ -765,6 +771,20 @@ def set_pc(self, cpu, val):
'''
cpu.env_ptr.eip = val

def _get_mmr_val(self, cpu, reg):
reg = reg.lower()
sc = getattr(cpu.env_ptr, reg)
return (sc.selector, sc.base, sc.limit, sc.flags)

def _set_mmr_val(self, cpu, reg, val):
reg = reg.lower()
selector, base, limit, flags = val
sc = getattr(cpu.env_ptr, reg)
sc.selector = selector
sc.base = base
sc.limit = limit
sc.flags = flags

def _get_reg_val(self, cpu, reg):
'''
Return an x86_64 register
Expand Down Expand Up @@ -802,8 +822,12 @@ def get_reg(self, cpu, reg):

reg = reg.upper()
env = cpu.env_ptr
if reg in self.reg_names_mmr:
return self._get_mmr_val(cpu, reg)
if reg in self.seg_names:
return self._get_segment_register(env, reg)
elif reg in ['EFLAGS', 'RFLAGS']:
return env.eflags
elif reg in ['RIP', 'PC', 'EIP']:
pc = self.get_pc(cpu) # changes reg to 'IP' and re-calls this
if reg == 'EIP':
Expand Down Expand Up @@ -856,13 +880,17 @@ def set_reg(self, cpu, reg, val):
reg = reg.upper()
env = cpu.env_ptr

if reg in ['ES', 'CS', 'SS', 'DS', 'FS', 'GS']:
if reg in self.reg_names_mmr:
return self._set_mmr_val(cpu, reg, val)
elif reg in self.seg_names:
self._set_segment_register(env, reg, val)
elif reg in ['EFLAGS', 'RFLAGS']:
env.eflags = val
elif reg in ['RIP', 'PC']:
return self.set_pc(cpu, val) # changes reg to 'IP' and re-calls this
elif reg.startswith('XMM'):
#env.xmm_regs[int(reg[3:])] = val
raise NotImplementedError("XMM registers unsupported")
env.xmm_regs[int(reg[3:])] = val
#raise NotImplementedError("XMM registers unsupported")
elif reg.startswith('MM'):
raise NotImplementedError("MM registers unsupported")
elif reg.startswith('YMM'):
Expand Down Expand Up @@ -890,3 +918,28 @@ def set_reg(self, cpu, reg, val):
self._set_general_purpose_register(env, reg, val, mask)
else:
super().set_reg(cpu, reg, val)


class X86Arch(X86_64Arch):
'''
Register names and accessors for x86
'''

def __init__(self, panda):
super().__init__(panda)
regnames = ['EAX', 'ECX', 'EDX', 'EBX', 'ESP', 'EBP', 'ESI', 'EDI']
# XXX Note order is A C D B, because that's how qemu does it . See target/i386/cpu.h

# Note we don't set self.call_conventions because stack-based arg get/set is
# not yet supported
self.reg_retval = {"default": "EAX",
"syscall": "EAX",
"linux_kernel": "EAX"}

self.call_conventions = {"cdecl": [f"stack_{x}" for x in range(20)], # 20: arbitrary but big
"syscall": ["EAX", "EBX", "ECX", "EDX", "ESI", "EDI", "EBP"],
"linux_kernel": ["EAX", "EDX", "ECX", "stack_3", "stack_4", "stack_5", "stack_6"]}
self.call_conventions['default'] = self.call_conventions['cdecl']

self.reg_sp = regnames.index('ESP')
self.registers = {regnames[idx]: idx for idx in range(len(regnames)) }
4 changes: 3 additions & 1 deletion panda/python/core/pandare/panda.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
from .asyncthread import AsyncThread
from .qcows_internal import Qcows
from .qemu_logging import QEMU_Log_Manager
from .arch import ArmArch, Aarch64Arch, MipsArch, Mips64Arch, X86Arch, X86_64Arch
from .arch import ArmArch, Aarch64Arch, MipsArch, Mips64Arch, X86Arch, X86_64Arch, PowerPCArch
from .cosi import Cosi
from dataclasses import dataclass

Expand Down Expand Up @@ -150,6 +150,8 @@ def __init__(self, arch="i386", mem="128M",
self.arch = MipsArch(self)
elif self.arch_name in ["mips64", "mips64el"]:
self.arch = Mips64Arch(self)
elif self.arch_name in ["ppc"]:
self.arch = PowerPCArch(self)
else:
raise ValueError(f"Unsupported architecture {self.arch_name}")
self.bits, self.endianness, self.register_size = self.arch._determine_bits()
Expand Down
Loading