Philipp Deppenwiese (zaolin.daisuki@googlemail.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/16328
-gerrit
commit 90d9ac6eedc8adf1e9e408a307923c7c026d4dfc Author: Philipp Deppenwiese zaolin@das-labor.org Date: Fri Aug 26 02:10:51 2016 +0200
util/intelmetool: Add bootguard information dump support
With this implementation it's possible to detect the state of bootguard in intel based systems. Currently it's WIP and in a testphase. Handle it with care!
Change-Id: Ifeec8e20fa8efc35d7db4c6a84be1f118dccfc4a Signed-off-by: Philipp Deppenwiese zaolin@das-labor.org --- util/intelmetool/Makefile | 2 +- util/intelmetool/intelmetool.c | 198 ++++++++++++++++++++++++++++------------- util/intelmetool/intelmetool.h | 8 +- util/intelmetool/mmap.c | 4 - util/intelmetool/msr.c | 77 ++++++++++++++++ util/intelmetool/msr.h | 43 +++++++++ 6 files changed, 264 insertions(+), 68 deletions(-)
diff --git a/util/intelmetool/Makefile b/util/intelmetool/Makefile index 4461f86..4ea5c0f 100644 --- a/util/intelmetool/Makefile +++ b/util/intelmetool/Makefile @@ -20,7 +20,7 @@ PREFIX ?= /usr/local CFLAGS ?= -O0 -g -Wall -W -Wno-unused-parameter -Wno-unused-but-set-variable -Wno-sign-compare -Wno-unused-function LDFLAGS += -lpci -lz
-OBJS = intelmetool.o me.o me_status.o mmap.o +OBJS = intelmetool.o me.o me_status.o mmap.o msr.o
OS_ARCH = $(shell uname) ifeq ($(OS_ARCH), Darwin) diff --git a/util/intelmetool/intelmetool.c b/util/intelmetool/intelmetool.c index aec0715..41e39b7 100644 --- a/util/intelmetool/intelmetool.c +++ b/util/intelmetool/intelmetool.c @@ -16,6 +16,8 @@ #include <stdlib.h> #include <getopt.h> #include <unistd.h> +#include <string.h> +#include <cpuid.h>
#ifdef __NetBSD__ #include <machine/sysarch.h> @@ -23,17 +25,16 @@
#include "me.h" #include "mmap.h" +#include "msr.h" #include "intelmetool.h"
-#define FD2 0x3428 -#define ME_COMMAND_DELAY 10000 - extern int fd_mem; int debug = 0;
static uint32_t fd2 = 0; static const int size = 0x4000; static volatile uint8_t *rcba; +static char cpu_id[CPU_ID_SIZE] = { 0 };
static void dumpmem(uint8_t *phys, uint32_t size) { @@ -72,6 +73,16 @@ static void rehide_me() { } }
+static void get_cpu_id(char *id) { + cpu_t cpu; + unsigned int level = 0; + unsigned int eax = 0; + + __get_cpuid(level, &eax, &cpu.ebx, &cpu.ecx, &cpu.edx); + + memcpy(id, (char*)&cpu, CPU_ID_SIZE); +} + /* You need >4GB total ram, in kernel cmdline, use 'mem=1000m' * then this code will clone to absolute memory address 0xe0000000 * which can be read using a mmap tool at that offset. @@ -83,6 +94,10 @@ static void dump_me_memory() { uint8_t *dump;
dump = map_physical_exact(me_clone, me_clone, 0x2000000); + if(!dump) { + printf("ME physical memory can't be mapped!! Take a look at DMESG log.\n"); + return; + } zeroit(dump, 0x2000000); printf("Send magic command for memory clone\n");
@@ -103,10 +118,9 @@ static void dump_me_memory() { } }
-static int pci_platform_scan() { +static int pci_platform_scan(char* msg) { struct pci_access *pacc; struct pci_dev *dev; - char namebuf[1024], *name;
pacc = pci_alloc(); pacc->method = PCI_ACCESS_I386_TYPE1; @@ -116,38 +130,28 @@ static int pci_platform_scan() {
for (dev=pacc->devices; dev; dev=dev->next) { pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_SIZES | PCI_FILL_CLASS); - name = pci_lookup_name(pacc, namebuf, sizeof(namebuf), - PCI_LOOKUP_DEVICE, dev->vendor_id, dev->device_id); - if (dev->vendor_id == 0x8086) { + if (dev->vendor_id == INTEL_PLATFORM_VENDOR_ID) { if (PCI_DEV_HAS_ME_DISABLE(dev->device_id)) { - printf(CGRN "Good news, you have a `%s` so ME is present but can be disabled, continuing...\n\n" RESET, name); + snprintf(msg, ME_MESSAGE_LEN, CGRN "Good news, your ME is present but can be disabled, continuing...\n\n" RESET); break; } else if (PCI_DEV_HAS_ME_DIFFICULT(dev->device_id)) { - printf(CRED "Bad news, you have a `%s` so you have ME hardware on board and you can't control or disable it, continuing...\n\n" RESET, name); + snprintf(msg, ME_MESSAGE_LEN, CRED "Bad news, you have ME hardware on board but you can't control or disable it, continuing...\n\n" RESET); break; } else if (PCI_DEV_CAN_DISABLE_ME_IF_PRESENT(dev->device_id)) { - printf(CYEL "Not sure if ME hardware is present because you have a `%s`, but it is possible to disable it if you do, continuing...\n\n" RESET, name); + snprintf(msg, ME_MESSAGE_LEN, CYEL "Not sure if ME hardware is present, but it is possible to disable it if you do, continuing...\n\n" RESET); break; } else if (PCI_DEV_ME_NOT_SURE(dev->device_id)) { - printf(CYEL "Found `%s`. Not sure whether you have ME hardware, exiting\n\n" RESET, name); - pci_cleanup(pacc); - return 1; + snprintf(msg, ME_MESSAGE_LEN, CYEL "Not sure whether you have ME hardware, exiting\n\n" RESET); break; } } }
- if (!PCI_DEV_HAS_ME_DISABLE(dev->device_id) && - !PCI_DEV_HAS_ME_DIFFICULT(dev->device_id) && - !PCI_DEV_CAN_DISABLE_ME_IF_PRESENT(dev->device_id) && - !PCI_DEV_ME_NOT_SURE(dev->device_id)) { - printf(CCYN "ME is not present on your board or unkown\n\n" RESET); - pci_cleanup(pacc); - return 1; + if(!dev) { + snprintf(msg, ME_MESSAGE_LEN, CCYN "ME is not present on your board or unkown\n\n" RESET); }
pci_cleanup(pacc); - return 0; }
@@ -166,7 +170,7 @@ static struct pci_dev *pci_me_interface_scan(char **name) { for (dev=pacc->devices; dev; dev=dev->next) { pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_SIZES | PCI_FILL_CLASS); *name = pci_lookup_name(pacc, namebuf, sizeof(namebuf), - PCI_LOOKUP_DEVICE, dev->vendor_id, dev->device_id); + PCI_LOOKUP_DEVICE, dev->vendor_id, dev->device_id); if (dev->vendor_id == 0x8086) { if (PCI_DEV_HAS_SUPPORTED_ME(dev->device_id)) { me = 1; @@ -207,6 +211,9 @@ static int activate_me() {
rcba_phys = pci_read_long(sb, 0xf0) & 0xfffffffe; rcba = map_physical(rcba_phys, size); + if(!rcba) { + return 1; + }
//printf("RCBA at 0x%08" PRIx32 "\n", (uint32_t)rcba_phys); fd2 = *(uint32_t *)(rcba + FD2); @@ -225,9 +232,9 @@ static int activate_me() { static void dump_me_info() { struct pci_dev *dev; uint32_t stat, stat2; - char *name; + char *name, msg[ME_MESSAGE_LEN] = { 0 };
- if (pci_platform_scan()) { + if (pci_platform_scan(msg)) { exit(1); }
@@ -236,10 +243,9 @@ static void dump_me_info() { exit(1); }
- if (activate_me()) { - exit(1); - } + activate_me();
+ printf("%s", msg); printf("MEI found: [%x:%x] %s\n\n", dev->vendor_id, dev->device_id, name); stat = pci_read_long(dev, 0x40); printf("ME Status : 0x%x\n", stat); @@ -271,10 +277,63 @@ static void dump_me_info() { munmap((void*)rcba, size); }
+static void dump_bootguard_info() { + struct pci_dev *dev; + uint32_t stat = 0; + char *name, msg[ME_MESSAGE_LEN] = { 0 }; + uint64_t bootguard = 0; + + if(msr_bootguard(&bootguard, debug) < 0) { + return; + } + + pci_platform_scan(msg); + dev = pci_me_interface_scan(&name); + activate_me(); + + if(dev) { + stat = pci_read_long(dev, 0x40); + } + + printf(CYEL "Beware this feature is WIP and not stable!\n\n" RESET); + if(debug) { + printf("BootGuard MSR Output: 0x%" PRIx64 "\n", bootguard); + bootguard &= ~0xff; + } + + if(BOOTGUARD_CAPABILITY(bootguard)) { + printf("ME Capability: BootGuard : YES\n"); + if (dev && (stat & 0x10)) { + printf(CYEL "Your southbridge configuration is insecure!! BootGuard keys can be overwritten or wiped or you are in developer mode.\n" RESET); + } + switch(bootguard) { + case BOOTGUARD_DISABLED: + printf("ME Capability: BootGuard Mode : Disabled\n"); + printf(CGRN "Your system is bootguard ready but your vendor disabled it. You can flash other firmware!\n" RESET); + break; + case BOOTGUARD_ENABLED_COMBI_MODE: + printf("ME Capability: Bootguard Mode : Verified & Measured Boot\n"); + printf(CRED "You can't flash other firmware. Verified boot is enabled!\n" RESET); + break; + case BOOTGUARD_ENABLED_MEASUREMENT_MODE: + printf("ME Capability: Bootguard Mode : Measured Boot\n"); + printf(CGRN "Your system is bootguard ready but only running the measured boot mode. You can flash other firmware!\n" RESET); + break; + case BOOTGUARD_ENABLED_VERIFIED_MODE: + printf("ME Capability: Bootguard Mode : Verified Boot\n"); + printf(CRED "You can't flash other firmware. Verified boot is enabled!\n" RESET); + break; + } + } else { + printf("ME Capability: BootGuard : NO\n"); + printf(CGRN "Your system isn't bootguard ready. You can flash other firmware!\n" RESET); + } +} + static void print_version(void) { printf("intelmetool v%s -- ", INTELMETOOL_VERSION); - printf("Copyright (C) 2015 Damien Zammit\n\n"); + printf("Copyright (C) 2016 Damien Zammit, Philipp Deppenwiese\n\n"); printf( "This program is free software: you can redistribute it and/or modify\n" "it under the terms of the GNU General Public License as published by\n" @@ -287,13 +346,14 @@ static void print_version(void)
static void print_usage(const char *name) { - printf("usage: %s [-vh?sd]\n", name); + printf("usage: %s [-vh?mdb]\n", name); printf("\n" - " -v | --version: print the version\n" - " -h | --help: print this help\n\n" - " -s | --show: dump all me information on console\n" - " -d | --debug: enable debug output\n" - "\n"); + " -v | --version: print the version\n" + " -h | --help: print this help\n\n" + " -m | --me: dump all me related information on console\n" + " -b | --bootguard dump bootguard state of the platform\n" + " -d | --debug: enable debug output\n" + "\n"); exit(1); }
@@ -305,21 +365,25 @@ int main(int argc, char *argv[]) static struct option long_options[] = { {"version", 0, 0, 'v'}, {"help", 0, 0, 'h'}, - {"show", 0, 0, 's'}, + {"me", 0, 0, 'm'}, + {"bootguard", 0, 0, 'b'}, {"debug", 0, 0, 'd'}, {0, 0, 0, 0} };
- while ((opt = getopt_long(argc, argv, "vh?sd", - long_options, &option_index)) != EOF) { - switch (opt) { + while ((opt = getopt_long(argc, argv, "vh?mdb", + long_options, &option_index)) != EOF) { + switch (opt) { case 'v': print_version(); exit(0); break; - case 's': + case 'm': cmd_exec = 1; break; + case 'b': + cmd_exec = 2; + break; case 'd': debug = 1; break; @@ -329,42 +393,52 @@ int main(int argc, char *argv[]) print_usage(argv[0]); exit(0); break; - } } + }
#if defined(__FreeBSD__) - if (open("/dev/io", O_RDWR) < 0) { - perror("/dev/io"); + if (open("/dev/io", O_RDWR) < 0) { + perror("/dev/io"); #elif defined(__NetBSD__) # ifdef __i386__ - if (i386_iopl(3)) { - perror("iopl"); + if (i386_iopl(3)) { + perror("iopl"); # else - if (x86_64_iopl(3)) { - perror("iopl"); + if (x86_64_iopl(3)) { + perror("iopl"); # endif #else - if (iopl(3)) { - perror("iopl"); + if (iopl(3)) { + perror("iopl"); #endif - printf("You need to be root.\n"); - exit(1); - } + printf("You need to be root.\n"); + exit(1); + }
#ifndef __DARWIN__ - if ((fd_mem = open("/dev/mem", O_RDWR)) < 0) { - perror("Can not open /dev/mem"); - exit(1); - } + if ((fd_mem = open("/dev/mem", O_RDWR)) < 0) { + perror("Can not open /dev/mem"); + exit(1); + } + + get_cpu_id(cpu_id); + if(strncmp(cpu_id, "GenuineIntel", CPU_ID_SIZE-1)) { + perror("Error CPU is not from Intel."); + exit(1); + } #endif
switch(cmd_exec) { - case 1: - dump_me_info(); - break; - default: - print_usage(argv[0]); - break; + case 1: + dump_me_info(); + break; + case 2: + dump_bootguard_info(); + break; + default: + dump_me_info(); + dump_bootguard_info(); + break; }
return 0; diff --git a/util/intelmetool/intelmetool.h b/util/intelmetool/intelmetool.h index 4b9803b..ab2c0ea 100644 --- a/util/intelmetool/intelmetool.h +++ b/util/intelmetool/intelmetool.h @@ -22,7 +22,7 @@ #define ME_PRESENT_CAN_DISABLE 4 #define ME_PRESENT_CANNOT_DISABLE 5
-#define INTELMETOOL_VERSION "1.0" +#define INTELMETOOL_VERSION "1.1"
#if defined(__GLIBC__) #include <sys/io.h> @@ -48,6 +48,12 @@ #define CWHT "\x1B[37m" #define RESET "\033[0m"
+#define CPU_ID_SIZE 13 +#define FD2 0x3428 +#define ME_COMMAND_DELAY 10000 +#define ME_MESSAGE_LEN 256 +#define INTEL_PLATFORM_VENDOR_ID 0x8086 + extern int debug;
// Definitely has ME and can be disabled diff --git a/util/intelmetool/mmap.c b/util/intelmetool/mmap.c index da36eaa..bf3c378 100644 --- a/util/intelmetool/mmap.c +++ b/util/intelmetool/mmap.c @@ -28,8 +28,6 @@ void *map_physical_exact(uint64_t phys_addr, uint64_t mapto, size_t len) {
if (virt_addr == MAP_FAILED) { err = errno; - printf("Error mapping physical memory 0x%016" PRIx64 "[0x%zx] ERRNO=%d\n", - phys_addr, len, err); return NULL; }
@@ -44,8 +42,6 @@ void *map_physical(uint64_t phys_addr, size_t len) {
if (virt_addr == MAP_FAILED) { err = errno; - printf("Error mapping physical memory 0x%016" PRIx64 "[0x%zx] ERRNO=%d\n", - phys_addr, len, err); return NULL; }
diff --git a/util/intelmetool/msr.c b/util/intelmetool/msr.c new file mode 100644 index 0000000..34abb88 --- /dev/null +++ b/util/intelmetool/msr.c @@ -0,0 +1,77 @@ +/* intelmetool + * + * Copyright (C) 2013-2016 Philipp Deppenwiese zaolin@das-labor.org, Alexander Couzens lynxis@fe80.eu + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "msr.h" + +#ifndef __DARWIN__ +static int fd_msr = 0; + +static uint64_t rdmsr(int addr) +{ + uint32_t buf[2]; + uint64_t msr = 0; + + if (lseek(fd_msr, (off_t) addr, SEEK_SET) == -1) { + perror("Could not lseek() to MSR"); + close(fd_msr); + return -1; + } + + if (read(fd_msr, buf, 8) == 8) { + msr = buf[1]; + msr <<= 32; + msr |= buf[0]; + close(fd_msr); + return msr; + } + + if (errno == EIO) { + close(fd_msr); + return -2; + } else { + perror("Could not read() MSR"); + close(fd_msr); + return -1; + } + + return msr; +} +#endif + +int msr_bootguard(uint64_t *msr, int debug) { + +#ifndef __DARWIN__ + fd_msr = open("/dev/cpu/0/msr", O_RDONLY); + if (fd_msr < 0) { + perror("Error while opening /dev/cpu/0/msr"); + printf("Did you run 'modprobe msr'?\n"); + return -1; + } +#endif + + *msr = rdmsr(MSR_BOOTGUARD); + if(debug) { + *msr &= ~0xff; + } + + return 0; +} diff --git a/util/intelmetool/msr.h b/util/intelmetool/msr.h new file mode 100644 index 0000000..b46a8da --- /dev/null +++ b/util/intelmetool/msr.h @@ -0,0 +1,43 @@ +/* intelmetool + * + * Copyright (C) 2013-2016 Philipp Deppenwiese zaolin@das-labor.org, Alexander Couzens lynxis@fe80.eu + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <inttypes.h> +#include <stdlib.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <stdio.h> + +#define MSR_BOOTGUARD 0x13A + +#define BOOTGUARD_DISABLED 0x400000000 +#define BOOTGUARD_ENABLED_VERIFIED_MODE 0x100000000 +#define BOOTGUARD_ENABLED_MEASUREMENT_MODE 0x200000000 +#define BOOTGUARD_ENABLED_COMBI_MODE 0x300000000 +#define BOOTGUARD_CAPABILITY(x) ( \ + ( (x) == BOOTGUARD_DISABLED ) || \ + ( (x) == BOOTGUARD_ENABLED_VERIFIED_MODE ) || \ + ( (x) == BOOTGUARD_ENABLED_MEASUREMENT_MODE ) || \ + ( (x) == BOOTGUARD_ENABLED_COMBI_MODE )) + +#ifndef __DARWIN__ + +typedef struct { + unsigned int ebx; + unsigned int edx; + unsigned int ecx; +} cpu_t; + +extern int msr_bootguard(uint64_t *msr, int debug); +#endif