From a3fa6ea4abbce05d674847ef19848002ecfd4b6f Mon Sep 17 00:00:00 2001 From: Christian Dietrich Date: Mon, 16 Aug 2021 10:59:38 +0200 Subject: [PATCH] towards multi-arch --- Makefile | 72 +++-- arch/bochs.mk | 30 +++ .../bochs/BIOS-bochs-latest | Bin arch/bochs/lib.c | 4 + startup.s => arch/bochs/startup.s | 0 vgabios.bin => arch/bochs/vgabios.bin | Bin arch/riscv-common.mk | 33 +++ arch/riscv/bootcode/boot.h | 30 +++ arch/riscv/bootcode/cheri32.c | 30 +++ arch/riscv/bootcode/cheri64.c | 1 + arch/riscv/bootcode/riscv32.c | 12 + arch/riscv/bootcode/riscv64.c | 1 + arch/riscv/lib.c | 3 + arch/riscv/linker.ld | 254 ++++++++++++++++++ arch/riscv32 | 1 + arch/riscv32.mk | 5 + arch/riscv64 | 1 + lib.c | 24 ++ main.c | 25 +- 19 files changed, 488 insertions(+), 38 deletions(-) create mode 100644 arch/bochs.mk rename BIOS-bochs-latest => arch/bochs/BIOS-bochs-latest (100%) create mode 100644 arch/bochs/lib.c rename startup.s => arch/bochs/startup.s (100%) rename vgabios.bin => arch/bochs/vgabios.bin (100%) create mode 100644 arch/riscv-common.mk create mode 100644 arch/riscv/bootcode/boot.h create mode 100644 arch/riscv/bootcode/cheri32.c create mode 120000 arch/riscv/bootcode/cheri64.c create mode 100644 arch/riscv/bootcode/riscv32.c create mode 120000 arch/riscv/bootcode/riscv64.c create mode 100644 arch/riscv/lib.c create mode 100644 arch/riscv/linker.ld create mode 120000 arch/riscv32 create mode 100644 arch/riscv32.mk create mode 120000 arch/riscv64 create mode 100644 lib.c diff --git a/Makefile b/Makefile index 9478287..9fce2b6 100644 --- a/Makefile +++ b/Makefile @@ -1,42 +1,70 @@ -FAIL_DIR ?= ~/fail -FAIL_BIN ?= ${FAIL_DIR}/build/bin -BOCHS_RUNNER ?= python ${FAIL_DIR}/tools/bochs-experiment-runner/bochs-experiment-runner.py +FAIL_DOWNLOAD_BASE="https://collaborating.tuhh.de/e-exk4/projects/fail/-/jobs/artifacts/feature/sail/download" + +ARCH ?= bochs + +all: help + +BUILD_DIR := build-${ARCH} +FAIL_BIN ?= ${BUILD_DIR}/bin +BOCHS_RUNNER ?= ${FAIL_BIN}/bochs-experiment-runner FAIL_SERVER ?= ${FAIL_BIN}/generic-experiment-server FAIL_TRACE ?= ${FAIL_BIN}/fail-generic-tracing FAIL_INJECT ?= ${FAIL_BIN}/fail-generic-experiment FAIL_IMPORT ?= ${FAIL_BIN}/import-trace --enable-sanitychecks FAIL_PRUNE ?= ${FAIL_BIN}/prune-trace +EXPERIMENTS := $(patsubst %.c,%,$(shell echo *.c)) -all: main/system.iso +CFLAGS := -I. -include arch/${ARCH}/lib.c -O2 -std=c11 + +include arch/${ARCH}.mk + +$(foreach element,$(EXPERIMENTS),$(eval $(call arch-make-targets,$(element)))) + +help: + @echo "Small Playground for FAIL* Injections" + @echo "-------------------------------------" + @echo "Architecture Unspecific Targets:" + @echo " \e[3mdocker\e[0m Start a Docker container with all dependencies" + @echo " \e[3mdownload\e[0m Download Precompiled FAIL* client" + @echo "" + @echo "Current Configuartion" + @echo " ARCH=${ARCH}" + +docker: + @echo Starting Docker with ARCH=$(ARCH) + docker run \ + -v ${PWD}:/home/fail/fail \ + -e ARCH=${ARCH} \ + -w /home/fail/fail \ + -it danceos/fail-ci-build + +################################################################ +# Download +download: ${BUILD_DIR}/bin/fail-client + +${BUILD_DIR}/bin/fail-client: + mkdir -p ${BUILD_DIR}/bin + wget ${FAIL_DOWNLOAD_URL} -O ${BUILD_DIR}/bin/fail.zip + cd ${BUILD_DIR}/bin/ && unzip fail.zip && mv build/bin/* . && rm -rf build -%/system.elf: %/system.o startup.o - ${CC} -Wl,-T linker.ld $^ -m32 -static -nostdlib -Wl,--build-id=none -o $@ +clean: + @rm -rf build -%/system.o: %.c - mkdir -p $(shell dirname $@) - ${CC} $< -o $@ -O2 -std=c11 -m32 -c -ffunction-sections +clean-%: + @rm -rf ${BUILD_DIR}/$(patsubst build-%,%,$@) -startup.o: startup.s - ${CC} startup.s -m32 -c -o startup.o -ffunction-sections - -%/system.iso: %/system.elf - rm -rf $(shell dirname $<)/grub - mkdir -p $(shell dirname $<)/grub/boot/grub - cp grub.cfg $(shell dirname $<)/grub/boot/grub - cp $< $(shell dirname $<)/grub/boot/system.elf - grub-mkrescue -o $@ $(shell dirname $<)/grub +build-%: @echo "****************************************************************\n\ * The next step is to trace a golden run. The golden run executes the\n\ -* system-under-test (SUT) within the Bochs emulator. A trace file is \n\ -* produced and saved as main/trace.pb\n\ +* system-under-test (SUT) within the emulator. A trace file is \n\ +* produced and saved as: ${BUILD_DIR}/main/trace.pb\n\ *\n\ -* $ make trace-$(shell dirname $<)\n\ +* $ make trace-$(patsubst build-%,%,$@)\n\ ****************************************************************" - trace-%: %/system.elf %/system.iso ${BOCHS_RUNNER} -e $< -i $(shell dirname $<)/system.iso -1 \ -V vgabios.bin -b BIOS-bochs-latest \ diff --git a/arch/bochs.mk b/arch/bochs.mk new file mode 100644 index 0000000..66a5b25 --- /dev/null +++ b/arch/bochs.mk @@ -0,0 +1,30 @@ +FAIL_DOWNLOAD_URL = ${FAIL_DOWNLOAD_BASE}?job=build-bochs-generic-tools + +CFLAGS += -m32 +LDFLAGS += -Wl,-T linker.ld $^ -m32 -static -nostdlib -Wl,--build-id=none + +################################################################ +# Build Targets +${BUILD_DIR}/%/system.o: %.c + mkdir -p $(shell dirname $@) + ${CC} $< -o $@ ${CFLAGS} -c -ffunction-sections + +${BUILD_DIR}/startup.o: arch/bochs/startup.s + ${CC} $< ${CFLAGS} -c -o $@ -ffunction-sections + +${BUILD_DIR}/%/system.elf: ${BUILD_DIR}/%/system.o ${BUILD_DIR}/startup.o + ${CC} ${LDFLAGS} -o $@ + +${BUILD_DIR}/%/system.iso: ${BUILD_DIR}/%/system.elf + rm -rf $(shell dirname $<)/grub + mkdir -p $(shell dirname $<)/grub/boot/grub + cp grub.cfg $(shell dirname $<)/grub/boot/grub + cp $< $(shell dirname $<)/grub/boot/system.elf + grub-mkrescue -o $@ $(shell dirname $<)/grub + +define arch-make-targets +build-$1: ${BUILD_DIR}/$1/system.iso +endef + + + diff --git a/BIOS-bochs-latest b/arch/bochs/BIOS-bochs-latest similarity index 100% rename from BIOS-bochs-latest rename to arch/bochs/BIOS-bochs-latest diff --git a/arch/bochs/lib.c b/arch/bochs/lib.c new file mode 100644 index 0000000..2eab5ee --- /dev/null +++ b/arch/bochs/lib.c @@ -0,0 +1,4 @@ +#pragma once + +#define ARCH_ASM_CLOBBER_ALL "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp" + diff --git a/startup.s b/arch/bochs/startup.s similarity index 100% rename from startup.s rename to arch/bochs/startup.s diff --git a/vgabios.bin b/arch/bochs/vgabios.bin similarity index 100% rename from vgabios.bin rename to arch/bochs/vgabios.bin diff --git a/arch/riscv-common.mk b/arch/riscv-common.mk new file mode 100644 index 0000000..5abb917 --- /dev/null +++ b/arch/riscv-common.mk @@ -0,0 +1,33 @@ +CC := clang-11 +CFLAGS += -nostdlib -fno-inline-functions -fno-unroll-loops -mcmodel=medium -gdwarf-5 +LDFLAGS += -nostdlib -nostartfiles -static -fuse-ld=lld -Wl,-nostdlib -Wl,--script=arch/riscv/linker.ld + + +${BUILD_DIR}/startup.o: arch/riscv/bootcode/${ARCH}.c + @mkdir -p $(dir $@) + ${CC} ${CFLAGS} -o $@ -c $^ + +${BUILD_DIR}/%/system.o: %.c + @mkdir -p $(dir $@) + ${CC} ${CFLAGS} -o $@ -c $^ + +${BUILD_DIR}/%/system.elf: ${BUILD_DIR}/startup.o ${BUILD_DIR}/%/system.o + ${CC} ${CFLAGS} ${LDFLAGS} -o $@ $^ + + +define arch-make-targets +build-$1: ${BUILD_DIR}/$1/system.elf + +trace-$1: ${BUILD_DIR}/$1/system.elf + ${FAIL_TRACE} \ + -Wf,--elf-file -Wf,$$< \ + -Wf,--start-symbol -Wf,start_trace \ + -Wf,--end-symbol -Wf,stop_trace \ + -Wf,--check-bounds \ + -Wf,--state-file=$$(dir $$<)/state \ + -Wf,--trace-file=$$(dir $$<)/trace.pb \ + $$< + +endef + + diff --git a/arch/riscv/bootcode/boot.h b/arch/riscv/bootcode/boot.h new file mode 100644 index 0000000..dfb7d2e --- /dev/null +++ b/arch/riscv/bootcode/boot.h @@ -0,0 +1,30 @@ +#pragma once + +#if defined(__riscv) && !defined(__CHERI__) +#define RISCV 1 +#define ARCH_ASM_CLOBBER_ALL NO_CAP_REGS + +#elif defined(__riscv) && defined(__CHERI__) +#define RISCVCHERI 1 +#define ARCH_ASM_CLOBBER_ALL NO_CAPS_REGS, CAP_REGS + +#else +#warning compiling for unknown architecture, using stdlib malloc. +#endif + +#define NO_CAP_REGS "ra","sp","gp","tp","t0","t1","t2","t3","t4","t5","t6","s0","s1","s2","s3","s4","s5","s6","s7","s8","s9","s10","s11","a0","a1","a2","a3","a4","a5","a6","a7" + +#define CAP_REGS "cra","csp","cgp","ctp","ct0","ct1","ct2","ct3","ct4","ct5","ct6","cs0","cs1","cs2","cs3","cs4","cs5","cs6","cs7","cs8","cs9","cs10","cs11","ca0","ca1","ca2","ca3","ca4","ca5","ca6","ca7" + +#ifndef __ASSEMBLER__ + +#if __riscv_xlen == 32 +typedef unsigned int size_t; +#elif __riscv_xlen == 64 +typedef unsigned long size_t; +#elif DEBUG +#else +#warning Unknown __riscv_xlen value +typedef unsigned long size_t; +#endif +#endif diff --git a/arch/riscv/bootcode/cheri32.c b/arch/riscv/bootcode/cheri32.c new file mode 100644 index 0000000..c11354a --- /dev/null +++ b/arch/riscv/bootcode/cheri32.c @@ -0,0 +1,30 @@ +#include +#include "boot.h" + +asm ( +".text" "\n" +".option push" "\n" +".option nocapmode" "\n" +".global _start" "\n" +"_start:" "\n" +" lla sp, __sp" "\n" +" lla t0, __stack_size" "\n" +" cfromptr csp, ddc, sp" "\n" +" csetbounds csp, csp, t0" "\n" +" cincoffset csp, csp, t0" "\n" +" lla t0, _start_purecap" "\n" +" cfromptr ct0, ddc, t0" "\n" +" li t1, 1" "\n" +" csetflags ct0, ct0, t1" "\n" +" cjr ct0" "\n" +".option pop" "\n" +); + +extern void os_main(); + +void _start_purecap(void) { + cheri_init_globals_3(__builtin_cheri_global_data_get(), + __builtin_cheri_program_counter_get(), + __builtin_cheri_global_data_get()); + os_main(); +} diff --git a/arch/riscv/bootcode/cheri64.c b/arch/riscv/bootcode/cheri64.c new file mode 120000 index 0000000..dff6dd9 --- /dev/null +++ b/arch/riscv/bootcode/cheri64.c @@ -0,0 +1 @@ +cheri32.c \ No newline at end of file diff --git a/arch/riscv/bootcode/riscv32.c b/arch/riscv/bootcode/riscv32.c new file mode 100644 index 0000000..c72f891 --- /dev/null +++ b/arch/riscv/bootcode/riscv32.c @@ -0,0 +1,12 @@ +#include "boot.h" + +asm ( +".text" "\n" +".global _start" "\n" +"_start:" "\n" +" la sp, __sp" "\n" +" la t0, __stack_size" "\n" +" add sp, sp, t0" "\n" +" la t0, os_main" "\n" +" jr t0" "\n" + ); diff --git a/arch/riscv/bootcode/riscv64.c b/arch/riscv/bootcode/riscv64.c new file mode 120000 index 0000000..11f5a56 --- /dev/null +++ b/arch/riscv/bootcode/riscv64.c @@ -0,0 +1 @@ +riscv32.c \ No newline at end of file diff --git a/arch/riscv/lib.c b/arch/riscv/lib.c new file mode 100644 index 0000000..05af63d --- /dev/null +++ b/arch/riscv/lib.c @@ -0,0 +1,3 @@ +#include "arch/riscv/bootcode/boot.h" + + diff --git a/arch/riscv/linker.ld b/arch/riscv/linker.ld new file mode 100644 index 0000000..6fed280 --- /dev/null +++ b/arch/riscv/linker.ld @@ -0,0 +1,254 @@ + +/*======================================================================*/ +/* Default maven linker script */ +/*======================================================================*/ +/* This is the default linker script for maven. It is based off of the + mips idt32.ld linker script. I have added many more comments and + tried to clean things up a bit. For more information about standard + MIPS sections see Section 9.5 of "See MIPS Run Linux" by Dominic + Sweetman. For more generic information about the init, fini, ctors, + and dtors sections see the paper titled "ELF From the Programmers + Perspective" by Hongiu Lu. */ + +/*----------------------------------------------------------------------*/ +/* Setup */ +/*----------------------------------------------------------------------*/ + +/* The OUTPUT_ARCH command specifies the machine architecture where the + argument is one of the names used in the BFD library. More + specifically one of the entires in bfd/cpu-mips.c */ + +OUTPUT_ARCH( "riscv" ) + +/* The ENTRY command specifies the entry point (ie. first instruction to + execute). The symbol _start is defined in crt0.S */ + +ENTRY( _start ) + + +/*----------------------------------------------------------------------*/ +/* Sections */ +/*----------------------------------------------------------------------*/ +/* This is where we specify how the input sections map to output + sections. The .= commands set the location counter, and the + sections are inserted in increasing address order according to the + location counter. The following statement will take all of the .bar + input sections and reloate them into the .foo output section which + starts at address 0x1000. + + . = 0.x1000; + .foo : { *(.bar) } + + If we wrap an input specification with a KEEP command then it + prevents it from being eliminted during "link-time garbage + collection". I'm not sure what this is, so I just followed what was + done in idt32.ld. + + We can also set a global external symbol to a specific address in the + output binary with this syntax: + + _etext = .; + PROVIDE( etext = . ); + + This will set the global symbol _ftext to the current location. If we + wrap this in a PROVIDE commad, the symbol will only be set if it is + not defined. We do this with symbols which don't begin with an + underscore since technically in ansi C someone might have a function + with the same name (eg. etext). + + If we need to label the beginning of a section we need to make sure + that the linker doesn't insert an orphan section inbetween where we + set the symbol and the actual begining of the section. We can do that + by assigning the location dot to itself. + + . = . + _ftext = .; + .text : + { } + + */ + +SECTIONS +{ + /* Defines for stack and heap size. These are used by the startup code. */ + __stack_size = 0x800; + __heap_size = 0x800; + + /* Define data/bss padding size, defaults to zero but can be override by passing -Wl,--defsym=__padding_size=0x123 */ + __padding_size = DEFINED(__padding_size) ? __padding_size: 0x0; + + /*--------------------------------------------------------------------*/ + /* Code and read-only segment */ + /*--------------------------------------------------------------------*/ + + /* Begining of code and text segment */ + . = 0x80000000; + _ftext = .; + + /* text: Program code section */ + .text : + { + *(.text) + *(.text.*) + *(.gnu.linkonce.t.*) + } + + /* init: Code to execute before main (called by crt0.S) */ + .init : + { + KEEP( *(.init) ) + } + + /* fini: Code to execute after main (called by crt0.S) */ + .fini : + { + KEEP( *(.fini) ) + } + + /* rodata: Read-only data */ + .rodata : + { + *(.rdata) + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + } + + /* End of code and read-only segment */ + PROVIDE( etext = . ); + _etext = .; + + /*--------------------------------------------------------------------*/ + /* Global constructor/destructor segement */ + /*--------------------------------------------------------------------*/ + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array )) + PROVIDE_HIDDEN (__init_array_end = .); + } + + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array )) + PROVIDE_HIDDEN (__fini_array_end = .); + } + + + /*--------------------------------------------------------------------*/ + /* Other misc gcc segments (this was in idt32.ld) */ + /*--------------------------------------------------------------------*/ + /* I am not quite sure about these sections but it seems they are for + C++ exception handling. I think .jcr is for "Java Class + Registration" but it seems to end up in C++ binaries as well. */ + + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : { KEEP( *(.eh_frame) ) } + .gcc_except_table : { *(.gcc_except_table) } + .jcr : { KEEP (*(.jcr)) } + + /*--------------------------------------------------------------------*/ + /* Initialized data segment */ + /*--------------------------------------------------------------------*/ + + .padding_before : { + . += __padding_size; + } + + /* Start of initialized data segment */ + . = ALIGN(16); + _fdata = .; + + /* data: Writable data */ + .data : + { + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + } + + /* End of initialized data segment */ + PROVIDE( edata = . ); + _edata = .; + + /* Have _gp point to middle of sdata/sbss to maximize displacement range */ + . = ALIGN(16); + _gp = . + 0x800; + + /* Writable small data segment */ + .sdata : + { + *(.sdata) + *(.sdata.*) + *(.srodata.*) + *(.gnu.linkonce.s.*) + } + + /*--------------------------------------------------------------------*/ + /* Uninitialized data segment */ + /*--------------------------------------------------------------------*/ + + /* Start of uninitialized data segment */ + . = ALIGN(16); + _fbss = .; + + /* Writable uninitialized small data segment */ + .sbss : + { + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + } + + /* bss: Uninitialized writeable data section */ + . = .; + _bss_start = .; + .bss : + { + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + } + + .padding_after : { + . += __padding_size; + } + + /*--------------------------------------------------------------------*/ + /* Stack and Heap storage */ + /*--------------------------------------------------------------------*/ + .heap : ALIGN(16) { + *(.heap) + *(.heap.*) + } + + .stack : ALIGN(16) { + PROVIDE(__sp = .); + . += __stack_size; + } + + /*--------------------------------------------------------------------*/ + /* HTIF, isolated on a seperate page. */ + /*--------------------------------------------------------------------*/ + .htif (NOLOAD) : ALIGN(0x1000) { + tohost = .; + PROVIDE(tohost = tohost); + . += 8; + fromhost = .; + PROVIDE(fromhost = fromhost); + . += 8; + } + . = ALIGN(0x1000); +} diff --git a/arch/riscv32 b/arch/riscv32 new file mode 120000 index 0000000..4847a64 --- /dev/null +++ b/arch/riscv32 @@ -0,0 +1 @@ +riscv \ No newline at end of file diff --git a/arch/riscv32.mk b/arch/riscv32.mk new file mode 100644 index 0000000..f928573 --- /dev/null +++ b/arch/riscv32.mk @@ -0,0 +1,5 @@ +FAIL_DOWNLOAD_URL = ${FAIL_DOWNLOAD_BASE}?job=build-riscv-generic-tools%3A+%5Briscv64%5D + +include arch/riscv-common.mk + +CFLAGS += -march=rv32im -target riscv32-unknown-freebsd diff --git a/arch/riscv64 b/arch/riscv64 new file mode 120000 index 0000000..4847a64 --- /dev/null +++ b/arch/riscv64 @@ -0,0 +1 @@ +riscv \ No newline at end of file diff --git a/lib.c b/lib.c new file mode 100644 index 0000000..9c248f8 --- /dev/null +++ b/lib.c @@ -0,0 +1,24 @@ +#pragma once + +#define INLINE __attribute__((always_inline)) inline +#define NOINLINE __attribute__((noinline)) + +#define __QUOTE(x) #x +#define QUOTE(x) __QUOTE(x) + +#define MARKER(str) __asm__ volatile(QUOTE(str) ":" \ + : /* no inputs */ \ + : /* no outputs */ \ + : "memory", ARCH_ASM_CLOBBER_ALL \ + ) + +#ifndef DEBUG +#define MAIN() void os_main(void) +#define PRINT_DEBUG(...) +#else +#include +#define MARKER(str) printf(QUOTE(str) "\n") +#define DEBUG 1 +#define PRINT_DEBUG(...) printf(__VA_ARGS__) +#define MAIN() void main(int argc, char** argv) +#endif diff --git a/main.c b/main.c index ac7ddc2..c0a387d 100644 --- a/main.c +++ b/main.c @@ -1,28 +1,21 @@ -volatile int __dummy; -void __attribute__ ((noinline)) fail_marker(); -void __attribute__ ((noinline)) fail_marker() -{ - __dummy = 100; -} - -void __attribute__ ((noinline)) stop_trace(); -void __attribute__ ((noinline)) stop_trace() -{ - __dummy = 100; -} - +#include "lib.c" int array[] = {1, 1, 2, 3, 5, 8, 13, 21}; int sum; -void os_main() { + +MAIN() { + MARKER(start_trace); sum = 20; for (int i = 0; i < sizeof(array)/sizeof(*array); i++) { sum += (array[i] * 23) + 1; } + MARKER(stop_trace); + if (sum != 1270) - fail_marker(); - stop_trace(); + MARKER(fail_maker); + else + MARKER(ok_marker); }