]> xenbits.xensource.com Git - people/andrewcoop/xen-test-framework.git/commitdiff
XSA-194 PoC
authorAndrew Cooper <andrew.cooper3@citrix.com>
Tue, 15 Nov 2016 17:40:45 +0000 (17:40 +0000)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Wed, 30 Nov 2016 19:18:11 +0000 (19:18 +0000)
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
arch/x86/link.lds.S
docs/all-tests.dox
include/arch/x86/xtf.h
include/xen/elfnote.h
include/xtf/asm_macros.h
include/xtf/elf.h [new file with mode: 0644]
include/xtf/lib.h
tests/xsa-194/Makefile [new file with mode: 0644]
tests/xsa-194/main.c [new file with mode: 0644]

index 8828e5fbfa5102d83844c0f5ac199cea58de341d..49bc38149a22b9c0e0254408cd668b11747c11fd 100644 (file)
@@ -38,6 +38,10 @@ SECTIONS
                 *(.text)
         } :load = 0x9090
 
+        .data : {
+                *(.data)
+        }
+
         .rodata : {
                 *(.rodata)
                 *(.rodata.*)
@@ -52,6 +56,12 @@ SECTIONS
                 *(.note)
                 *(.note.*)
         }
+
+        .bss : {
+                *(.bss)
+        }
+
+        _end = .;
 }
 
 /*
index b6e586ba68e9c852cab3a306d38ec3ab96385a04..71e27c02686aa23ce0814570b4c683c844ff5178 100644 (file)
@@ -71,6 +71,8 @@ XSA-190 - See @ref test-fpu-exception-emulation.
 @subpage test-xsa-193 - x86: Segment base write emulation lacking canonical
 address checks.
 
+@subpage test-xsa-194 - Guest 32-bit ELF symbol table load leaking host data.
+
 
 @section index-utility Utilities
 
index ab0bf69db9b5c119bd956a416fd2dd5d7d97ca14..1196d5251bd3ce480593237c1094204603e8598a 100644 (file)
@@ -4,6 +4,8 @@
 #include <arch/x86/cpuid.h>
 #include <arch/x86/lib.h>
 
+extern char _end[];
+
 #endif /* XTF_X86_XTF_H */
 
 /*
index 98516b87fc7d047ad03f102ec3156bbcb96118a6..e4bfc2052bcb7a3d1d9c7d76e47adab653f0c41e 100644 (file)
@@ -12,6 +12,7 @@
 #define XEN_ELFNOTE_LOADER         8
 #define XEN_ELFNOTE_PAE_MODE       9
 #define XEN_ELFNOTE_FEATURES      10
+#define XEN_ELFNOTE_BSD_SYMTAB    11
 
 #endif /* XEN_PUBLIC_ELFNOTE_H */
 
index 1fe00ffcc25a6f50bc1be045a8eaa70b6cadc5dd..0be9a2dd19e3e8ab97147a08b531c463a47db0b9 100644 (file)
@@ -73,6 +73,20 @@ name:
 4:.align 4                                        ; \
     .popsection
 
+#else
+
+#define ELFNOTE(name, type, desc)                \
+    asm (".pushsection .note." #name ";"         \
+    ".align 4;"                                  \
+    ".long 2f - 1f;"       /* namesz */          \
+    ".long 4f - 3f;"       /* descsz */          \
+    ".long " STR(type) ";" /* type   */          \
+    "1: .asciz \"" #name "\";" /* name   */      \
+    "2:.align 4;"                                \
+    "3: " desc ";"         /* desc   */          \
+    "4:.align 4;"                                \
+    ".popsection;")
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* XTF_ASM_MACROS_H */
diff --git a/include/xtf/elf.h b/include/xtf/elf.h
new file mode 100644 (file)
index 0000000..d672b58
--- /dev/null
@@ -0,0 +1,90 @@
+#ifndef XTF_ELF_H
+#define XTF_ELF_H
+
+#include <xtf/types.h>
+
+typedef uint32_t        Elf32_Addr;
+typedef uint32_t        Elf32_Off;
+typedef uint16_t        Elf32_Half;
+typedef int32_t         Elf32_Sword;
+typedef uint32_t        Elf32_Word;
+
+typedef uint64_t        Elf64_Addr;
+typedef uint64_t        Elf64_Off;
+typedef uint16_t        Elf64_Half;
+typedef int32_t         Elf64_Sword;
+typedef uint32_t        Elf64_Word;
+typedef int64_t         Elf64_Sxword;
+typedef uint64_t        Elf64_Xword;
+
+#define EI_MAG0         0
+#define EI_MAG1         1
+#define EI_MAG2         2
+#define EI_MAG3         3
+#define EI_CLASS        4
+#define EI_NIDENT       16
+
+#define ELFMAG0         0x7f
+#define ELFMAG1         'E'
+#define ELFMAG2         'L'
+#define ELFMAG3         'F'
+
+#define ELFCLASSNONE    0
+#define ELFCLASS32      1
+#define ELFCLASS64      2
+#define ELFCLASSNUM     3
+
+typedef struct {
+    unsigned char   e_ident[EI_NIDENT];
+    Elf32_Half      e_type;
+    Elf32_Half      e_machine;
+    Elf32_Word      e_version;
+    Elf32_Addr      e_entry;
+    Elf32_Off       e_phoff;
+    Elf32_Off       e_shoff;
+    Elf32_Word      e_flags;
+    Elf32_Half      e_ehsize;
+    Elf32_Half      e_phentsize;
+    Elf32_Half      e_phnum;
+    Elf32_Half      e_shentsize;
+    Elf32_Half      e_shnum;
+    Elf32_Half      e_shstrndx;
+} Elf32_Ehdr;
+
+typedef struct {
+    Elf32_Word      sh_name;
+    Elf32_Word      sh_type;
+    Elf32_Word      sh_flags;
+    Elf32_Addr      sh_addr;
+    Elf32_Off       sh_offset;
+    Elf32_Word      sh_size;
+    Elf32_Word      sh_link;
+    Elf32_Word      sh_info;
+    Elf32_Word      sh_addralign;
+    Elf32_Word      sh_entsize;
+} Elf32_Shdr;
+
+typedef struct {
+    Elf64_Word      sh_name;
+    Elf64_Word      sh_type;
+    Elf64_Xword     sh_flags;
+    Elf64_Addr      sh_addr;
+    Elf64_Off       sh_offset;
+    Elf64_Xword     sh_size;
+    Elf64_Word      sh_link;
+    Elf64_Word      sh_info;
+    Elf64_Xword     sh_addralign;
+    Elf64_Xword     sh_entsize;
+} Elf64_Shdr;
+
+#endif /* XTF_ELF_H */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
index 65abdab86996c6a2d647456faac7dc0c4d5ed150..9db282dd7fe111b2004eb21821399cf741d96460 100644 (file)
@@ -47,6 +47,8 @@ void __noreturn panic(const char *fmt, ...) __printf(1, 2);
         _a > _b ? _a : _b;                              \
     })
 
