~ubuntu-branches/ubuntu/saucy/clamav/saucy-backports

« back to all changes in this revision

Viewing changes to libclamav/mbr.c

  • Committer: Package Import Robot
  • Author(s): Scott Kitterman
  • Date: 2014-07-15 01:08:10 UTC
  • mfrom: (0.35.47 sid)
  • Revision ID: package-import@ubuntu.com-20140715010810-ru66ek4fun2iseba
Tags: 0.98.4+dfsg-2~ubuntu13.10.1
No-change backport to saucy (LP: #1341962)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  Copyright (C) 2014 Sourcefire, Inc.
 
3
 *
 
4
 *  Authors: Kevin Lin <klin@sourcefire.com>
 
5
 *
 
6
 *  This program is free software; you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License version 2 as
 
8
 *  published by the Free Software Foundation.
 
9
 *
 
10
 *  This program is distributed in the hope that it will be useful,
 
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 *  GNU General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with this program; if not, write to the Free Software
 
17
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
18
 *  MA 02110-1301, USA.
 
19
 */
 
20
 
 
21
#if HAVE_CONFIG_H
 
22
#include "clamav-config.h"
 
23
#endif
 
24
 
 
25
#include <stdio.h>
 
26
#include <errno.h>
 
27
#if HAVE_STRING_H
 
28
#include <string.h>
 
29
#endif
 
30
#include <ctype.h>
 
31
#include <fcntl.h>
 
32
#include <zlib.h>
 
33
 
 
34
#include <openssl/ssl.h>
 
35
#include <openssl/err.h>
 
36
#include "libclamav/crypto.h"
 
37
 
 
38
#include "cltypes.h"
 
39
#include "others.h"
 
40
#include "mbr.h"
 
41
#include "prtn_intxn.h"
 
42
#include "scanners.h"
 
43
#include "dconf.h"
 
44
 
 
45
//#define DEBUG_MBR_PARSE
 
46
//#define DEBUG_EBR_PARSE
 
47
 
 
48
#ifndef PRTN_INTXN_DETECTION
 
49
#  define PRTN_INTXN_DETECTION "heuristic.mbrprtnintersect"
 
50
#endif
 
51
 
 
52
#ifdef DEBUG_MBR_PARSE
 
53
#  define mbr_parsemsg(...) cli_dbgmsg( __VA_ARGS__)
 
54
#else
 
55
#  define mbr_parsemsg(...) ;
 
56
#endif
 
57
 
 
58
#ifdef DEBUG_EBR_PARSE
 
59
#  define ebr_parsemsg(...) cli_dbgmsg( __VA_ARGS__)
 
60
#else
 
61
#  define ebr_parsemsg(...) ;
 
62
#endif
 
63
 
 
64
enum MBR_STATE {
 
65
    SEEN_NOTHING,
 
66
    SEEN_PARTITION,
 
67
    SEEN_EXTENDED,
 
68
    SEEN_EMPTY
 
69
};
 
70
 
 
71
static int mbr_scanextprtn(cli_ctx *ctx, unsigned *prtncount, off_t extlba, 
 
72
                           size_t extlbasize, size_t sectorsize);
 
73
static void mbr_printbr(struct mbr_boot_record *record);
 
74
static int mbr_check_mbr(struct mbr_boot_record *record, size_t maplen, size_t sectorsize);
 
75
static int mbr_check_ebr(struct mbr_boot_record *record);
 
76
static int mbr_primary_prtn_intxn(cli_ctx *ctx, struct mbr_boot_record mbr, size_t sectorsize);
 
77
static int mbr_extended_prtn_intxn(cli_ctx *ctx, unsigned *prtncount, off_t extlba, size_t sectorsize);
 
78
 
 
79
int cli_mbr_check(const unsigned char *buff, size_t len, size_t maplen) {
 
80
    struct mbr_boot_record mbr;
 
81
    off_t mbr_base = 0;
 
82
    size_t sectorsize = 512;
 
83
 
 
84
    if (len < sectorsize) {
 
85
        return CL_EFORMAT;
 
86
    }
 
87
 
 
88
    mbr_base = sectorsize - sizeof(struct mbr_boot_record);
 
89
    memcpy(&mbr, buff+mbr_base, sizeof(mbr));
 
90
    mbr_convert_to_host(&mbr);
 
91
 
 
92
    if ((mbr.entries[0].type == MBR_PROTECTIVE) || (mbr.entries[0].type == MBR_HYBRID))
 
93
        return CL_TYPE_GPT;
 
94
 
 
95
    return mbr_check_mbr(&mbr, maplen, sectorsize);
 
96
}
 
97
 
 
98
int cli_mbr_check2(cli_ctx *ctx, size_t sectorsize) {
 
99
    struct mbr_boot_record mbr;
 
100
    off_t pos = 0, mbr_base = 0;
 
101
    size_t maplen;
 
102
 
 
103
    if (!ctx || !ctx->fmap) {
 
104
        cli_errmsg("cli_scanmbr: Invalid context\n");
 
105
        return CL_ENULLARG;
 
106
    }
 
107
 
 
108
    /* sector size calculation, actual value is OS dependent */
 
109
    if (sectorsize == 0)
 
110
        sectorsize = MBR_SECTOR_SIZE;
 
111
 
 
112
    mbr_base = sectorsize - sizeof(struct mbr_boot_record);
 
113
 
 
114
    /* size of total file must be a multiple of the sector size */
 
115
    maplen = (*ctx->fmap)->real_len;
 
116
    if ((maplen % sectorsize) != 0) {
 
117
        cli_dbgmsg("cli_scanmbr: File sized %lu is not a multiple of sector size %lu\n",
 
118
                   (unsigned long)maplen, (unsigned long)sectorsize);
 
119
        return CL_EFORMAT;
 
120
    }
 
121
 
 
122
    /* sector 0 (first sector) is the master boot record */
 
123
    pos = (MBR_SECTOR * sectorsize) + mbr_base;
 
124
 
 
125
    /* read the master boot record */
 
126
    if (fmap_readn(*ctx->fmap, &mbr, pos, sizeof(mbr)) != sizeof(mbr)) {
 
127
        cli_dbgmsg("cli_scanmbr: Invalid master boot record\n");
 
128
        return CL_EFORMAT;
 
129
    }
 
130
 
 
131
    /* convert the little endian to host, include the internal  */
 
132
    mbr_convert_to_host(&mbr);
 
133
 
 
134
    if ((mbr.entries[0].type == MBR_PROTECTIVE) || (mbr.entries[0].type == MBR_HYBRID))
 
135
        return CL_TYPE_GPT;
 
136
 
 
137
    return mbr_check_mbr(&mbr, maplen, sectorsize);
 
138
}
 
139
 
 
140
/* sets sectorsize to default value if specfied to be 0 */
 
141
int cli_scanmbr(cli_ctx *ctx, size_t sectorsize)
 
142
{
 
143
    struct mbr_boot_record mbr;
 
144
    enum MBR_STATE state = SEEN_NOTHING;
 
145
    int ret = CL_CLEAN, detection = CL_CLEAN;
 
146
    off_t pos = 0, mbr_base = 0, partoff = 0;
 
147
    unsigned i = 0, prtncount = 0;
 
148
    size_t maplen, partsize;
 
149
 
 
150
    mbr_parsemsg("The start of something magnificant: MBR parsing\n");
 
151
 
 
152
    if (!ctx || !ctx->fmap) {
 
153
        cli_errmsg("cli_scanmbr: Invalid context\n");
 
154
        return CL_ENULLARG;
 
155
    }
 
156
 
 
157
    /* sector size calculation, actual value is OS dependent */
 
158
    if (sectorsize == 0)
 
159
        sectorsize = MBR_SECTOR_SIZE;
 
160
 
 
161
    mbr_base = sectorsize - sizeof(struct mbr_boot_record);
 
162
 
 
163
    /* size of total file must be a multiple of the sector size */
 
164
    maplen = (*ctx->fmap)->real_len;
 
165
    if ((maplen % sectorsize) != 0) {
 
166
        cli_dbgmsg("cli_scanmbr: File sized %lu is not a multiple of sector size %lu\n",
 
167
                   (unsigned long)maplen, (unsigned long)sectorsize);
 
168
        return CL_EFORMAT;
 
169
    }
 
170
 
 
171
    /* sector 0 (first sector) is the master boot record */
 
172
    pos = (MBR_SECTOR * sectorsize) + mbr_base;
 
173
 
 
174
    /* read the master boot record */
 
175
    if (fmap_readn(*ctx->fmap, &mbr, pos, sizeof(mbr)) != sizeof(mbr)) {
 
176
        cli_dbgmsg("cli_scanmbr: Invalid master boot record\n");
 
177
        return CL_EFORMAT;
 
178
    }
 
179
 
 
180
    /* convert the little endian to host, include the internal  */
 
181
    mbr_convert_to_host(&mbr);
 
182
 
 
183
    /* MBR checks */
 
184
    ret = mbr_check_mbr(&mbr, maplen, sectorsize);
 
185
    if (ret != CL_CLEAN) {
 
186
        return ret;
 
187
    }
 
188
 
 
189
    /* MBR is valid, examine bootstrap code */
 
190
    ret = cli_map_scan(*ctx->fmap, 0, sectorsize, ctx, CL_TYPE_ANY);
 
191
    if (ret != CL_CLEAN) {
 
192
        if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))
 
193
            detection = CL_VIRUS;
 
194
        else
 
195
            return ret;
 
196
    }
 
