From ff0f02008bdf78a4d9e9ebda7dbd942b9f993670 Mon Sep 17 00:00:00 2001 From: Ann Priestman <apriestman@basistech.com> Date: Thu, 13 Oct 2016 14:27:34 -0400 Subject: [PATCH] Add support for loading secondary GPT --- tsk/vs/gpt.c | 148 ++++++++++++++++++++++++++++++++--------------- tsk/vs/tsk_gpt.h | 5 ++ 2 files changed, 105 insertions(+), 48 deletions(-) diff --git a/tsk/vs/gpt.c b/tsk/vs/gpt.c index 22754c193..d14bd1bb4 100644 --- a/tsk/vs/gpt.c +++ b/tsk/vs/gpt.c @@ -22,7 +22,7 @@ * It is loaded into the internal sorted list */ static uint8_t -gpt_load_table(TSK_VS_INFO * vs) +gpt_load_table(TSK_VS_INFO * vs, GPT_TYPE_ENUM gpt_type) { gpt_head *head; gpt_entry *ent; @@ -32,68 +32,94 @@ gpt_load_table(TSK_VS_INFO * vs) char *safe_str, *head_str, *tab_str, *ent_buf; ssize_t cnt; char *sect_buf; - TSK_DADDR_T taddr = vs->offset / vs->block_size + GPT_PART_SOFFSET; TSK_DADDR_T max_addr = (vs->img_info->size - vs->offset) / vs->block_size; // max sector + TSK_DADDR_T gpt_relative_addr; + TSK_DADDR_T gpt_absolute_addr; + TSK_DADDR_T dos_sect_relative_addr; + TSK_DADDR_T dos_sect_absolute_addr; + + if(gpt_type == PRIMARY_TABLE){ + dos_sect_relative_addr = GPT_PART_SOFFSET; + dos_sect_absolute_addr = vs->offset / vs->block_size + GPT_PART_SOFFSET; + gpt_relative_addr = GPT_PART_SOFFSET + 1; + gpt_absolute_addr = vs->offset / vs->block_size + GPT_PART_SOFFSET + 1; + } else { + gpt_relative_addr = ((vs->img_info->size - vs->offset) / vs->block_size) - 1; + gpt_absolute_addr = (vs->img_info->size / vs->block_size) - 1; + } + if (tsk_verbose) tsk_fprintf(stderr, "gpt_load_table: Sector: %" PRIuDADDR "\n", - taddr); + gpt_absolute_addr); if ((sect_buf = tsk_malloc(vs->block_size)) == NULL) return 1; - dos_part = (dos_sect *) sect_buf; - cnt = tsk_vs_read_block - (vs, GPT_PART_SOFFSET, sect_buf, vs->block_size); - /* if -1, then tsk_errno is already set */ - if (cnt != vs->block_size) { - if (cnt >= 0) { - tsk_error_reset(); - tsk_error_set_errno(TSK_ERR_VS_READ); + if(gpt_type == PRIMARY_TABLE){ + dos_part = (dos_sect *) sect_buf; + + cnt = tsk_vs_read_block + (vs, dos_sect_relative_addr, sect_buf, vs->block_size); + /* if -1, then tsk_errno is already set */ + if (cnt != vs->block_size) { + if (cnt >= 0) { + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_VS_READ); + } + tsk_error_set_errstr2 + ("Error reading DOS safety partition table in Sector: %" + PRIuDADDR, dos_sect_absolute_addr); + free(sect_buf); + return 1; } - tsk_error_set_errstr2 - ("Error reading DOS safety partition table in Sector: %" - PRIuDADDR, taddr); - free(sect_buf); - return 1; - } - /* Sanity Check */ - if (tsk_vs_guessu16(vs, dos_part->magic, DOS_MAGIC)) { - tsk_error_reset(); - tsk_error_set_errno(TSK_ERR_VS_MAGIC); - tsk_error_set_errstr - ("Missing DOS safety partition (invalid magic) (Sector: %" - PRIuDADDR ")", taddr); - free(sect_buf); - return 1; - } + /* Sanity Check */ + if (tsk_vs_guessu16(vs, dos_part->magic, DOS_MAGIC)) { + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_VS_MAGIC); + tsk_error_set_errstr + ("Missing DOS safety partition (invalid magic) (Sector: %" + PRIuDADDR ")", dos_sect_absolute_addr); + free(sect_buf); + return 1; + } - if (dos_part->ptable[0].ptype != GPT_DOS_TYPE) { - tsk_error_reset(); - tsk_error_set_errno(TSK_ERR_VS_MAGIC); - tsk_error_set_errstr - ("Missing DOS safety partition (invalid type in table: %d)", - dos_part->ptable[0].ptype); - free(sect_buf); - return 1; + if (dos_part->ptable[0].ptype != GPT_DOS_TYPE) { + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_VS_MAGIC); + tsk_error_set_errstr + ("Missing DOS safety partition (invalid type in table: %d)", + dos_part->ptable[0].ptype); + free(sect_buf); + return 1; + } } /* Read the GPT header */ head = (gpt_head *) sect_buf; cnt = tsk_vs_read_block - (vs, GPT_PART_SOFFSET + 1, sect_buf, vs->block_size); + (vs, gpt_relative_addr, sect_buf, vs->block_size); if (cnt != vs->block_size) { if (cnt >= 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_READ); } tsk_error_set_errstr2("GPT Header structure in Sector: %" - PRIuDADDR, taddr + 1); + PRIuDADDR, gpt_absolute_addr); free(sect_buf); return 1; } + /* Do the endianness test for the secondary table since the test in the dos safety table was skipped */ + if(gpt_type == SECONDARY_TABLE){ + if(tsk_getu64(TSK_BIG_ENDIAN, head->head_lba) == gpt_relative_addr){ + vs->endian = TSK_BIG_ENDIAN; + } else { + vs->endian = TSK_LIT_ENDIAN; + } + } + if (tsk_getu64(vs->endian, &head->signature) != GPT_HEAD_SIG) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_MAGIC); @@ -109,21 +135,22 @@ gpt_load_table(TSK_VS_INFO * vs) return 1; } - snprintf(safe_str, 16, "Safety Table"); - if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) 0, (TSK_DADDR_T) 1, - TSK_VS_PART_FLAG_META, safe_str, -1, -1)) { - free(sect_buf); - return 1; + if(gpt_type == PRIMARY_TABLE){ + snprintf(safe_str, 16, "Safety Table"); + if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) 0, (TSK_DADDR_T) 1, + TSK_VS_PART_FLAG_META, safe_str, -1, -1)) { + free(sect_buf); + return 1; + } } - if ((head_str = tsk_malloc(16)) == NULL) { free(sect_buf); return 1; } snprintf(head_str, 16, "GPT Header"); - if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) 1, + if (NULL == tsk_vs_part_add(vs, gpt_relative_addr, (TSK_DADDR_T) ((tsk_getu32(vs->endian, &head->head_size_b) + (vs->block_size - 1)) / vs->block_size), TSK_VS_PART_FLAG_META, @@ -303,7 +330,7 @@ tsk_vs_gpt_open(TSK_IMG_INFO * img_info, TSK_DADDR_T offset) vs->close = gpt_close; /* Load the partitions into the sorted list */ - if (gpt_load_table(vs)) { + if (gpt_load_table(vs, PRIMARY_TABLE)) { int found = 0; if (tsk_verbose) tsk_fprintf(stderr, "gpt_open: Trying other sector sizes\n"); @@ -315,7 +342,7 @@ tsk_vs_gpt_open(TSK_IMG_INFO * img_info, TSK_DADDR_T offset) tsk_fprintf(stderr, "gpt_open: Trying sector size: %d\n", vs->block_size); - if (gpt_load_table(vs)) { + if (gpt_load_table(vs, PRIMARY_TABLE)) { vs->block_size *= 2; continue; } @@ -324,8 +351,33 @@ tsk_vs_gpt_open(TSK_IMG_INFO * img_info, TSK_DADDR_T offset) } if (found == 0) { - gpt_close(vs); - return NULL; + /* Look for the secondary GPT at the end of the image */ + if (tsk_verbose) + tsk_fprintf(stderr, "gpt_open: Trying secondary table\n"); + vs->block_size = img_info->sector_size; + if(gpt_load_table(vs, SECONDARY_TABLE)){ + + /* Try other sector sizes again */ + vs->block_size = 512; + while (vs->block_size <= 8192) { + if (tsk_verbose) + tsk_fprintf(stderr, "gpt_open: Trying secondary table sector size: %d\n", + vs->block_size); + + if (gpt_load_table(vs, SECONDARY_TABLE)) { + vs->block_size *= 2; + continue; + } + found = 1; + break; + } + + if(found == 0){ + gpt_close(vs); + return NULL; + } + } + } } diff --git a/tsk/vs/tsk_gpt.h b/tsk/vs/tsk_gpt.h index b265bcc2b..d74a4fef4 100644 --- a/tsk/vs/tsk_gpt.h +++ b/tsk/vs/tsk_gpt.h @@ -57,6 +57,11 @@ extern "C" { uint8_t name[72]; /* name in unicode */ } gpt_entry; + typedef enum { + PRIMARY_TABLE, + SECONDARY_TABLE, + } GPT_TYPE_ENUM; + #ifdef __cplusplus } -- GitLab