intelmetool.c
1 /* intelmetool Dump interesting things about Management Engine even if hidden */ 2 /* SPDX-License-Identifier: GPL-2.0-or-later */ 3 4 #include <stdio.h> 5 #include <inttypes.h> 6 #include <stdlib.h> 7 #include <getopt.h> 8 #include <unistd.h> 9 #include <string.h> 10 #include <cpuid.h> 11 #include <sys/io.h> 12 13 #ifdef __NetBSD__ 14 #include <machine/sysarch.h> 15 #endif 16 17 #include "intelmetool.h" 18 #include "me.h" 19 #include "mmap.h" 20 #include "msr.h" 21 #include "rcba.h" 22 23 extern int fd_mem; 24 int debug = 0; 25 26 static uint32_t fd2 = 0; 27 static int ME_major_ver = 0; 28 static int ME_minor_ver = 0; 29 30 static void dumpmem(uint8_t *phys, uint32_t size) 31 { 32 uint32_t i; 33 printf("Dumping cloned ME memory:\n"); 34 for (i = 0; i < size; i++) { 35 printf("%02X",*((uint8_t *) (phys + i))); 36 } 37 printf("\n"); 38 } 39 40 static void zeroit(uint8_t *phys, uint32_t size) 41 { 42 uint32_t i; 43 for (i = 0; i < size; i++) { 44 *((uint8_t *) (phys + i)) = 0x00; 45 } 46 } 47 48 static void dumpmemfile(uint8_t *phys, uint32_t size) 49 { 50 FILE *fp = fopen("medump.bin", "w"); 51 uint32_t i; 52 for (i = 0; i < size; i++) { 53 fprintf(fp, "%c", *((uint8_t *) (phys + i))); 54 } 55 fclose(fp); 56 } 57 58 static int isCPUGenuineIntel(void) 59 { 60 regs_t regs; 61 unsigned int level = 0; 62 unsigned int eax = 0; 63 64 __get_cpuid(level, &eax, ®s.ebx, ®s.ecx, ®s.edx); 65 66 return !strncmp((char *)®s, "GenuineIntel", CPU_ID_SIZE-1); 67 } 68 69 /* You need >4GB total ram, in kernel cmdline, use 'mem=1000m' 70 * then this code will clone to absolute memory address 0xe0000000 71 * which can be read using a mmap tool at that offset. 72 * Real ME memory is located around top of memory minus 64MB. (I think) 73 * so we avoid cloning to this part. 74 */ 75 static void dump_me_memory(void) 76 { 77 uintptr_t me_clone = 0x60000000; 78 uint8_t *dump; 79 80 dump = map_physical_exact((off_t)me_clone, (void *)me_clone, 0x2000000); 81 if (dump == NULL) { 82 printf("Could not map ME memory\n"); 83 return; 84 } 85 zeroit(dump, 0x2000000); 86 printf("Send magic command for memory clone\n"); 87 88 mei_reset(); 89 usleep(ME_COMMAND_DELAY); 90 void* ptr = &me_clone; 91 int err = mkhi_debug_me_memory(ptr); 92 93 if (!err) { 94 printf("Wait a second..."); 95 usleep(ME_COMMAND_DELAY); 96 printf("done\n\nHere are the first bytes:\n"); 97 dumpmemfile(dump, 0x2000000); 98 //printf("Try reading 0x%zx with other mmap tool...\n" 99 // "Press enter to quit, you only get one chance to run" 100 // "this tool before reboot required for some reason\n", 101 // me_clone); 102 while (getc(stdin) != '\n') {}; 103 unmap_physical(dump, 0x2000000); 104 } 105 } 106 107 static int pci_platform_scan(void) 108 { 109 struct pci_access *pacc; 110 struct pci_dev *dev; 111 char namebuf[1024]; 112 const char *name; 113 114 pacc = pci_alloc(); 115 pacc->method = PCI_ACCESS_I386_TYPE1; 116 117 pci_init(pacc); 118 pci_scan_bus(pacc); 119 120 for (dev=pacc->devices; dev; dev=dev->next) { 121 pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_BASES | 122 PCI_FILL_SIZES | PCI_FILL_CLASS); 123 name = pci_lookup_name(pacc, namebuf, sizeof(namebuf), 124 PCI_LOOKUP_DEVICE, dev->vendor_id, dev->device_id); 125 if (name == NULL) 126 name = "<unknown>"; 127 if (dev->vendor_id != PCI_VENDOR_ID_INTEL) 128 continue; 129 130 if (PCI_DEV_NO_ME(dev->device_id)) { 131 printf(CGRN "Good news, you have a `%s` so you have " 132 "no ME present at all, continuing...\n\n" 133 RESET, name); 134 break; 135 } else if (PCI_DEV_HAS_ME_DISABLE(dev->device_id)) { 136 printf(CGRN "Good news, you have a `%s` so ME is " 137 "present but can be disabled, continuing...\n\n" 138 RESET, name); 139 break; 140 } else if (PCI_DEV_HAS_ME_DIFFICULT(dev->device_id)) { 141 printf(CRED "Bad news, you have a `%s` so you have ME " 142 "hardware on board and you can't control or " 143 "disable it, continuing...\n\n" RESET, name); 144 break; 145 } else if (PCI_DEV_CAN_DISABLE_ME_IF_PRESENT(dev->device_id)) { 146 printf(CYEL "Not sure if ME hardware is present " 147 "because you have a `%s`, but it is possible to " 148 "disable it if you do, continuing...\n\n" RESET, 149 name); 150 break; 151 } else if (PCI_DEV_ME_NOT_SURE(dev->device_id)) { 152 printf(CYEL "Found `%s`. Not sure whether you have ME " 153 "hardware, exiting\n\n" RESET, name); 154 pci_cleanup(pacc); 155 return 1; 156 } 157 } 158 159 if (dev != NULL && 160 !PCI_DEV_HAS_ME_DISABLE(dev->device_id) && 161 !PCI_DEV_HAS_ME_DIFFICULT(dev->device_id) && 162 !PCI_DEV_CAN_DISABLE_ME_IF_PRESENT(dev->device_id) && 163 !PCI_DEV_ME_NOT_SURE(dev->device_id)) { 164 printf(CCYN "ME is not present on your board or unknown\n\n" 165 RESET); 166 pci_cleanup(pacc); 167 return 1; 168 } 169 170 pci_cleanup(pacc); 171 172 return 0; 173 } 174 175 static int activate_me(void) 176 { 177 const uint32_t rcba = get_rcba_phys(); 178 if (debug) 179 printf("RCBA addr: 0x%08x\n", rcba); 180 if (rcba > 0) { 181 if (read_rcba32(FD2, &fd2)) { 182 printf("Error reading RCBA\n"); 183 return 1; 184 } 185 if (write_rcba32(FD2, fd2 & ~0x2)) { 186 printf("Error writing RCBA\n"); 187 return 1; 188 } 189 if (debug && (fd2 & 0x2)) 190 printf("MEI was hidden on PCI, now unlocked\n"); 191 else if (debug) 192 printf("MEI not hidden on PCI, checking if visible\n"); 193 } 194 195 return 0; 196 } 197 198 static void rehide_me(void) 199 { 200 const uint32_t rcba = get_rcba_phys(); 201 if (rcba > 0) { 202 if (fd2 & 0x2) { 203 if (debug) 204 printf("Re-hiding MEI device..."); 205 if (read_rcba32(FD2, &fd2)) { 206 printf("Error reading RCBA\n"); 207 return; 208 } 209 if (write_rcba32(FD2, fd2 | 0x2)) { 210 printf("Error writing RCBA\n"); 211 return; 212 } 213 if (debug) 214 printf("done\n"); 215 } 216 } 217 } 218 219 static struct pci_dev *pci_me_interface_scan(const char **name, char *namebuf, 220 int namebuf_size) 221 { 222 struct pci_access *pacc; 223 struct pci_dev *dev; 224 int me = 0; 225 226 pacc = pci_alloc(); 227 pacc->method = PCI_ACCESS_I386_TYPE1; 228 229 pci_init(pacc); 230 pci_scan_bus(pacc); 231 232 for (dev=pacc->devices; dev; dev=dev->next) { 233 pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_BASES | 234 PCI_FILL_SIZES | PCI_FILL_CLASS); 235 *name = pci_lookup_name(pacc, namebuf, namebuf_size, 236 PCI_LOOKUP_DEVICE, dev->vendor_id, dev->device_id); 237 if (dev->vendor_id != PCI_VENDOR_ID_INTEL) 238 continue; 239 240 if (PCI_DEV_HAS_SUPPORTED_ME(dev->device_id)) { 241 me = 1; 242 break; 243 } 244 } 245 246 if (!me) { 247 rehide_me(); 248 249 pci_cleanup(pacc); 250 return NULL; 251 } 252 253 return dev; 254 } 255 256 static void dump_me_info(void) 257 { 258 struct pci_dev *dev; 259 uint32_t stat, stat2; 260 char namebuf[1024]; 261 const char *name = NULL; 262 263 if (pci_platform_scan()) 264 return; 265 266 dev = pci_me_interface_scan(&name, namebuf, sizeof(namebuf)); 267 if (!dev) { 268 if (debug) 269 printf("ME PCI device is hidden\n"); 270 271 if (activate_me()) 272 return; 273 dev = pci_me_interface_scan(&name, namebuf, sizeof(namebuf)); 274 if (!dev) { 275 printf("Can't find ME PCI device\n"); 276 return; 277 } 278 } 279 280 if (name == NULL) 281 name = "<unknown>"; 282 283 printf("MEI found: [%x:%x] %s\n\n", 284 dev->vendor_id, dev->device_id, name); 285 stat = pci_read_long(dev, 0x40); 286 printf("ME Status : 0x%x\n", stat); 287 stat2 = pci_read_long(dev, 0x48); 288 printf("ME Status 2 : 0x%x\n\n", stat2); 289 290 intel_me_status(stat, stat2); 291 printf("\n"); 292 intel_me_extend_valid(dev); 293 printf("\n"); 294 295 if (stat & 0xf000) 296 printf("ME: has a broken implementation on your board with " 297 "this firmware\n"); 298 299 if (intel_mei_setup(dev)) 300 goto out; 301 usleep(ME_COMMAND_DELAY); 302 mei_reset(); 303 usleep(ME_COMMAND_DELAY); 304 if (mkhi_get_fw_version(&ME_major_ver, &ME_minor_ver)) 305 goto out; 306 usleep(ME_COMMAND_DELAY); 307 mei_reset(); 308 usleep(ME_COMMAND_DELAY); 309 if (mkhi_get_fwcaps()) 310 goto out; 311 usleep(ME_COMMAND_DELAY); 312 313 out: 314 rehide_me(); 315 } 316 317 static void print_btg_bool_param(const char *name, u8 state) 318 { 319 printf("%-20s : %s\n", name, state ? "ON" : "OFF"); 320 } 321 322 static void dump_bootguard_info(void) 323 { 324 struct pci_dev *dev; 325 char namebuf[1024]; 326 const char *name = NULL; 327 328 if (pci_platform_scan()) 329 return; 330 331 dev = pci_me_interface_scan(&name, namebuf, sizeof(namebuf)); 332 if (!dev) { 333 if (debug) 334 printf("ME PCI device is hidden\n"); 335 336 if (activate_me()) 337 return; 338 dev = pci_me_interface_scan(&name, namebuf, sizeof(namebuf)); 339 if (!dev) { 340 printf("Can't find ME PCI device\n"); 341 return; 342 } 343 } 344 345 /* ME_major_ver is zero on some platforms (Mac) */ 346 if (ME_major_ver && 347 (ME_major_ver < 9 || 348 (ME_major_ver == 9 && ME_minor_ver < 5))) { 349 printf(CGRN "Your system isn't Boot Guard ready.\n" 350 "You can flash other firmware!\n" RESET); 351 rehide_me(); 352 return; 353 } 354 355 if (pci_read_long(dev, 0x40) & 0x10) 356 printf(CYEL "Your southbridge configuration is insecure!!\n" 357 "Boot Guard keys can be overwritten or wiped, or you are " 358 "in developer mode.\n" 359 RESET); 360 rehide_me(); 361 362 union { 363 struct { 364 u8 nem_enabled : 1; /* [ 0.. 0] */ 365 u8 tpm_type : 2; /* [ 2.. 1] */ 366 u8 tpm_success : 1; /* [ 3.. 3] */ 367 u8 facb_fpf : 1; /* [ 4.. 4] */ 368 u8 measured_boot : 1; /* [ 5.. 5] */ 369 u8 verified_boot : 1; /* [ 6.. 6] */ 370 u8 module_revoked : 1; /* [ 7.. 7] */ 371 u32 : 24; 372 u8 btg_capability : 1; /* [32..32] */ 373 u32 : 31; 374 }; 375 u64 raw; 376 } btg; 377 378 if (msr_bootguard(&btg.raw) < 0) { 379 printf("Could not read the BOOTGUARD_SACM_INFO MSR.\n"); 380 return; 381 } 382 383 printf("Boot Guard MSR Output : 0x%" PRIx64 "\n", btg.raw); 384 385 if (!btg.btg_capability) { 386 printf(CGRN "Your system isn't Boot Guard ready.\n" 387 "You can flash other firmware!\n" RESET); 388 return; 389 } 390 391 print_btg_bool_param("Measured boot", btg.measured_boot); 392 print_btg_bool_param("Verified boot", btg.verified_boot); 393 print_btg_bool_param("FACB in FPFs", btg.facb_fpf); 394 print_btg_bool_param("Module revoked", btg.module_revoked); 395 if (btg.measured_boot) { 396 const char *const tpm_type_strs[] = { 397 "None", 398 "TPM 1.2", 399 "TPM 2.0", 400 "PTT", 401 }; 402 printf("%-20s : %s\n", "TPM type", tpm_type_strs[btg.tpm_type]); 403 print_btg_bool_param("TPM success", btg.tpm_success); 404 } 405 if (btg.verified_boot) { 406 print_btg_bool_param("NEM enabled", btg.nem_enabled); 407 if (btg.nem_enabled) 408 printf(CRED "Verified boot is enabled and ACM has enabled " 409 "Cache-As-RAM.\nYou can't flash other firmware!\n" RESET); 410 else 411 printf(CYEL "Verified boot is enabled, but ACM did not enable " 412 "Cache-As-RAM.\nIt might be possible to flash other firmware.\n" 413 RESET); 414 } else { 415 printf(CGRN "Your system is Boot Guard ready but verified boot is disabled.\n" 416 "You can flash other firmware!\n" RESET); 417 } 418 } 419 420 static void print_version(void) 421 { 422 printf("intelmetool v%s -- ", INTELMETOOL_VERSION); 423 printf("Copyright (C) 2015 Damien Zammit\n"); 424 printf("Copyright (C) 2017 Philipp Deppenwiese\n"); 425 printf("Copyright (C) 2017 Patrick Rudolph\n\n"); 426 printf(GPLV2COPYRIGHT); 427 } 428 429 static void print_usage(const char *name) 430 { 431 printf("usage: %s [-vh?smdb]\n", name); 432 printf("\n" 433 " -v | --version: print the version\n" 434 " -h | --help: print this help\n\n" 435 " -d | --debug: enable debug output\n" 436 " -m | --me dump all me information on console\n" 437 " -b | --bootguard dump bootguard state of the platform\n" 438 "\n"); 439 exit(1); 440 } 441 442 int main(int argc, char *argv[]) 443 { 444 int opt, option_index = 0; 445 unsigned cmd_exec = 0; 446 447 static struct option long_options[] = { 448 {"version", 0, 0, 'v'}, 449 {"help", 0, 0, 'h'}, 450 {"me", 0, 0, 'm'}, 451 {"bootguard", 0, 0, 'b'}, 452 {"debug", 0, 0, 'd'}, 453 {0, 0, 0, 0} 454 }; 455 456 while ((opt = getopt_long(argc, argv, "vh?smdb", 457 long_options, &option_index)) != EOF) { 458 switch (opt) { 459 case 'v': 460 print_version(); 461 exit(0); 462 break; 463 case 's': /* Legacy fallthrough */ 464 case 'm': 465 cmd_exec = 1; 466 break; 467 case 'b': 468 cmd_exec = 2; 469 break; 470 case 'd': 471 debug = 1; 472 break; 473 case 'h': 474 case '?': 475 default: 476 print_usage(argv[0]); 477 exit(0); 478 break; 479 } 480 } 481 482 if (!cmd_exec) 483 print_usage(argv[0]); 484 485 #if defined(__FreeBSD__) 486 if (open("/dev/io", O_RDWR) < 0) { 487 perror("/dev/io"); 488 #elif defined(__NetBSD__) 489 # ifdef __i386__ 490 if (i386_iopl(3)) { 491 perror("iopl"); 492 # else 493 if (x86_64_iopl(3)) { 494 perror("iopl"); 495 # endif 496 #else 497 if (iopl(3)) { 498 perror("iopl"); 499 #endif 500 printf("You need to be root.\n"); 501 exit(1); 502 } 503 504 #ifndef __DARWIN__ 505 fd_mem = open("/dev/mem", O_RDWR); 506 if (fd_mem < 0) { 507 perror("Can not open /dev/mem. Do you have disabled " 508 "Secure Boot ?"); 509 exit(1); 510 } 511 512 if (!isCPUGenuineIntel()) { 513 perror("Error CPU is not from Intel."); 514 exit(1); 515 } 516 #endif 517 518 if (cmd_exec & 3) 519 dump_me_info(); 520 if (cmd_exec & 2) 521 dump_bootguard_info(); 522 523 return 0; 524 }