197
 
 
198
    /* check that the partition table has no intersections - HEURISTICS */
 
199
    if ((ctx->options & CL_SCAN_PARTITION_INTXN) && (ctx->dconf->other & OTHER_CONF_PRTNINTXN)) {
 
200
        ret = mbr_primary_prtn_intxn(ctx, mbr, sectorsize);
 
201
        if (ret != CL_CLEAN) {
 
202
            if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))
 
203
                detection = CL_VIRUS;
 
204
            else
 
205
                return ret;
 
206
        }
 
207
    }
 
208
 
 
209
    /* MBR is valid, examine partitions */
 
210
    prtncount = 0;
 
211
    cli_dbgmsg("MBR Signature: %x\n", mbr.signature);
 
212
    for (i = 0; i < MBR_MAX_PARTITION_ENTRIES && prtncount < ctx->engine->maxpartitions; ++i) {
 
213
        cli_dbgmsg("MBR Partition Entry %u:\n", i);
 
214
        cli_dbgmsg("Status: %u\n", mbr.entries[i].status);
 
215
        cli_dbgmsg("Type: %x\n", mbr.entries[i].type);
 
216
        cli_dbgmsg("Blocks: [%u, +%u), ([%lu, +%lu))\n",
 
217
                   mbr.entries[i].firstLBA, mbr.entries[i].numLBA,
 
218
                   (unsigned long)(mbr.entries[i].firstLBA * sectorsize),
 
219
                   (unsigned long)(mbr.entries[i].numLBA * sectorsize));
 
220
 
 
221
        /* Handle MBR entry based on type */
 
222
        if (mbr.entries[i].type == MBR_EMPTY) {
 
223
            /* empty partiton entry */
 
224
            prtncount++;
 
225
        }
 
226
        else if (mbr.entries[i].type == MBR_EXTENDED) {
 
227
            if (state == SEEN_EXTENDED) {
 
228
                cli_dbgmsg("cli_scanmbr: detected a master boot record "
 
229
                           "with multiple extended partitions\n");
 
230
            }
 
231
            state = SEEN_EXTENDED; /* used only to detect mutiple extended partitions */
 
232
 
 
233
            ret = mbr_scanextprtn(ctx, &prtncount, mbr.entries[i].firstLBA, 
 
234
                                  mbr.entries[i].numLBA, sectorsize);
 
235
            if (ret != CL_CLEAN) {
 
236
                if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))
 
237
                    detection = CL_VIRUS;
 
238
                else
 
239
                    return ret;
 
240
            }
 
