... | ... |
@@ -34,6 +34,7 @@ |
34 | 34 |
#include "cltypes.h" |
35 | 35 |
#include "others.h" |
36 | 36 |
#include "gpt.h" |
37 |
+#include "mbr.h" |
|
37 | 38 |
#include "str.h" |
38 | 39 |
#include "prtn_intxn.h" |
39 | 40 |
#include "scanners.h" |
... | ... |
@@ -63,6 +64,7 @@ enum GPT_SCANSTATE { |
63 | 63 |
|
64 | 64 |
static int gpt_scan_partitions(cli_ctx *ctx, struct gpt_header hdr, size_t sectorsize); |
65 | 65 |
static int gpt_validate_header(cli_ctx *ctx, struct gpt_header hdr, size_t sectorsize); |
66 |
+static int gpt_check_mbr(cli_ctx *ctx, size_t sectorsize); |
|
66 | 67 |
static void gpt_printSectors(cli_ctx *ctx, size_t sectorsize); |
67 | 68 |
static void gpt_printName(uint16_t name[], const char* msg); |
68 | 69 |
static void gpt_printGUID(uint8_t GUID[], const char* msg); |
... | ... |
@@ -111,7 +113,7 @@ int cli_scangpt(cli_ctx *ctx, size_t sectorsize) |
111 | 111 |
/* sector size calculatation */ |
112 | 112 |
if (sectorsize == 0) { |
113 | 113 |
sectorsize = gpt_detect_size((*ctx->fmap)); |
114 |
- cli_errmsg("cli_scangpt: detected %u sector size\n", sectorsize); |
|
114 |
+ cli_dbgmsg("cli_scangpt: detected %u sector size\n", sectorsize); |
|
115 | 115 |
} |
116 | 116 |
if (sectorsize == 0) { |
117 | 117 |
cli_errmsg("cli_scangpt: could not detemine sector size\n"); |
... | ... |
@@ -126,6 +128,14 @@ int cli_scangpt(cli_ctx *ctx, size_t sectorsize) |
126 | 126 |
return CL_EFORMAT; |
127 | 127 |
} |
128 | 128 |
|
129 |
+ /* check the protective mbr */ |
|
130 |
+ ret = gpt_check_mbr(ctx, sectorsize); |
|
131 |
+ if ((ret != CL_CLEAN) && |
|
132 |
+ !((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))) { |
|
133 |
+ |
|
134 |
+ return ret; |
|
135 |
+ } |
|
136 |
+ |
|
129 | 137 |
pos = GPT_PRIMARY_HDR_LBA * sectorsize; /* sector 1 (second sector) is the primary gpt header */ |
130 | 138 |
|
131 | 139 |
/* read primary gpt header */ |
... | ... |
@@ -454,6 +464,58 @@ static int gpt_validate_header(cli_ctx *ctx, struct gpt_header hdr, size_t secto |
454 | 454 |
return CL_SUCCESS; |
455 | 455 |
} |
456 | 456 |
|
457 |
+static int gpt_check_mbr(cli_ctx *ctx, size_t sectorsize) |
|
458 |
+{ |
|
459 |
+ struct mbr_boot_record pmbr; |
|
460 |
+ off_t pos = 0, mbr_base = 0; |
|
461 |
+ int ret = CL_CLEAN; |
|
462 |
+ unsigned i = 0; |
|
463 |
+ |
|
464 |
+ /* read the mbr */ |
|
465 |
+ mbr_base = sectorsize - sizeof(struct mbr_boot_record); |
|
466 |
+ pos = (MBR_SECTOR * sectorsize) + mbr_base; |
|
467 |
+ |
|
468 |
+ if (fmap_readn(*ctx->fmap, &pmbr, pos, sizeof(pmbr)) != sizeof(pmbr)) { |
|
469 |
+ cli_dbgmsg("cli_scangpt: Invalid primary MBR header\n"); |
|
470 |
+ return CL_EFORMAT; |
|
471 |
+ } |
|
472 |
+ |
|
473 |
+ /* convert mbr */ |
|
474 |
+ mbr_convert_to_host(&pmbr); |
|
475 |
+ |
|
476 |
+ /* check the protective mbr - warning */ |
|
477 |
+ if (pmbr.entries[0].type == MBR_PROTECTIVE) { |
|
478 |
+ /* check the efi partition matches the gpt spec */ |
|
479 |
+ if (pmbr.entries[0].firstLBA != GPT_PRIMARY_HDR_LBA) { |
|
480 |
+ cli_warnmsg("cli_scangpt: protective MBR first LBA is incorrect %u\n", |
|
481 |
+ pmbr.entries[0].firstLBA); |
|
482 |
+ } |
|
483 |
+ |
|
484 |
+ /* other entries are empty */ |
|
485 |
+ for (i = 1; i < MBR_MAX_PARTITION_ENTRIES; ++i) { |
|
486 |
+ if (pmbr.entries[i].type != MBR_EMPTY) { |
|
487 |
+ cli_warnmsg("cli_scangpt: protective MBR has non-empty partition\n"); |
|
488 |
+ break; |
|
489 |
+ } |
|
490 |
+ } |
|
491 |
+ } |
|
492 |
+ else if (pmbr.entries[0].type == MBR_HYBRID) { |
|
493 |
+ /* hybrid mbr detected */ |
|
494 |
+ cli_warnmsg("cli_scangpt: detected a hybrid MBR\n"); |
|
495 |
+ } |
|
496 |
+ else { |
|
497 |
+ /* non-protective mbr detected */ |
|
498 |
+ cli_warnmsg("cli_scangpt: detected a non-protective MBR\n"); |
|
499 |
+ } |
|
500 |
+ |
|
501 |
+ /* scan the bootloader segment - pushed to scanning mbr */ |
|
502 |
+ /* check if MBR size matches GPT size */ |
|
503 |
+ /* check if the MBR and GPT partitions align - heuristic */ |
|
504 |
+ /* scan the MBR partitions - additional scans */ |
|
505 |
+ |
|
506 |
+ return ret; |
|
507 |
+} |
|
508 |
+ |
|
457 | 509 |
static void gpt_printSectors(cli_ctx *ctx, size_t sectorsize) |
458 | 510 |
{ |
459 | 511 |
#ifdef DEBUG_GPT_PARSE |
... | ... |
@@ -67,7 +67,6 @@ enum MBR_STATE { |
67 | 67 |
static int mbr_scanextprtn(cli_ctx *ctx, unsigned *prtncount, off_t extlba, |
68 | 68 |
size_t extlbasize, size_t sectorsize); |
69 | 69 |
static void mbr_printbr(struct mbr_boot_record *record); |
70 |
-static void mbr_convert_to_host(struct mbr_boot_record *record); |
|
71 | 70 |
static int mbr_check_mbr(struct mbr_boot_record *record, size_t maplen, size_t sectorsize); |
72 | 71 |
static int mbr_check_ebr(struct mbr_boot_record *record); |
73 | 72 |
static int mbr_primary_prtn_intxn(cli_ctx *ctx, struct mbr_boot_record mbr, size_t sectorsize); |
... | ... |
@@ -273,11 +272,11 @@ static int mbr_scanextprtn(cli_ctx *ctx, unsigned *prtncount, off_t extlba, size |
273 | 273 |
logiclba = 0; |
274 | 274 |
/* fall-through */ |
275 | 275 |
case SEEN_EXTENDED: |
276 |
- cli_dbgmsg("cli_scanebr: detected a logical boot record " |
|
277 |
- "without a partition record\n"); |
|
276 |
+ cli_warnmsg("cli_scanebr: detected a logical boot record " |
|
277 |
+ "without a partition record\n"); |
|
278 | 278 |
break; |
279 | 279 |
default: |
280 |
- cli_dbgmsg("cli_scanebr: undefined state for EBR parsing\n"); |
|
280 |
+ cli_warnmsg("cli_scanebr: undefined state for EBR parsing\n"); |
|
281 | 281 |
return CL_EPARSE; |
282 | 282 |
} |
283 | 283 |
} |
... | ... |
@@ -289,12 +288,12 @@ static int mbr_scanextprtn(cli_ctx *ctx, unsigned *prtncount, off_t extlba, size |
289 | 289 |
case SEEN_PARTITION: |
290 | 290 |
break; |
291 | 291 |
case SEEN_EMPTY: |
292 |
- cli_dbgmsg("cli_scanebr: detected a logical boot record " |
|
293 |
- "without a partition record\n"); |
|
292 |
+ cli_warnmsg("cli_scanebr: detected a logical boot record " |
|
293 |
+ "without a partition record\n"); |
|
294 | 294 |
break; |
295 | 295 |
case SEEN_EXTENDED: |
296 |
- cli_dbgmsg("cli_scanebr: detected a logical boot record " |
|
297 |
- "with multiple extended partition records\n"); |
|
296 |
+ cli_warnmsg("cli_scanebr: detected a logical boot record " |
|
297 |
+ "with multiple extended partition records\n"); |
|
298 | 298 |
return CL_EFORMAT; |
299 | 299 |
default: |
300 | 300 |
cli_dbgmsg("cli_scanebr: undefined state for EBR parsing\n"); |
... | ... |
@@ -309,17 +308,17 @@ static int mbr_scanextprtn(cli_ctx *ctx, unsigned *prtncount, off_t extlba, size |
309 | 309 |
state = SEEN_PARTITION; |
310 | 310 |
break; |
311 | 311 |
case SEEN_PARTITION: |
312 |
- cli_dbgmsg("cli_scanebr: detected a logical boot record " |
|
313 |
- "with multiple partition records\n"); |
|
312 |
+ cli_warnmsg("cli_scanebr: detected a logical boot record " |
|
313 |
+ "with multiple partition records\n"); |
|
314 | 314 |
logiclba = 0; /* no extended partitions are possible */ |
315 | 315 |
break; |
316 | 316 |
case SEEN_EXTENDED: |
317 |
- cli_dbgmsg("cli_scanebr: detected a logical boot record " |
|
318 |
- "with extended partition record first\n"); |
|
317 |
+ cli_warnmsg("cli_scanebr: detected a logical boot record " |
|
318 |
+ "with extended partition record first\n"); |
|
319 | 319 |
break; |
320 | 320 |
case SEEN_EMPTY: |
321 |
- cli_dbgmsg("cli_scanebr: detected a logical boot record " |
|
322 |
- "with empty partition record first\n"); |
|
321 |
+ cli_warnmsg("cli_scanebr: detected a logical boot record " |
|
322 |
+ "with empty partition record first\n"); |
|
323 | 323 |
logiclba = 0; /* no extended partitions are possible */ |
324 | 324 |
break; |
325 | 325 |
default: |
... | ... |
@@ -357,6 +356,20 @@ static int mbr_scanextprtn(cli_ctx *ctx, unsigned *prtncount, off_t extlba, size |
357 | 357 |
return ret; |
358 | 358 |
} |
359 | 359 |
|
360 |
+void mbr_convert_to_host(struct mbr_boot_record *record) |
|
361 |
+{ |
|
362 |
+ struct mbr_partition_entry *entry; |
|
363 |
+ unsigned i; |
|
364 |
+ |
|
365 |
+ for (i = 0; i < MBR_MAX_PARTITION_ENTRIES; ++i) { |
|
366 |
+ entry = &record->entries[i]; |
|
367 |
+ |
|
368 |
+ entry->firstLBA = le32_to_host(entry->firstLBA); |
|
369 |
+ entry->numLBA = le32_to_host(entry->numLBA); |
|
370 |
+ } |
|
371 |
+ record->signature = be16_to_host(record->signature); |
|
372 |
+} |
|
373 |
+ |
|
360 | 374 |
static void mbr_printbr(struct mbr_boot_record *record) |
361 | 375 |
{ |
362 | 376 |
unsigned i; |
... | ... |
@@ -375,20 +388,6 @@ static void mbr_printbr(struct mbr_boot_record *record) |
375 | 375 |
} |
376 | 376 |
} |
377 | 377 |
|
378 |
-static void mbr_convert_to_host(struct mbr_boot_record *record) |
|
379 |
-{ |
|
380 |
- struct mbr_partition_entry *entry; |
|
381 |
- unsigned i; |
|
382 |
- |
|
383 |
- for (i = 0; i < MBR_MAX_PARTITION_ENTRIES; ++i) { |
|
384 |
- entry = &record->entries[i]; |
|
385 |
- |
|
386 |
- entry->firstLBA = le32_to_host(entry->firstLBA); |
|
387 |
- entry->numLBA = le32_to_host(entry->numLBA); |
|
388 |
- } |
|
389 |
- record->signature = be16_to_host(record->signature); |
|
390 |
-} |
|
391 |
- |
|
392 | 378 |
static int mbr_check_mbr(struct mbr_boot_record *record, size_t maplen, size_t sectorsize) |
393 | 379 |
{ |
394 | 380 |
unsigned i = 0; |
... | ... |
@@ -44,6 +44,8 @@ |
44 | 44 |
/* MBR Partition Types */ |
45 | 45 |
#define MBR_EMPTY 0x00 |
46 | 46 |
#define MBR_EXTENDED 0x05 |
47 |
+#define MBR_HYBRID 0xed |
|
48 |
+#define MBR_PROTECTIVE 0xee |
|
47 | 49 |
/* End Partition Types */ |
48 | 50 |
|
49 | 51 |
#ifndef HAVE_ATTRIB_PACKED |
... | ... |
@@ -84,5 +86,6 @@ struct mbr_boot_record { |
84 | 84 |
|
85 | 85 |
int cli_mbr_check(const unsigned char *buff, size_t len, size_t maplen); |
86 | 86 |
int cli_scanmbr(cli_ctx *ctx, size_t sectorsize); |
87 |
+void mbr_convert_to_host(struct mbr_boot_record *record); |
|
87 | 88 |
|
88 | 89 |
#endif |