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 0263307f27a533d346d02f2ad66ef9e123b2e245 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 | 164 ++++++++++++++++++++++++++++------------- util/intelmetool/intelmetool.h | 2 +- util/intelmetool/mmap.c | 4 - util/intelmetool/msr.c | 98 ++++++++++++++++++++++++ util/intelmetool/msr.h | 43 +++++++++++ 6 files changed, 254 insertions(+), 59 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..6f4da0b 100644 --- a/util/intelmetool/intelmetool.c +++ b/util/intelmetool/intelmetool.c @@ -16,6 +16,7 @@ #include <stdlib.h> #include <getopt.h> #include <unistd.h> +#include <string.h>
#ifdef __NetBSD__ #include <machine/sysarch.h> @@ -23,6 +24,7 @@
#include "me.h" #include "mmap.h" +#include "msr.h" #include "intelmetool.h"
#define FD2 0x3428 @@ -83,6 +85,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");
@@ -106,7 +112,6 @@ static void dump_me_memory() { static int pci_platform_scan() { struct pci_access *pacc; struct pci_dev *dev; - char namebuf[1024], *name;
pacc = pci_alloc(); pacc->method = PCI_ACCESS_I386_TYPE1; @@ -116,38 +121,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 (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); + printf(CGRN "Good news, your ME is present but can be disabled, continuing...\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); + printf(CRED "Bad news, you have a ME hardware on board and you can't control or disable it, continuing...\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); + printf(CYEL "Not sure if ME hardware is present, but it is possible to disable it if you do, continuing...\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; + printf(CYEL "Not sure whether you have ME hardware, exiting\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) { + printf(CCYN "ME is not present on your board or unkown\n" RESET); }
pci_cleanup(pacc); - return 0; }
@@ -166,7 +161,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 +202,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); @@ -231,14 +229,14 @@ static void dump_me_info() { exit(1); }
+ printf("\n"); + dev = pci_me_interface_scan(&name); if (!dev) { exit(1); }
- if (activate_me()) { - exit(1); - } + activate_me();
printf("MEI found: [%x:%x] %s\n\n", dev->vendor_id, dev->device_id, name); stat = pci_read_long(dev, 0x40); @@ -271,10 +269,62 @@ static void dump_me_info() { munmap((void*)rcba, size); }
+static void dump_bootguard_info() { + int result = 0; + struct pci_dev *dev; + uint32_t stat = 0; + char *name; + uint64_t bootguard; + + bootguard = msr_bootguard(&result); + + if(result < 0) { + return; + } + + pci_platform_scan(); + 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); + } + + if(BOOTGUARD_CAPABILITY(bootguard)) { + printf("ME BootGuard Capability: YES\n"); + if (dev && (stat & 0x10) >> 4) { + printf(CRED "Your southbridge configuration is insecure!! BootGuard keys can be overwritten or wiped.\n" RESET); + } + switch(bootguard) { + case BOOTGUARD_DISABLED: + printf("ME 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 BootGuard Mode: Verified & Measured Boot\n"); + break; + case BOOTGUARD_ENABLED_MEASUREMENT_MODE: + printf("ME BootGuard Mode: Measured Boot\n"); + break; + case BOOTGUARD_ENABLED_VERIFIED_MODE: + printf("ME BootGuard Mode: Verified Boot\n"); + break; + } + } else { + printf("ME BootGuard Capability: 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 +337,14 @@ static void print_version(void)
static void print_usage(const char *name) { - printf("usage: %s [-vh?sd]\n", name); + printf("usage: %s [-vh?sdb]\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" + " -s | --show: dump all me information on console\n" + " -b | --bootguard dump bootguard state of the platform\n" + " -d | --debug: enable debug output\n" + "\n"); exit(1); }
@@ -306,13 +357,14 @@ int main(int argc, char *argv[]) {"version", 0, 0, 'v'}, {"help", 0, 0, 'h'}, {"show", 0, 0, 's'}, + {"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?sdb", + long_options, &option_index)) != EOF) { + switch (opt) { case 'v': print_version(); exit(0); @@ -320,6 +372,9 @@ int main(int argc, char *argv[]) case 's': cmd_exec = 1; break; + case 'b': + cmd_exec = 2; + break; case 'd': debug = 1; break; @@ -329,42 +384,45 @@ 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); + } #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: + print_usage(argv[0]); + break; }
return 0; diff --git a/util/intelmetool/intelmetool.h b/util/intelmetool/intelmetool.h index 4b9803b..019b79d 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> 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..3314fb4 --- /dev/null +++ b/util/intelmetool/msr.c @@ -0,0 +1,98 @@ +/* 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 <cpuid.h> + +#include "msr.h" + +#define CPU_ID_SIZE 13 + +#ifndef __DARWIN__ +int fd_msr = 0; + +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); +} + +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 == 5) { + close(fd_msr); + return -2; + } else { + perror("Could not read() MSR"); + close(fd_msr); + return -1; + } + + return msr; +} +#endif + +uint64_t msr_bootguard(int *result) { + uint64_t msr = 0; + char cpu_id[CPU_ID_SIZE] = { 0 }; + +#ifndef __DARWIN__ + get_cpu_id(cpu_id); + if(strncmp(cpu_id, "GenuineIntel", CPU_ID_SIZE-1)) { + perror("Error CPU is not from Intel."); + *result = -1; + return 0; + } + + fd_msr = open("/dev/cpu/0/msr", O_RDWR); + if (fd_msr < 0) { + perror("Error while opening /dev/cpu/0/msr"); + printf("Did you run 'modprobe msr'?\n"); + *result = -2; + return 0; + } +#endif + + msr = rdmsr(MSR_BOOTGUARD); + msr &= ~0xff; + + return msr; +} diff --git a/util/intelmetool/msr.h b/util/intelmetool/msr.h new file mode 100644 index 0000000..c76206b --- /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 uint64_t msr_bootguard(int *result); +#endif