241
        }
 
242
        else {
 
243
            prtncount++;
 
244
 
 
245
            partoff = mbr.entries[i].firstLBA * sectorsize;
 
246
            partsize = mbr.entries[i].numLBA * sectorsize;
 
247
            mbr_parsemsg("cli_map_scan: [%u, +%u)\n", partoff, partsize);
 
248
            ret = cli_map_scan(*ctx->fmap, partoff, partsize, ctx, CL_TYPE_PART_ANY);
 
249
            if (ret != CL_CLEAN) {
 
250
                if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))
 
251
                    detection = CL_VIRUS;
 
252
                else
 
253
                    return ret;
 
254
            }
 
255
        }
 
256
    }
 
257
 
 
258
    if (prtncount >= ctx->engine->maxpartitions) {
 
259
        cli_dbgmsg("cli_scanmbr: maximum partitions reached\n");
 
260
    }
 
261
 
 
262
    return detection;
 
263
}
 
264
 
 
265
static int mbr_scanextprtn(cli_ctx *ctx, unsigned *prtncount, off_t extlba, size_t extlbasize, size_t sectorsize)
 
266
{
 
267
    struct mbr_boot_record ebr;
 
268
    enum MBR_STATE state = SEEN_NOTHING;
 
269
    int ret = CL_CLEAN, detection = CL_CLEAN;
 
270
    off_t pos = 0, mbr_base = 0, logiclba = 0, extoff = 0, partoff = 0;
 
271
    size_t partsize, extsize;
 
272
    unsigned i = 0, j = 0;
 
273
 
 
274
    ebr_parsemsg("The start of something exhausting: EBR parsing\n");
 
275
 
 
276
    mbr_base = sectorsize - sizeof(struct mbr_boot_record);
 
277
 
 
278
    logiclba = 0;
 
279
    extoff = extlba * sectorsize;
 
280
    extsize = extlbasize * sectorsize;
 
281
    do {
 
282
        pos = extlba * sectorsize; /* start of extended partition */
 
283
 
 
284
        /* read the extended boot record */
 
285
        pos += (logiclba * sectorsize) + mbr_base;
 
286
        if (fmap_readn(*ctx->fmap, &ebr, pos, sizeof(ebr)) != sizeof(ebr)) {
 
287
            cli_dbgmsg("cli_scanebr: Invalid extended boot record\n");
 
288
            return CL_EFORMAT;
 
289
        }
 
290
 
 
291
        /* convert the little endian to host */
 
292
        mbr_convert_to_host(&ebr);
 
293
 
 
294
        /* EBR checks */
 
295
        ret = mbr_check_ebr(&ebr);
 
296
        if (ret != CL_CLEAN) {
 
297
            return ret;
 
298
        }
 
299
 
 
300
        /* update state */
 
301
        state = SEEN_NOTHING;
 
302
        (*prtncount)++;
 
303
 
 
304
        /* EBR is valid, examine partitions */
 
305
        cli_dbgmsg("EBR Partition Entry %u:\n", i++);
 
306
        cli_dbgmsg("EBR Signature: %x\n", ebr.signature);
 
307
        for (j = 0; j < MBR_MAX_PARTITION_ENTRIES; ++j) {
 
308
            if (j < 2) {
 
309
                cli_dbgmsg("Logical Partition Entry %u:\n", j);
 
310
                cli_dbgmsg("Status: %u\n", ebr.entries[j].status);
 
311
                cli_dbgmsg("Type: %x\n", ebr.entries[j].type);
 
312
                cli_dbgmsg("Blocks: [%u, +%u), ([%lu, +%lu))\n",
 
313
                           ebr.entries[j].firstLBA, ebr.entries[j].numLBA,
 
314
                           (unsigned long)(ebr.entries[j].firstLBA * sectorsize),
 
315
                           (unsigned long)(ebr.entries[j].numLBA * sectorsize));
 
316
 
 
317
                if (ebr.entries[j].type == MBR_EMPTY) {
 
318
                    /* empty partiton entry */
 
319
                    switch(state) {
 
320
                    case SEEN_NOTHING:
 
321
                        state = SEEN_EMPTY;
 
322
                        break;
 
323
                    case SEEN_PARTITION:
 
324
                        logiclba = 0;
 
325
                        break;
 
326
                    case SEEN_EMPTY:
 
327
                        logiclba = 0;
 
328
                        /* fall-through */
 
329
                    case SEEN_EXTENDED:
 
330
                        cli_warnmsg("cli_scanebr: detected a logical boot record "
 
331
                                    "without a partition record\n");
 
332
                        break;
 
333
                    default:
 
334
                        cli_warnmsg("cli_scanebr: undefined state for EBR parsing\n");
 
335
                        return CL_EPARSE;
 
336
                    }
 
337
                }
 
338
                else if (ebr.entries[j].type == MBR_EXTENDED) {
 
339
                    switch(state) {
 
340
                    case SEEN_NOTHING:
 
341
                        state = SEEN_EXTENDED;
 
342
                        break;
 
343
                    case SEEN_PARTITION:
 
344
                        break;
 
345
                    case SEEN_EMPTY:
 
346
                        cli_warnmsg("cli_scanebr: detected a logical boot record "
 
347
                                    "without a partition record\n");
 
348
                        break;
 
349
                    case SEEN_EXTENDED:
 
350
                        cli_warnmsg("cli_scanebr: detected a logical boot record "
 
351
                                    "with multiple extended partition records\n");
 
352
                        return CL_EFORMAT;
 
353
                    default:
 
354
                        cli_dbgmsg("cli_scanebr: undefined state for EBR parsing\n");
 
355
                        return CL_EPARSE;
 
356
                    }
 
357
 
 
358
                    logiclba = ebr.entries[j].firstLBA;
 
359
                }
 
360
                else {
 
361
                    switch(state) {
 
362
                    case SEEN_NOTHING:
 
363
                        state = SEEN_PARTITION;
 
364
                        break;
 
365
                    case SEEN_PARTITION:
 
366
                        cli_warnmsg("cli_scanebr: detected a logical boot record "
 
367
                                    "with multiple partition records\n");
 
368
                        logiclba = 0; /* no extended partitions are possible */
 
369
                        break;
 
370
                    case SEEN_EXTENDED:
 
371
                        cli_warnmsg("cli_scanebr: detected a logical boot record "
 
372
                                    "with extended partition record first\n");
 
373
                        break;
 
374
                    case SEEN_EMPTY:
 
375
                        cli_warnmsg("cli_scanebr: detected a logical boot record "
 
376
                                    "with empty partition record first\n");
 
377
                        logiclba = 0; /* no extended partitions are possible */
 
378
                        break;
 
379
                    default:
 
380
                        cli_dbgmsg("cli_scanebr: undefined state for EBR parsing\n");
 
381
                        return CL_EPARSE;
 
382
                    }
 
383
 
 
384
                    partoff = (extlba + logiclba + ebr.entries[j].firstLBA) * sectorsize;
 
385
                    partsize = ebr.entries[j].numLBA * sectorsize;
 
386
                    if (partoff + partsize > extoff + extsize) {
 
387
                        cli_dbgmsg("cli_scanebr: Invalid extended partition entry\n");
 
388
                        return CL_EFORMAT;
 
389
                    }
 
390
 
 
391
                    ret = cli_map_scan(*ctx->fmap, partoff, partsize, ctx, CL_TYPE_PART_ANY);
 
392
                    if (ret != CL_CLEAN) {
 
393
                        if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))
 
394
                            detection = CL_VIRUS;
 
395
                        else
 
396
                            return ret;
 
397
                    }
 
398
                }
 
399
            }
 
400
            else {
 
401
                /* check the last two entries to be empty */
 
402
                if (ebr.entries[j].type != MBR_EMPTY) {
 
403
                    cli_dbgmsg("cli_scanebr: detected a non-empty partition "
 
404
                               "entry at index %u\n", j);
 
405
                    /* should we attempt to use these entries? */
 
406
                    return CL_EFORMAT;
 
407
                }
 
408
            }
 
409
        }
 