+#define ROUNDUP(x, a) (((x) + (a) - 1) & ~((a) - 1))
+
 void heapsort(void *base, size_t nmemb, size_t size,
               int (*compar)(const void *, const void *),
               void (*swap)(void *, void *));
diff --git a/tests/xsa-194/Makefile b/tests/xsa-194/Makefile
new file mode 100644 (file)
index 0000000..ff6f208
--- /dev/null
@@ -0,0 +1,9 @@
+include $(ROOT)/build/common.mk
+
+NAME      := xsa-194
+CATEGORY  := xsa
+TEST-ENVS := pv32pae
+
+obj-perenv += main.o
+
+include $(ROOT)/build/gen.mk
diff --git a/tests/xsa-194/main.c b/tests/xsa-194/main.c
new file mode 100644 (file)
index 0000000..0b98a56
--- /dev/null
@@ -0,0 +1,97 @@
+/**
+ * @file tests/xsa-194/main.c
+ * @ref test-xsa-194
+ *
+ * @page test-xsa-194 XSA-194
+ *
+ * Advisory: [XSA-194](http://xenbits.xen.org/xsa/advisory-xsa-194.html)
+ *
+ * When a guest requests BSD_SYMTAB, Some versions of libelf use a packed
+ * struct containing an Elf header, and three Section headers.  These headers
+ * however are a union of their 32 and 64bit variants, resulting in padding
+ * between the headers when building the BSD symtab for a 32bit PV guest.
+ *
+ * As a consequence, libelf stack gets leaked in the padding.
+ *
+ * Spotting leakage in the Elf header is easy.
+ *
+ * Spotting leakage in the Section headers are not.  All buggy versions of
+ * libelf (to the time of writing) erroneously set Elf32_Ehdr.e_shentsize to
+ * sizeof(Elf32_Shdr), despite actually providing sizeof(Elf64_Shdr) per
+ * entry.
+ *
+ * We therefore cannot distinguish an older libelf which provides real 32bit
+ * section headers, from a vulnerable version of libelf claiming 32bit section
+ * header but actually providing 64bit headers.
+ *
+ * @see tests/xsa-194/main.c
+ */
+#include <xtf.h>
+
+#include <xtf/elf.h>
+#include <xen/elfnote.h>
+
+const char test_title[] = "XSA-194 PoC";
+
+ELFNOTE(Xen, XEN_ELFNOTE_BSD_SYMTAB, ".asciz \"yes\"");
+
+int memcmpzero(const void *buf, size_t sz)
+{
+    const char *ptr = buf;
+    size_t i;
+
+    for ( i = 0; i < sz; ++i )
+        if ( ptr[i] != 0 )
+            return ptr[i];
+
+    return 0;
+}
+
+void test_main(void)
+{
+    bool leak_detected = false;
+    uint32_t *size = _p(ROUNDUP((unsigned long)&_end[0],
+                                sizeof(unsigned long)));
+    Elf32_Ehdr *ehdr = _p(size) + 4;
+
+    if ( !(ehdr->e_ident[EI_MAG0] == ELFMAG0 &&
+           ehdr->e_ident[EI_MAG1] == ELFMAG1 &&
+           ehdr->e_ident[EI_MAG2] == ELFMAG2 &&
+           ehdr->e_ident[EI_MAG3] == ELFMAG3) )
+        return xtf_error("Error: Elf header not found\n");
+
+    if ( ehdr->e_ident[EI_CLASS] != ELFCLASS32 )
+        return xtf_error("Error: Unexpected ELF type %u\n",
+                         ehdr->e_ident[EI_CLASS]);
+
+    if ( ehdr->e_shnum != 3 )
+        return xtf_error("Error: Expected 3 section headers\n");
+
+    /*
+     * libelf has some padding between an Elf32_Ehdr and the start of the
+     * section header list it writes.  (Specifically, the padding until the
+     * end of a Elf64_Ehdr).
+     */
+    if ( ehdr->e_ehsize < ehdr->e_shoff )
+    {
+        if ( memcmpzero(_p(ehdr) + ehdr->e_ehsize,
+                        ehdr->e_shoff - ehdr->e_ehsize) )
+        {
+            leak_detected = true;
+            xtf_failure("Fail: Data leaked after EHDR\n");
+        }
+    }
+
+    if ( !leak_detected )
+        xtf_success("Success: No leak detected\n");
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */