diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2018-03-22 14:01:29 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2018-03-22 14:01:29 +0000 |
commit | 211d6260208d079429fd0d447b86ff480d0524ca (patch) | |
tree | 155317fe1b35b86355bdac59c006da44fe721df8 | |
parent | 99728ba3ec9b8795ff7191ea75a2a8c0329c29a5 (diff) | |
parent | e2679395d598bd40770c22a793c0152576ac211f (diff) |
Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging
Multiboot patches
# gpg: Signature made Wed 21 Mar 2018 14:38:36 GMT
# gpg: using RSA key 7F09B272C88F2FD6
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>"
# Primary key fingerprint: DC3D EB15 9A9A F95D 3D74 56FE 7F09 B272 C88F 2FD6
* remotes/kevin/tags/for-upstream:
tests/multiboot: Add .gitignore
tests/multiboot: Add tests for the a.out kludge
tests/multiboot: Test exit code for every qemu run
multiboot: Check validity of mh_header_addr
multiboot: Reject kernels exceeding the address space
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | hw/i386/multiboot.c | 8 | ||||
-rw-r--r-- | tests/multiboot/.gitignore | 3 | ||||
-rw-r--r-- | tests/multiboot/Makefile | 22 | ||||
-rw-r--r-- | tests/multiboot/aout_kludge.S | 138 | ||||
-rw-r--r-- | tests/multiboot/aout_kludge.out | 42 | ||||
-rwxr-xr-x | tests/multiboot/run_test.sh | 34 |
6 files changed, 227 insertions, 20 deletions
diff --git a/hw/i386/multiboot.c b/hw/i386/multiboot.c index b9064264d8..5bc0a2cddb 100644 --- a/hw/i386/multiboot.c +++ b/hw/i386/multiboot.c @@ -229,6 +229,10 @@ int load_multiboot(FWCfgState *fw_cfg, error_report("invalid load_addr address"); exit(1); } + if (mh_header_addr - mh_load_addr > i) { + error_report("invalid header_addr address"); + exit(1); + } uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr); uint32_t mb_load_size = 0; @@ -247,6 +251,10 @@ int load_multiboot(FWCfgState *fw_cfg, } mb_load_size = kernel_file_size - mb_kernel_text_offset; } + if (mb_load_size > UINT32_MAX - mh_load_addr) { + error_report("kernel does not fit in address space"); + exit(1); + } if (mh_bss_end_addr) { if (mh_bss_end_addr < (mh_load_addr + mb_load_size)) { error_report("invalid bss_end_addr address"); diff --git a/tests/multiboot/.gitignore b/tests/multiboot/.gitignore new file mode 100644 index 0000000000..93ef99800b --- /dev/null +++ b/tests/multiboot/.gitignore @@ -0,0 +1,3 @@ +*.bin +*.elf +test.out diff --git a/tests/multiboot/Makefile b/tests/multiboot/Makefile index 36f01dc647..ed4225e7d1 100644 --- a/tests/multiboot/Makefile +++ b/tests/multiboot/Makefile @@ -3,16 +3,26 @@ CCFLAGS=-m32 -Wall -Wextra -Werror -fno-stack-protector -nostdinc -fno-builtin ASFLAGS=-m32 LD=ld -LDFLAGS=-melf_i386 -T link.ld +LDFLAGS_ELF=-melf_i386 -T link.ld +LDFLAGS_BIN=-melf_i386 -T link.ld --oformat=binary LIBS=$(shell $(CC) $(CCFLAGS) -print-libgcc-file-name) -all: mmap.elf modules.elf +AOUT_KLUDGE_BIN=$(foreach x,$(shell seq 1 9),aout_kludge_$x.bin) -mmap.elf: start.o mmap.o libc.o - $(LD) $(LDFLAGS) -o $@ $^ $(LIBS) +all: mmap.elf modules.elf $(AOUT_KLUDGE_BIN) -modules.elf: start.o modules.o libc.o - $(LD) $(LDFLAGS) -o $@ $^ $(LIBS) +mmap.elf: start.o mmap.o libc.o link.ld + $(LD) $(LDFLAGS_ELF) -o $@ $^ $(LIBS) + +modules.elf: start.o modules.o libc.o link.ld + $(LD) $(LDFLAGS_ELF) -o $@ $^ $(LIBS) + +aout_kludge_%.bin: aout_kludge_%.o link.ld + $(LD) $(LDFLAGS_BIN) -o $@ $^ $(LIBS) + +.PRECIOUS: aout_kludge_%.o +aout_kludge_%.o: aout_kludge.S + $(CC) $(ASFLAGS) -DSCENARIO=$* -c -o $@ $^ %.o: %.c $(CC) $(CCFLAGS) -c -o $@ $^ diff --git a/tests/multiboot/aout_kludge.S b/tests/multiboot/aout_kludge.S new file mode 100644 index 0000000000..52e8ebd766 --- /dev/null +++ b/tests/multiboot/aout_kludge.S @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2018 Kevin Wolf <kwolf@redhat.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +.section multiboot + +#define MB_MAGIC 0x1badb002 +#define MB_FLAGS 0x10000 +#define MB_CHECKSUM -(MB_MAGIC + MB_FLAGS) + +.align 4 +.int MB_MAGIC +.int MB_FLAGS +.int MB_CHECKSUM + +#define LAST_BYTE_VALUE 0xa5 + +/* + * Order of fields in the a.out kludge header fields: + * + * header_addr + * load_addr + * load_end_addr + * bss_end_addr + * entry_addr + */ +#if SCENARIO == 1 +/* Well-behaved kernel file with explicit bss_end */ +.int 0x100000 +.int 0x100000 +.int data_end +.int data_end +.int _start +#elif SCENARIO == 2 +/* Well-behaved kernel file with default bss_end */ +.int 0x100000 +.int 0x100000 +.int data_end +.int 0 +.int _start +#elif SCENARIO == 3 +/* Well-behaved kernel file with default load_end */ +.int 0x100000 +.int 0x100000 +.int 0 +.int 0 +.int _start +#elif SCENARIO == 4 +/* Well-behaved kernel file with load_end < data_end and bss > data_end */ +#undef LAST_BYTE_VALUE +#define LAST_BYTE_VALUE 0 +.int 0x100000 +.int 0x100000 +.int code_end +.int 0x140000 +.int _start +#elif SCENARIO == 5 +/* header < load */ +.int 0x10000 +.int 0x100000 +.int data_end +.int data_end +.int _start +#elif SCENARIO == 6 +/* load_end < load */ +.int 0x100000 +.int 0x100000 +.int 0x10000 +.int data_end +.int _start +#elif SCENARIO == 7 +/* header much larger than in reality with default load_end */ +.int 0x80000000 +.int 0x100000 +.int 0 +.int data_end +.int _start +#elif SCENARIO == 8 +/* bss_end < load_end - load (regression test for CVE-2018-7550) */ +.int 0x100000 +.int 0x100000 +.int data_end +.int code_end +.int _start +#elif SCENARIO == 9 +/* Default load_end_addr, load_addr + kernel_file_size > UINT32_MAX */ +.int 0xfffff000 +.int 0xfffff000 +.int 0 +.int 0xfffff001 +.int _start +#else +#error Invalid SCENARIO +#endif + +.section .text +.global _start +_start: + xor %eax, %eax + + cmpb $LAST_BYTE_VALUE, last_byte + je passed + or $0x1, %eax +passed: + + /* Test device exit */ + outl %eax, $0xf4 + + cli + hlt + jmp . +code_end: + +#if SCENARIO != 8 +.space 8192 +#endif + +last_byte: +.byte 0xa5 +data_end: diff --git a/tests/multiboot/aout_kludge.out b/tests/multiboot/aout_kludge.out new file mode 100644 index 0000000000..031459275b --- /dev/null +++ b/tests/multiboot/aout_kludge.out @@ -0,0 +1,42 @@ + + + +=== Running test case: aout_kludge_1.bin === + + + +=== Running test case: aout_kludge_2.bin === + + + +=== Running test case: aout_kludge_3.bin === + + + +=== Running test case: aout_kludge_4.bin === + + + +=== Running test case: aout_kludge_5.bin === + +qemu-system-x86_64: invalid load_addr address + + +=== Running test case: aout_kludge_6.bin === + +qemu-system-x86_64: invalid load_end_addr address + + +=== Running test case: aout_kludge_7.bin === + +qemu-system-x86_64: invalid header_addr address + + +=== Running test case: aout_kludge_8.bin === + +qemu-system-x86_64: invalid bss_end_addr address + + +=== Running test case: aout_kludge_9.bin === + +qemu-system-x86_64: kernel does not fit in address space diff --git a/tests/multiboot/run_test.sh b/tests/multiboot/run_test.sh index 0278148b43..6c33003e71 100755 --- a/tests/multiboot/run_test.sh +++ b/tests/multiboot/run_test.sh @@ -34,10 +34,21 @@ run_qemu() { -device isa-debugcon,chardev=stdio \ -chardev file,path=test.out,id=stdio \ -device isa-debug-exit,iobase=0xf4,iosize=0x4 \ - "$@" + "$@" >> test.log 2>&1 ret=$? cat test.out >> test.log + + debugexit=$((ret & 0x1)) + ret=$((ret >> 1)) + + if [ $debugexit != 1 ]; then + printf %b "\e[31m ?? \e[0m $kernel $* (no debugexit used, exit code $ret)\n" + pass=0 + elif [ $ret != 0 ]; then + printf %b "\e[31mFAIL\e[0m $kernel $* (exit code $ret)\n" + pass=0 + fi } mmap() { @@ -56,24 +67,19 @@ modules() { run_qemu modules.elf -initrd "module.txt,module.txt argument,module.txt" } +aout_kludge() { + for i in $(seq 1 9); do + run_qemu aout_kludge_$i.bin + done +} + make all -for t in mmap modules; do +for t in mmap modules aout_kludge; do echo > test.log - $t - - debugexit=$((ret & 0x1)) - ret=$((ret >> 1)) pass=1 - - if [ $debugexit != 1 ]; then - printf %b "\e[31m ?? \e[0m $t (no debugexit used, exit code $ret)\n" - pass=0 - elif [ $ret != 0 ]; then - printf %b "\e[31mFAIL\e[0m $t (exit code $ret)\n" - pass=0 - fi + $t if ! diff $t.out test.log > /dev/null 2>&1; then printf %b "\e[31mFAIL\e[0m $t (output difference)\n" |