410
    } while (logiclba != 0 && (*prtncount) < ctx->engine->maxpartitions);
 
411
 
 
412
    cli_dbgmsg("cli_scanmbr: examined %u logical partitions\n", i);
 
413
 
 
414
    return detection;
 
415
}
 
416
 
 
417
void mbr_convert_to_host(struct mbr_boot_record *record)
 
418
{
 
419
    struct mbr_partition_entry *entry;
 
420
    unsigned i;
 
421
 
 
422
    for (i = 0; i < MBR_MAX_PARTITION_ENTRIES; ++i) {
 
423
        entry = &record->entries[i];
 
424
 
 
425
        entry->firstLBA = le32_to_host(entry->firstLBA);
 
426
        entry->numLBA = le32_to_host(entry->numLBA);
 
427
    }
 
428
    record->signature = be16_to_host(record->signature);
 
429
}
 
430
 
 
431
static void mbr_printbr(struct mbr_boot_record *record)
 
432
{
 
433
    unsigned i;
 
434
 
 
435
    cli_dbgmsg("signature: %x\n", record->signature);
 
436
    for (i = 0; i < MBR_MAX_PARTITION_ENTRIES; ++i) {
 
437
        cli_dbgmsg("entry %u:\n", i);
 
438
        cli_dbgmsg("\tstatus: %x\n", record->entries[i].status);
 
439
        cli_dbgmsg("\tfirstCHS: [%u, %u, %u]\n", record->entries[i].firstCHS[0],
 
440
                   record->entries[i].firstCHS[1], record->entries[i].firstCHS[2]);
 
441
        cli_dbgmsg("\ttype: %x\n", record->entries[i].type);
 
442
        cli_dbgmsg("\tlastCHS: [%u, %u, %u]\n", record->entries[i].lastCHS[0],
 
443
                   record->entries[i].lastCHS[1], record->entries[i].lastCHS[2]);
 
444
        cli_dbgmsg("\tfirstLBA: %u\n", record->entries[i].firstLBA);
 
445
        cli_dbgmsg("\tnumLBA: %u\n", record->entries[i].numLBA);
 
446
    }
 
447
}
 
