Browse code

gpt: reorganized parsing functions gpt: scan secondary header partitions if differ gpt: added/moved checks, minor renaming gpt: minor debugging message changes

Kevin Lin authored on 2014/02/07 08:50:41
Showing 2 changed files
... ...
@@ -34,6 +34,7 @@
34 34
 #include "cltypes.h"
35 35
 #include "others.h"
36 36
 #include "gpt.h"
37
+#include "prtn_intxn.h"
37 38
 #include "scanners.h"
38 39
 
39 40
 //#define DEBUG_GPT_PARSE
... ...
@@ -51,68 +52,259 @@
51 51
 #  define gpt_printmsg(...) ;
52 52
 #endif
53 53
 
54
-static void gpt_printSectors(cli_ctx *ctx, size_t sectorsize)
54
+enum GPT_SCANSTATE {
55
+    INVALID,
56
+    PRIMARY_ONLY,
57
+    SECONDARY_ONLY,
58
+    BOTH
59
+};
60
+
61
+static int gpt_scan_partitions(cli_ctx *ctx, struct gpt_header hdr, size_t sectorsize);
62
+static int gpt_validate_header(cli_ctx *ctx, struct gpt_header hdr, size_t sectorsize);
63
+static void gpt_printSectors(cli_ctx *ctx, size_t sectorsize);
64
+static void gpt_printName(uint16_t name[], const char* msg);
65
+static void gpt_printGUID(uint8_t GUID[], const char* msg);
66
+static int gpt_prtn_intxn(cli_ctx *ctx, struct gpt_header hdr, size_t sectorsize);
67
+
68
+int cli_scangpt(cli_ctx *ctx)
55 69
 {
56
-#ifdef DEBUG_GPT_PARSE
57 70
     struct gpt_header phdr, shdr;
58
-    off_t ppos = 0, spos = 0;
59
-    size_t pptable_len, sptable_len, maplen;
60
-    uint64_t ptableLastLBA, stableLastLBA;
71
+    enum GPT_SCANSTATE state = INVALID;
72
+    int ret = 0;
73
+    size_t sectorsize, maplen;
74
+    off_t pos = 0;
61 75
 
62
-    /* sector size may need to be calculated */
63
-    sectorsize = GPT_SECTOR_SIZE;
76
+    gpt_parsemsg("The beginning of something big: GPT parsing\n");
64 77
 
78
+    if (!ctx || !ctx->fmap) {
79
+        cli_errmsg("cli_scangpt: Invalid context\n");
80
+        return CL_ENULLARG;
81
+    }
82
+
83
+    /* sector size calculatation */
84
+    sectorsize = GPT_DEFAULT_SECTOR_SIZE;
85
+
86
+    /* size of total file must be a multiple of the sector size */
65 87
     maplen = (*ctx->fmap)->real_len;
88
+    if ((maplen % sectorsize) != 0) {
89
+        cli_dbgmsg("cli_scangpt: File sized %u is not a multiple of sector size %u\n",
90
+                   maplen, sectorsize);
91
+        return CL_EFORMAT;
92
+    }
66 93
 
67
-    ppos = 1 * sectorsize; /* sector 1 (second sector) is the primary gpt header */
68
-    spos = maplen - sectorsize; /* last sector is the secondary gpt header */
94
+    pos = GPT_PRIMARY_HDR_LBA * sectorsize; /* sector 1 (second sector) is the primary gpt header */
69 95
 
70
-    /* read in the primary and secondary gpt headers */
71
-    if (fmap_readn(*ctx->fmap, &phdr, ppos, sizeof(phdr)) != sizeof(phdr)) {
96
+    /* read primary gpt header */
97
+    cli_dbgmsg("cli_scangpt: Using primary GPT header\n");
98
+    if (fmap_readn(*ctx->fmap, &phdr, pos, sizeof(phdr)) != sizeof(phdr)) {
72 99
         cli_dbgmsg("cli_scangpt: Invalid primary GPT header\n");
73
-        return;
100
+        return CL_EFORMAT;
74 101
     }
75
-    if (fmap_readn(*ctx->fmap, &shdr, spos, sizeof(shdr)) != sizeof(shdr)) {
76
-        cli_dbgmsg("cli_scangpt: Invalid secondary GPT header\n");
77
-        return;
102
+
103
+    pos = maplen - sectorsize; /* last sector is the secondary gpt header */
104
+
105
+    if (gpt_validate_header(ctx, phdr, sectorsize)) {
106
+        cli_dbgmsg("cli_scangpt: Primary GPT header is invalid\n");
107
+        cli_dbgmsg("cli_scangpt: Using secondary GPT header\n");
108
+
109
+        state = SECONDARY_ONLY;
110
+
111
+        /* read secondary gpt header */
112
+        if (fmap_readn(*ctx->fmap, &shdr, pos, sizeof(shdr)) != sizeof(shdr)) {
113
+            cli_dbgmsg("cli_scangpt: Invalid secondary GPT header\n");
114
+            return CL_EFORMAT;
115
+        }
116
+
117
+        if (gpt_validate_header(ctx, shdr, sectorsize)) {
118
+            cli_dbgmsg("cli_scangpt: Secondary GPT header is invalid\n");
119
+            cli_dbgmsg("cli_scangpt: Disk is unusable\n");
120
+            return CL_EFORMAT;
121
+        }
78 122
     }
123
+    else {
124
+        cli_dbgmsg("cli_scangpt: Checking secondary GPT header\n");
79 125
 
80
-    pptable_len = phdr.tableNumEntries * phdr.tableEntrySize;
81
-    sptable_len = shdr.tableNumEntries * shdr.tableEntrySize;
82
-    ptableLastLBA = (phdr.tableStartLBA + (pptable_len / sectorsize)) - 1;
83
-    stableLastLBA = (shdr.tableStartLBA + (sptable_len / sectorsize)) - 1;
126
+        state = PRIMARY_ONLY;
84 127
 
85
-    gpt_parsemsg("0: MBR\n");
86
-    gpt_parsemsg("%llu: Primary GPT Header\n", phdr.currentLBA);
87
-    gpt_parsemsg("%llu-%llu: Primary GPT Partition Table\n", phdr.tableStartLBA, ptableLastLBA);
88
-    gpt_parsemsg("%llu-%llu: Usuable LBAs\n", phdr.firstUsableLBA, phdr.lastUsableLBA);
89
-    gpt_parsemsg("%llu-%llu: Secondary GPT Partition Table\n", shdr.tableStartLBA, stableLastLBA);
90
-    gpt_parsemsg("%llu: Secondary GPT Header\n", phdr.backupLBA);
91
-#else
92
-    return;
93
-#endif
128
+        /* check validity of secondary header; still using the primary */
129
+        if (fmap_readn(*ctx->fmap, &shdr, pos, sizeof(shdr)) != sizeof(shdr)) {
130
+            cli_dbgmsg("cli_scangpt: Invalid secondary GPT header\n");
131
+        }
132
+        else if (gpt_validate_header(ctx, shdr, sectorsize)) {
133
+            cli_dbgmsg("cli_scangpt: Secondary GPT header is invalid\n");
134
+        }
135
+        /* check that the two partition table crc32 checksum match, 
136
+         * may want a different hashing function */
137
+        else if (phdr.tableCRC32 != shdr.tableCRC32){
138
+            cli_dbgmsg("cli_scangpt: Primary and secondary GPT header table CRC32 differ\n");
139
+            cli_dbgmsg("cli_scangpt: Set to scan primary and secondary partition tables\n");
140
+
141
+            state = BOTH;
142
+        }
143
+        else {
144
+            cli_dbgmsg("cli_scangpt: Secondary GPT header check OK\n");
145
+        }
146
+    }
147
+
148
+    /* check that the partition table has no intersections - HEURISTICS */
149
+    if (ctx->options & CL_SCAN_PARTITION_INTXN) {
150
+        ret = gpt_prtn_intxn(ctx, phdr, sectorsize);
151
+        if ((ret != CL_CLEAN) &&
152
+            !((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))) {
153
+            
154
+            return ret;
155
+        }
156
+        ret = gpt_prtn_intxn(ctx, shdr, sectorsize);
157
+        if ((ret != CL_CLEAN) &&
158
+            !((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))) {
159
+            
160
+            return ret;
161
+        }
162
+    }
163
+
164
+    /* scanning partitions */
165
+    switch (state) {
166
+    case PRIMARY_ONLY:
167
+        cli_dbgmsg("cli_scangpt: Scanning primary GPT partitions only\n");
168
+        ret = gpt_scan_partitions(ctx, phdr, sectorsize);
169
+        if ((ret != CL_CLEAN) && 
170
+            !((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))) {
171
+                break;
172
+        }
173
+        break;
174
+    case SECONDARY_ONLY:
175
+        cli_dbgmsg("cli_scangpt: Scanning secondary GPT partitions only\n");
176
+        ret = gpt_scan_partitions(ctx, shdr, sectorsize);
177
+        if ((ret != CL_CLEAN) && 
178
+            !((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))) {
179
+                break;
180
+        }
181
+        break;
182
+    case BOTH:
183
+        cli_dbgmsg("cli_scangpt: Scanning primary GPT partitions\n");
184
+        ret = gpt_scan_partitions(ctx, phdr, sectorsize);
185
+        if ((ret != CL_CLEAN) &&
186
+            !((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))) {
187
+                break;
188
+        }
189
+        cli_dbgmsg("cli_scangpt: Scanning secondary GPT partitions\n");
190
+        ret = gpt_scan_partitions(ctx, shdr, sectorsize);
191
+        if ((ret != CL_CLEAN) &&
192
+            !((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))) {
193
+                break;
194
+        }
195
+        break;
196
+    default:
197
+        cli_dbgmsg("cli_scangpt: State is invalid\n");
198
+    }
199
+
200
+    return ret;
94 201
 }
95 202
 
96
-static void gpt_printGUID(uint8_t GUID[], const char* msg)
203
+static int gpt_scan_partitions(cli_ctx *ctx, struct gpt_header hdr, size_t sectorsize)
97 204
 {
98
-    unsigned i;
99
-    char hexstr[64], tmpstr[64];
205
+    struct gpt_partition_entry gpe;
206
+    int ret = 0;
207
+    size_t maplen, part_size = 0;
208
+    off_t pos = 0, part_off = 0;
209
+    unsigned i = 0, j = 0;
210
+    uint32_t max_prtns = 0;
100 211
 
101
-    hexstr[0] = '\0';
102
-    tmpstr[0] = '\0';
103
-    for (i = 0; i < 16; ++i) {
104
-        gpt_printmsg("%x\n", GUID[i]);
105
-        if (i == 3 || i == 5 || i == 7 || i == 9) {
106
-            snprintf(hexstr, 64, "%s%02x-", tmpstr, GUID[i]);
107
-            gpt_printmsg("%s\n", hexstr);
212
+    /* convert endian to host */
213
+    hdr.signature = be64_to_host(hdr.signature);
214
+    hdr.revision = be32_to_host(hdr.revision);
215
+    hdr.headerSize = le32_to_host(hdr.headerSize);
216
+    hdr.headerCRC32 = le32_to_host(hdr.headerCRC32);
217
+    hdr.reserved = le32_to_host(hdr.reserved);
218
+    hdr.currentLBA = le64_to_host(hdr.currentLBA);
219
+    hdr.backupLBA = le64_to_host(hdr.backupLBA);
220
+    hdr.firstUsableLBA = le64_to_host(hdr.firstUsableLBA);
221
+    hdr.lastUsableLBA = le64_to_host(hdr.lastUsableLBA);
222
+    hdr.tableStartLBA = le64_to_host(hdr.tableStartLBA);
223
+    hdr.tableNumEntries = le32_to_host(hdr.tableNumEntries);
224
+    hdr.tableEntrySize = le32_to_host(hdr.tableEntrySize);
225
+    hdr.tableCRC32 = le32_to_host(hdr.tableCRC32);
226
+
227
+    /* print header info for the debug */
228
+    cli_dbgmsg("GPT Header:\n");
229
+    cli_dbgmsg("Signature: 0x%llx\n", hdr.signature);
230
+    cli_dbgmsg("Revision: %x\n", hdr.revision);
231
+    gpt_printGUID(hdr.DiskGUID, "DISK GUID");
232
+    cli_dbgmsg("Partition Entry Count: %u\n", hdr.tableNumEntries);
233
+    cli_dbgmsg("Partition Entry Size: %u\n", hdr.tableEntrySize);
234
+
235
+    maplen = (*ctx->fmap)->real_len;
236
+
237
+    /* check engine maxpartitions limit */
238
+    if (hdr.tableNumEntries < ctx->engine->maxpartitions) {
239
+        max_prtns = hdr.tableNumEntries;
240
+    }
241
+    else {
242
+        max_prtns = ctx->engine->maxpartitions;
243
+    }
244
+
245
+    /* use the partition tables to pass partitions to cli_map_scan */
246
+    pos = hdr.tableStartLBA * sectorsize;
247
+    for (i = 0; i < max_prtns; ++i) {
248
+        /* read in partition entry */
249
+        if (fmap_readn(*ctx->fmap, &gpe, pos, sizeof(gpe)) != sizeof(gpe)) {
250
+            cli_dbgmsg("cli_scangpt: Invalid GPT partition entry\n");
251
+            return CL_EFORMAT;
252
+        }
253
+
254
+        /* convert the endian to host */
255
+        gpe.firstLBA = le64_to_host(gpe.firstLBA);
256
+        gpe.lastLBA = le64_to_host(gpe.lastLBA);
257
+        gpe.attributes = le64_to_host(gpe.attributes);
258
+        for (j = 0; j < 36; ++j) {
259
+            gpe.name[i] = le16_to_host(gpe.name[i]);
260
+        }
261
+
262
+        /* check that partition is not empty and within a valid location */
263
+        if (gpe.firstLBA == 0) {
264
+            /* empty partition, invalid */
265
+        }
266
+        else if ((gpe.firstLBA > gpe.lastLBA) ||
267
+                 (gpe.firstLBA < hdr.firstUsableLBA) || (gpe.lastLBA > hdr.lastUsableLBA)) {
268
+            cli_dbgmsg("cli_scangpt: GPT partition exists outside specified bounds\n");
269
+            gpt_parsemsg("%llu < %llu, %llu > %llu\n", gpe.firstLBA, hdr.firstUsableLBA,
270
+                         gpe.lastLBA, hdr.lastUsableLBA);
271
+            /* partition exists outside bounds specified by header or invalid */
272
+        }
273
+        else if (((gpe.lastLBA+1) * sectorsize) > maplen) {
274
+            /* partition exists outside bounds of the file map */
108 275
         }
109 276
         else {
110
-            snprintf(hexstr, 64, "%s%02x", tmpstr, GUID[i]);
111
-            gpt_printmsg("%s\n", hexstr);
277
+            /* print partition entry data for debug */
278
+            cli_dbgmsg("GPT Partition Entry %u:\n", i);
279
+            gpt_printName(gpe.name, "Name");
280
+            gpt_printGUID(gpe.typeGUID, "Type GUID");
281
+            gpt_printGUID(gpe.uniqueGUID, "Unique GUID");
282
+            cli_dbgmsg("Attributes: %llx\n", gpe.attributes);
283
+            cli_dbgmsg("Blocks: [%llu(%llu) -> %llu(%llu)]\n",
284
+                       gpe.firstLBA, (gpe.firstLBA * sectorsize), 
285
+                       gpe.lastLBA, ((gpe.lastLBA+1) * sectorsize));
286
+
287
+            /* send the partition to cli_map_scan */
288
+            part_off = gpe.firstLBA * sectorsize;
289
+            part_size = (gpe.lastLBA - gpe.firstLBA + 1) * sectorsize;
290
+            ret = cli_map_scan(*ctx->fmap, part_off, part_size, ctx, CL_TYPE_PART_ANY);
291
+            if ((ret != CL_CLEAN) &&
292
+                !((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))) {
293
+                    //gpt_printName(gpe.name, "Detection in Partition");
294
+                    return ret;
295
+            }
112 296
         }
113
-        strncpy(tmpstr, hexstr, 64);
297
+
298
+        /* increment the offsets to next partition entry */
299
+        pos += hdr.tableEntrySize;
114 300
     }
115
-    cli_dbgmsg("%s: %s\n", msg, hexstr);
301
+
302
+    if (i < hdr.tableNumEntries) {
303
+        cli_dbgmsg("cli_scangpt: max partitions exceeded\n");
304
+    }
305
+
306
+    return ret;
116 307
 }
117 308
 
118 309
 static int gpt_validate_header(cli_ctx *ctx, struct gpt_header hdr, size_t sectorsize)
... ...
@@ -125,20 +317,20 @@ static int gpt_validate_header(cli_ctx *ctx, struct gpt_header hdr, size_t secto
125 125
     maplen = (*ctx->fmap)->real_len;
126 126
 
127 127
     /* checking header crc32 checksum */
128
-    crc32_ref = hdr.headerCRC32;
128
+    crc32_ref = le32_to_host(hdr.headerCRC32);
129 129
     hdr.headerCRC32 = 0; /* checksum is calculated with field = 0 */
130 130
     crc32_calc = crc32(0, (unsigned char*)&hdr, sizeof(hdr));
131 131
     if (crc32_calc != crc32_ref) {
132 132
         cli_dbgmsg("cli_scangpt: GPT header checksum mismatch\n");
133 133
         gpt_parsemsg("%x != %x\n", crc32_calc, crc32_ref);
134
-        return -1;
134
+        return CL_EFORMAT;
135 135
     }
136 136
 
137 137
     /* convert endian to host to check partition table */
138 138
     hdr.signature = be64_to_host(hdr.signature);
139 139
     hdr.revision = be32_to_host(hdr.revision);
140 140
     hdr.headerSize = le32_to_host(hdr.headerSize);
141
-    hdr.headerCRC32 = le32_to_host(hdr.headerCRC32);
141
+    hdr.headerCRC32 = crc32_ref;
142 142
     hdr.reserved = le32_to_host(hdr.reserved);
143 143
     hdr.currentLBA = le64_to_host(hdr.currentLBA);
144 144
     hdr.backupLBA = le64_to_host(hdr.backupLBA);
... ...
@@ -147,7 +339,7 @@ static int gpt_validate_header(cli_ctx *ctx, struct gpt_header hdr, size_t secto
147 147
     hdr.tableStartLBA = le64_to_host(hdr.tableStartLBA);
148 148
     hdr.tableNumEntries = le32_to_host(hdr.tableNumEntries);
149 149
     hdr.tableEntrySize = le32_to_host(hdr.tableEntrySize);
150
-    hdr.tableCRC32 = le32_to_host(hdr.tableCRC32);
150
+    hdr.tableCRC32 = le32_to_host(hdr.tableCRC32);;
151 151
 
152 152
     ptable_start = hdr.tableStartLBA * sectorsize;
153 153
     ptable_len = hdr.tableNumEntries * hdr.tableEntrySize;
... ...
@@ -161,49 +353,57 @@ static int gpt_validate_header(cli_ctx *ctx, struct gpt_header hdr, size_t secto
161 161
     if (hdr.signature != GPT_SIGNATURE) {
162 162
         cli_dbgmsg("cli_scangpt: Invalid GPT header signature %llx\n",
163 163
                    hdr.signature);
164
-        return -1;
164
+        return CL_EFORMAT;
165 165
     }
166 166
 
167 167
     /* check header size */
168 168
     if (hdr.headerSize != sizeof(hdr)) {
169 169
         cli_dbgmsg("cli_scangpt: GPT header size does not match stated size\n");
170
-        return -1;
170
+        return CL_EFORMAT;
171 171
     }
172 172
 
173 173
     /* check reserved value == 0 */
174 174
     if (hdr.reserved != GPT_HDR_RESERVED) {
175 175
         cli_dbgmsg("cli_scangpt: GPT header reserved is not expected value\n");
176
-        return -1;
176
+        return CL_EFORMAT;
177 177
     }
178 178
 
179 179
     /* check that sectors are in a valid configuration */
180 180
     if (!((hdr.currentLBA == GPT_PRIMARY_HDR_LBA && hdr.backupLBA == lastLBA) ||
181 181
           (hdr.currentLBA == lastLBA && hdr.backupLBA == GPT_PRIMARY_HDR_LBA))) {
182 182
         cli_dbgmsg("cli_scangpt: GPT secondary header is not last LBA\n");
183
-        return -1;
183
+        return CL_EFORMAT;
184 184
     }
185 185
     if (hdr.firstUsableLBA > hdr.lastUsableLBA) {
186 186
         cli_dbgmsg("cli_scangpt: GPT first usable sectors is after last usable sector\n");
187
-        return -1;
187
+        return CL_EFORMAT;
188 188
     }
189 189
     if (hdr.firstUsableLBA <= GPT_PRIMARY_HDR_LBA || hdr.lastUsableLBA >= lastLBA) {
190 190
         cli_dbgmsg("cli_scangpt: GPT usable sectors intersects header sector\n");
191
-        return -1;
191
+        return CL_EFORMAT;
192 192
     }
193 193
     if ((hdr.tableStartLBA <= hdr.firstUsableLBA && tableLastLBA >= hdr.firstUsableLBA) ||
194 194
         (hdr.tableStartLBA >= hdr.firstUsableLBA && hdr.tableStartLBA <= hdr.lastUsableLBA)) {
195 195
         cli_dbgmsg("cli_scangpt: GPT usable sectors intersects partition table\n");
196
-        return -1;
196
+        return CL_EFORMAT;
197 197
     }
198 198
     if (hdr.tableStartLBA <= GPT_PRIMARY_HDR_LBA || tableLastLBA >= lastLBA) {
199 199
         cli_dbgmsg("cli_scangpt: GPT partition table intersects header sector\n");
200
-        return -1;
200
+        return CL_EFORMAT;
201 201
     }
202 202
 
203
+    /* check that valid table entry size */
204
+    if (hdr.tableEntrySize != GPT_PARTITION_ENTRY_SIZE) {
205
+        cli_dbgmsg("cli_scangpt: cannot parse gpt with partition entry sized %u\n",
206
+                   hdr.tableEntrySize);
207
+        return CL_EFORMAT;
208
+    }
209
+
210
+
203 211
     /* check valid table */
204 212
     if ((ptable_start + ptable_len) > maplen) {
205 213
         cli_dbgmsg("cli_scangpt: GPT partition table extends over fmap limit\n");
206
-        return -1;
214
+        return CL_EFORMAT;
207 215
     }
208 216
 
209 217
     /** END HEADER CHECKS **/
... ...
@@ -214,152 +414,155 @@ static int gpt_validate_header(cli_ctx *ctx, struct gpt_header hdr, size_t secto
214 214
     if (crc32_calc != hdr.tableCRC32) {
215 215
         cli_dbgmsg("cli_scangpt: GPT partition table checksum mismatch\n");
216 216
         gpt_parsemsg("%x != %x\n", crc32_calc, hdr.tableCRC32);
217
-        return -1;
217
+        return CL_EFORMAT;
218 218
     }
219 219
 
220
-    return 0;
220
+    return CL_SUCCESS;
221 221
 }
222 222
 
223
-int cli_scangpt(cli_ctx *ctx)
223
+static void gpt_printSectors(cli_ctx *ctx, size_t sectorsize)
224 224
 {
225
-    struct gpt_header hdr, chdr;
226
-    struct gpt_partition_entry gpe;
227
-    int ret = 0, func_ret = 0;
228
-    size_t sectorsize, maplen, part_size;
229
-    off_t pos = 0, part_off = 0;
230
-    unsigned i = 0;
231
-
232
-    gpt_parsemsg("The beginning of something big: GPT parsing\n");
233
-
234
-    if (!ctx || !ctx->fmap) {
235
-        cli_errmsg("cli_scangpt: Invalid context\n");
236
-        return CL_ENULLARG;
237
-    }
225
+#ifdef DEBUG_GPT_PARSE
226
+    struct gpt_header phdr, shdr;
227
+    off_t ppos = 0, spos = 0;
228
+    size_t pptable_len, sptable_len, maplen;
229
+    uint64_t ptableLastLBA, stableLastLBA;
238 230
 
239
-    /* sector size may need to be calculated */
240
-    sectorsize = GPT_SECTOR_SIZE;
231
+    /* sector size calculation */
232
+    sectorsize = GPT_DEFAULT_SECTOR_SIZE;
241 233
 
242
-    /* size of total file must be a multiple of the sector size */
243 234
     maplen = (*ctx->fmap)->real_len;
244
-    if ((maplen % sectorsize) != 0) {
245
-        cli_dbgmsg("cli_scangpt: File sized %u is not a multiple of sector size %u\n",
246
-                   maplen, sectorsize);
247
-        return CL_EFORMAT;
248
-    }
249 235
 
250
-    pos = GPT_PRIMARY_HDR_LBA * sectorsize; /* sector 1 (second sector) is the primary gpt header */
251
-  
252
-    /* read primary gpt header */
253
-    cli_dbgmsg("cli_scangpt: Using primary GPT header\n");
254
-    if (fmap_readn(*ctx->fmap, &hdr, pos, sizeof(hdr)) != sizeof(hdr)) {
236
+    ppos = 1 * sectorsize; /* sector 1 (second sector) is the primary gpt header */
237
+    spos = maplen - sectorsize; /* last sector is the secondary gpt header */
238
+
239
+    /* read in the primary and secondary gpt headers */
240
+    if (fmap_readn(*ctx->fmap, &phdr, ppos, sizeof(phdr)) != sizeof(phdr)) {
255 241
         cli_dbgmsg("cli_scangpt: Invalid primary GPT header\n");
256
-        return CL_EFORMAT;
242
+        return;
243
+    }
244
+    if (fmap_readn(*ctx->fmap, &shdr, spos, sizeof(shdr)) != sizeof(shdr)) {
245
+        cli_dbgmsg("cli_scangpt: Invalid secondary GPT header\n");
246
+        return;
257 247
     }
258 248
 
259
-    if (gpt_validate_header(ctx, hdr, sectorsize)) {
260
-        cli_dbgmsg("cli_scangpt: Primary GPT header is invalid\n");
261
-        cli_dbgmsg("cli_scangpt: Using secondary GPT header\n");
249
+    pptable_len = phdr.tableNumEntries * phdr.tableEntrySize;
250
+    sptable_len = shdr.tableNumEntries * shdr.tableEntrySize;
251
+    ptableLastLBA = (phdr.tableStartLBA + (pptable_len / sectorsize)) - 1;
252
+    stableLastLBA = (shdr.tableStartLBA + (sptable_len / sectorsize)) - 1;
262 253
 
263
-        pos = maplen - sectorsize; /* last sector is the secondary gpt header */
254
+    gpt_parsemsg("0: MBR\n");
255
+    gpt_parsemsg("%llu: Primary GPT Header\n", phdr.currentLBA);
256
+    gpt_parsemsg("%llu-%llu: Primary GPT Partition Table\n", phdr.tableStartLBA, ptableLastLBA);
257
+    gpt_parsemsg("%llu-%llu: Usuable LBAs\n", phdr.firstUsableLBA, phdr.lastUsableLBA);
258
+    gpt_parsemsg("%llu-%llu: Secondary GPT Partition Table\n", shdr.tableStartLBA, stableLastLBA);
259
+    gpt_parsemsg("%llu: Secondary GPT Header\n", phdr.backupLBA);
260
+#else
261
+    return;
262
+#endif
263
+}
264 264
 
265
-        /* read secondary gpt header */
266
-        if (fmap_readn(*ctx->fmap, &hdr, pos, sizeof(hdr)) != sizeof(hdr)) {
267
-            cli_dbgmsg("cli_scangpt: Invalid secondary GPT header\n");
268
-            return CL_EFORMAT;
269
-        }
265
+static void gpt_printName(uint16_t name[], const char* msg)
266
+{
267
+    char *namestr;
270 268
 
271
-        if (gpt_validate_header(ctx, hdr, sectorsize)) {
272
-            cli_dbgmsg("cli_scangpt: Secondary GPT header is invalid\n");
273
-            cli_dbgmsg("cli_scangpt: Disk is unusable\n");
274
-            return CL_EFORMAT;
275
-        }
276
-    }
277
-    else {
278
-        /* check validity of secondary header; still using the primary */
279
-        if (fmap_readn(*ctx->fmap, &chdr, pos, sizeof(chdr)) != sizeof(chdr)) {
280
-            cli_dbgmsg("cli_scangpt: Invalid secondary GPT header\n");
269
+    namestr = (char*)cli_utf16toascii((char*)name, 72);
270
+    cli_dbgmsg("%s: %s\n", msg, namestr);
271
+
272
+    free(namestr);
273
+}
274
+
275
+static void gpt_printGUID(uint8_t GUID[], const char* msg)
276
+{
277
+    unsigned i;
278
+    char hexstr[64], tmpstr[64];
279
+
280
+    hexstr[0] = '\0';
281
+    tmpstr[0] = '\0';
282
+    for (i = 0; i < 16; ++i) {
283
+        gpt_printmsg("%x\n", GUID[i]);
284
+        if (i == 3 || i == 5 || i == 7 || i == 9) {
285
+            snprintf(hexstr, 64, "%s%02x-", tmpstr, GUID[i]);
286
+            gpt_printmsg("%s\n", hexstr);
281 287
         }
282
-        else  if (gpt_validate_header(ctx, chdr, sectorsize)) {
283
-            cli_dbgmsg("cli_scangpt: Secondary GPT header is invalid\n");
288
+        else {
289
+            snprintf(hexstr, 64, "%s%02x", tmpstr, GUID[i]);
290
+            gpt_printmsg("%s\n", hexstr);
284 291
         }
292
+        strncpy(tmpstr, hexstr, 64);
285 293
     }
294
+    cli_dbgmsg("%s: %s\n", msg, hexstr);
295
+}
286 296
 
287
-    /* convert endian to host */
288
-    hdr.signature = be64_to_host(hdr.signature);
289
-    hdr.revision = be32_to_host(hdr.revision);
290
-    hdr.headerSize = le32_to_host(hdr.headerSize);
291
-    hdr.headerCRC32 = le32_to_host(hdr.headerCRC32);
292
-    hdr.reserved = le32_to_host(hdr.reserved);
293
-    hdr.currentLBA = le64_to_host(hdr.currentLBA);
294
-    hdr.backupLBA = le64_to_host(hdr.backupLBA);
295
-    hdr.firstUsableLBA = le64_to_host(hdr.firstUsableLBA);
296
-    hdr.lastUsableLBA = le64_to_host(hdr.lastUsableLBA);
297
+static int gpt_prtn_intxn(cli_ctx *ctx, struct gpt_header hdr, size_t sectorsize)
298
+{
299
+    prtn_intxn_list_t prtncheck;
300
+    struct gpt_partition_entry gpe;
301
+    unsigned i, pitxn;
302
+    int ret = 0, tmp = 0;
303
+    off_t pos;
304
+    size_t maplen;
305
+    uint32_t max_prtns = 0;
306
+
307
+    maplen = (*ctx->fmap)->real_len;
308
+
309
+    /* convert endian to host to check partition table */
297 310
     hdr.tableStartLBA = le64_to_host(hdr.tableStartLBA);
298 311
     hdr.tableNumEntries = le32_to_host(hdr.tableNumEntries);
299
-    hdr.tableEntrySize = le32_to_host(hdr.tableEntrySize);
300
-    hdr.tableCRC32 = le32_to_host(hdr.tableCRC32);
301 312
 
302
-    /* print header info for the debug */
303
-    cli_dbgmsg("GPT Header:\n");
304
-    cli_dbgmsg("Signature: 0x%llx\n", hdr.signature);
305
-    cli_dbgmsg("Revision: %x\n", hdr.revision);
306
-    gpt_printGUID(hdr.DiskGUID, "DISK GUID");
307
-    cli_dbgmsg("Partition Entry Count: %u\n", hdr.tableNumEntries);
308
-    cli_dbgmsg("Partition Entry Size: %u\n", hdr.tableEntrySize);
313
+    prtn_intxn_list_init(&prtncheck);    
309 314
 
310
-    /* check that all partition table parameters are expected values */
311
-    if (hdr.tableEntrySize != GPT_PARTITION_ENTRY_SIZE) {
312
-        cli_dbgmsg("cli_scangpt: cannot parse gpt with partition entry sized %u\n",
313
-                   hdr.tableEntrySize);
314
-        return CL_EFORMAT;
315
+    /* check engine maxpartitions limit */
316
+    if (hdr.tableNumEntries < ctx->engine->maxpartitions) {
317
+        max_prtns = hdr.tableNumEntries;
318
+    }
319
+    else {
320
+        max_prtns = ctx->engine->maxpartitions;
315 321
     }
316 322
 
317
-    /* use the partition tables to pass partitions to cli_map_scan */
318 323
     pos = hdr.tableStartLBA * sectorsize;
319
-    for (i = 0; i < hdr.tableNumEntries; ++i) {
324
+    for (i = 0; i < max_prtns; ++i) {
320 325
         /* read in partition entry */
321 326
         if (fmap_readn(*ctx->fmap, &gpe, pos, sizeof(gpe)) != sizeof(gpe)) {
322
-            cli_dbgmsg("cli_scangpt: Invalid secondary GPT partition entry\n");
327
+            cli_dbgmsg("cli_scangpt: Invalid GPT partition entry\n");
328
+            prtn_intxn_list_free(&prtncheck);
323 329
             return CL_EFORMAT;
324 330
         }
325 331
 
326 332
         /* convert the endian to host */
327 333
         gpe.firstLBA = le64_to_host(gpe.firstLBA);
328 334
         gpe.lastLBA = le64_to_host(gpe.lastLBA);
329
-        gpe.attributes = le64_to_host(gpe.attributes);
330 335
 
331
-        /* check that partition is not empty and within a valid location */
332 336
         if (gpe.firstLBA == 0) {
333
-            /* empty partition, valid */
337
+            /* empty partition, invalid */
334 338
         }
335 339
         else if ((gpe.firstLBA > gpe.lastLBA) ||
336 340
                  (gpe.firstLBA < hdr.firstUsableLBA) || (gpe.lastLBA > hdr.lastUsableLBA)) {
337 341
             /* partition exists outside bounds specified by header or invalid */
338
-            /* see what a mac does in this situation */
339
-            cli_dbgmsg("cli_scangpt: GPT partition exists outside specified bounds\n");
340
-            gpt_parsemsg("%llu < %llu, %llu > %llu\n", gpe.firstLBA, hdr.firstUsableLBA,
341
-                         gpe.lastLBA, hdr.lastUsableLBA);
342
-            return CL_EFORMAT;
342
+        }
343
+        else if (((gpe.lastLBA+1) * sectorsize) > maplen) {
344
+            /* partition exists outside bounds of the file map */
343 345
         }
344 346
         else {
345
-            /* print partition entry data for debug */
346
-            cli_dbgmsg("GPT Partition Entry %u:\n", i);
347
-            gpt_printGUID(gpe.typeGUID, "Type GUID");
348
-            gpt_printGUID(gpe.uniqueGUID, "Unique GUID");
349
-            cli_dbgmsg("Attributes: %llx\n", gpe.attributes);
350
-            /* printing this name is worrisome, disabling */
351
-            //cli_dbgmsg("Name: %s\n", (char*)gpe.name);
352
-
353
-            /* send the partition to cli_map_scan */
354
-            part_off = gpe.firstLBA * sectorsize;
355
-            part_size = (gpe.lastLBA - gpe.firstLBA + 1) * sectorsize;
356
-            ret = cli_map_scan(*ctx->fmap, part_off, part_size, ctx, CL_TYPE_PART_ANY);
357
-            if (ret != CL_CLEAN) {
358
-                if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS)) {
359
-                    func_ret = ret;
347
+            tmp = prtn_intxn_list_check(&prtncheck, &pitxn, gpe.firstLBA, gpe.lastLBA - gpe.firstLBA + 1);
348
+            if (tmp != CL_CLEAN) {
349
+                if ((ctx->options & CL_SCAN_ALLMATCHES) && (tmp == CL_VIRUS)) {
350
+                    cli_dbgmsg("cli_scangpt: detected intersection with partitions "
351
+                               "[%u, %u]\n", pitxn, i);
352
+                    cli_append_virus(ctx, "Heuristic.PartitionIntersection");
353
+                    ret = tmp;
354
+                    tmp = 0;
355
+                }
356
+                else if (tmp == CL_VIRUS) {
357
+                    cli_dbgmsg("cli_scangpt: detected intersection with partitions "
358
+                               "[%u, %u]\n", pitxn, i);
359
+                    cli_append_virus(ctx, "Heuristic.PartitionIntersection");
360
+                    prtn_intxn_list_free(&prtncheck);
361
+                    return CL_VIRUS;
360 362
                 }
361 363
                 else {
362
-                    return ret;
364
+                    prtn_intxn_list_free(&prtncheck);
365
+                    return tmp;
363 366
                 }
364 367
             }
365 368
         }
... ...
@@ -368,5 +571,6 @@ int cli_scangpt(cli_ctx *ctx)
368 368
         pos += hdr.tableEntrySize;
369 369
     }
370 370
 
371
-    return func_ret;
371
+    prtn_intxn_list_free(&prtncheck);
372
+    return ret;
372 373
 }
... ...
@@ -32,7 +32,7 @@
32 32
  * values. Sector size for GPT can be found by the offset the GPT header
33 33
  * signature is located (marking the beginning of the second sector.
34 34
 */
35
-#define GPT_SECTOR_SIZE 512
35
+#define GPT_DEFAULT_SECTOR_SIZE 512
36 36
 #define GPT_PARTITION_ENTRY_SIZE 128
37 37
 
38 38
 #define GPT_SIGNATURE 0x4546492050415254ULL
... ...
@@ -84,7 +84,7 @@ struct gpt_partition_entry {
84 84
     uint64_t firstLBA  __attribute__ ((packed));
85 85
     uint64_t lastLBA  __attribute__ ((packed));
86 86
     uint64_t attributes  __attribute__ ((packed));
87
-    uint8_t name[72];
87
+    uint16_t name[36] __attribute__ ((packed));
88 88
 };
89 89
 
90 90
 #ifdef HAVE_PRAGMA_PACK