448
 
 
449
static int mbr_check_mbr(struct mbr_boot_record *record, size_t maplen, size_t sectorsize)
 
450
{
 
451
    unsigned i = 0;
 
452
    off_t partoff = 0;
 
453
    size_t partsize = 0;
 
454
 
 
455
    for (i = 0; i < MBR_MAX_PARTITION_ENTRIES; ++i) {
 
456
        /* check status */
 
457
        if ((record->entries[i].status != MBR_STATUS_INACTIVE) && 
 
458
            (record->entries[i].status != MBR_STATUS_ACTIVE)) {
 
459
            cli_dbgmsg("cli_scanmbr: Invalid boot record status\n");
 
460
            return CL_EFORMAT;
 
461
        }
 
462
 
 
463
        partoff = record->entries[i].firstLBA * sectorsize;
 
464
        partsize = record->entries[i].numLBA * sectorsize;
 
465
        if (partoff + partsize > maplen) {
 
466
            cli_dbgmsg("cli_scanmbr: Invalid partition entry\n");
 
467
            return CL_EFORMAT;
 
468
        }
 
469
    }
 
470
 
 
471
    /* check the signature */
 
472
    if (record->signature != MBR_SIGNATURE) {
 
473
        cli_dbgmsg("cli_scanmbr: Invalid boot record signature\n");
 
474
        return CL_EFORMAT;
 
475
    }
 
476
 
 
477
    /* check the maplen */
 
478
    if ((maplen / sectorsize) < 2) {
 
479
        cli_dbgmsg("cli_scanmbr: file is too small to hold disk image\n");
 
480
        return CL_EFORMAT;
 
481
    }
 
482
 
 
483
    return CL_CLEAN;
 
484
}
 
485
 
 
486
static int mbr_check_ebr(struct mbr_boot_record *record)
 
487
{
 
488
    unsigned i = 0;
 
489
 
 
490
    for (i = 0; i < MBR_MAX_PARTITION_ENTRIES-2; ++i) {
 
491
        /* check status */
 
492
        if ((record->entries[i].status != MBR_STATUS_INACTIVE) && 
 
493
            (record->entries[i].status != MBR_STATUS_ACTIVE)) {
 
494
            cli_dbgmsg("cli_scanmbr: Invalid boot record status\n");
 
495
            return CL_EFORMAT;
 
496
        }
 
497
    }
 
498
 
 
499
    /* check the signature */
 
500
    if (record->signature != MBR_SIGNATURE) {
 
501
        cli_dbgmsg("cli_scanmbr: Invalid boot record signature\n");
 
502
        return CL_EFORMAT;
 
503
    }
 
504
 
 
505
    return CL_CLEAN;
 
506
}
 
507
 
 
508
/* this includes the overall bounds of extended partitions */
 
509
static int mbr_primary_prtn_intxn(cli_ctx *ctx, struct mbr_boot_record mbr, size_t sectorsize)
 
510
{
 
511
    prtn_intxn_list_t prtncheck;
 
512
    unsigned i = 0, pitxn = 0, prtncount = 0;
 
513
    int ret = CL_CLEAN, tmp = CL_CLEAN;
 
514
 
 
515
    prtn_intxn_list_init(&prtncheck);
 
516
 
 
517
    for (i = 0; i < MBR_MAX_PARTITION_ENTRIES && prtncount < ctx->engine->maxpartitions; ++i) {
 
518
        if (mbr.entries[i].type == MBR_EMPTY) {
 
519
            /* empty partiton entry */
 
520
            prtncount++;
 
521
        }
 
522
        else {
 
523
            tmp = prtn_intxn_list_check(&prtncheck, &pitxn, mbr.entries[i].firstLBA,
 
524
                                        mbr.entries[i].numLBA);
 
525
            if (tmp != CL_CLEAN) {
 
526
                if ((ctx->options & CL_SCAN_ALLMATCHES) && (tmp == CL_VIRUS)) {
 
527
                    cli_dbgmsg("cli_scanmbr: detected intersection with partitions "
 
528
                               "[%u, %u]\n", pitxn, i);
 
529
                    cli_append_virus(ctx, PRTN_INTXN_DETECTION);
 
530
                    ret = tmp;
 
531
                    tmp = 0;
 
532
                }
 
533
                else if (tmp == CL_VIRUS) {
 
534
                    cli_dbgmsg("cli_scanmbr: detected intersection with partitions "
 
535
                               "[%u, %u]\n", pitxn, i);
 
536
                    cli_append_virus(ctx, PRTN_INTXN_DETECTION);
 
537
                    prtn_intxn_list_free(&prtncheck);
 
538
                    return CL_VIRUS;
 
539
                }
 
540
                else {
 
541
                    prtn_intxn_list_free(&prtncheck);
 
542
                    return tmp;
 
543
                }
 
544
            }
 
545
 
 
546
            if (mbr.entries[i].type == MBR_EXTENDED) {
 
547
                /* check the logical partitions */
 
548
                tmp = mbr_extended_prtn_intxn(ctx, &prtncount, 
 
549
                                  mbr.entries[i].firstLBA, sectorsize);
 
550
                if (tmp != CL_CLEAN) {
 
551
                    if ((ctx->options & CL_SCAN_ALLMATCHES) && (tmp == CL_VIRUS)) {
 
552
                        ret = tmp;
 
553
                        tmp = 0;
 
554
                    }
 
555
                    else if (tmp == CL_VIRUS) {
 
556
                        prtn_intxn_list_free(&prtncheck);
 
557
                        return CL_VIRUS;
 
558
                    }
 
559
                    else {
 
560
                        prtn_intxn_list_free(&prtncheck);
 
561
                        return tmp;
 
562
                    }
 
563
                }
 
564
            }
 
565
            else {
 
566
                prtncount++;
 
567
            }
 
568
        }
 
569
    }
 
570
 
 
571
    prtn_intxn_list_free(&prtncheck);
 
572
    return ret;
 
573
}
 
574
 
 
575
/* checks internal logical partitions */
 
576
static int mbr_extended_prtn_intxn(cli_ctx *ctx, unsigned *prtncount, off_t extlba, size_t sectorsize)
 
577
{
 
578
    struct mbr_boot_record ebr;
 
579
    prtn_intxn_list_t prtncheck;
 
580
    unsigned i, pitxn;
 
581
    int ret = CL_CLEAN, tmp = CL_CLEAN, mbr_base = 0;
 
582
    off_t pos = 0, logiclba = 0;
 
583
 
 
584
    mbr_base = sectorsize - sizeof(struct mbr_boot_record);
 
585
 
 
586
    prtn_intxn_list_init(&prtncheck);
 
587
 
 
588
    logiclba = 0; i = 0;
 
589
    do {
 
590
        pos = extlba * sectorsize; /* start of extended partition */
 
591
 
 
592
        /* read the extended boot record */
 
593
        pos += (logiclba * sectorsize) + mbr_base;
 
594
        if (fmap_readn(*ctx->fmap, &ebr, pos, sizeof(ebr)) != sizeof(ebr)) {
 
595
            cli_dbgmsg("cli_scanebr: Invalid extended boot record\n");
 
596
            prtn_intxn_list_free(&prtncheck);
 
597
            return CL_EFORMAT;
 
598
        }
 
599
 
 
600
        /* convert the little endian to host */
 
601
        mbr_convert_to_host(&ebr);
 
602
 
 
603
        /* update state */
 
604
        (*prtncount)++;
 
605
 
 
606
        /* assume that logical record is first and extended is second */
 
607
        tmp = prtn_intxn_list_check(&prtncheck, &pitxn, logiclba, ebr.entries[0].numLBA);
 
608
        if (tmp != CL_CLEAN) {
 
609
            if ((ctx->options & CL_SCAN_ALLMATCHES) && (tmp == CL_VIRUS)) {
 
610
                cli_dbgmsg("cli_scanebr: detected intersection with partitions "
 
611
                           "[%u, %u]\n", pitxn, i);
 
612
                cli_append_virus(ctx, PRTN_INTXN_DETECTION);
 
613
                ret = tmp;
 
614
                tmp = 0;
 
615
            }
 
616
            else if (tmp == CL_VIRUS) {
 
617
                cli_dbgmsg("cli_scanebr: detected intersection with partitions "
 
618
                           "[%u, %u]\n", pitxn, i);
 
619
                cli_append_virus(ctx, PRTN_INTXN_DETECTION);
 
620
                prtn_intxn_list_free(&prtncheck);
 
621
                return CL_VIRUS;
 
622
            }
 
623
            else {
 
624
                prtn_intxn_list_free(&prtncheck);
 
625
                return tmp;
 
626
            }
 
627
        }
 
628
 
 
629
        /* assume extended is second entry */
 
630
        if (ebr.entries[1].type != MBR_EXTENDED) {
 
631
            cli_dbgmsg("cli_scanebr: second entry for EBR is not an extended partition\n");
 
632
            break;
 
633
        }
 
634
 
 
635
        logiclba = ebr.entries[1].firstLBA;
 
636
 
 
637
        ++i;
 
638
    } while (logiclba != 0 && (*prtncount) < ctx->engine->maxpartitions);
 
639
 
 
640
    prtn_intxn_list_free(&prtncheck);    
 
641
    return ret;
 
642
}