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

« back to all changes in this revision

Viewing changes to libclamav/apm.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 Cisco Systems, Inc.
 
3
 *
 
4
 *  Authors: Kevin Lin <kevlin2@cisco.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
 
 
33
#include <openssl/ssl.h>
 
34
#include <openssl/err.h>
 
35
#include "libclamav/crypto.h"
 
36
 
 
37
#include "cltypes.h"
 
38
#include "others.h"
 
39
#include "apm.h"
 
40
#include "prtn_intxn.h"
 
41
#include "scanners.h"
 
42
#include "dconf.h"
 
43
 
 
44
//#define DEBUG_APM_PARSE
 
45
 
 
46
#ifdef DEBUG_APM_PARSE
 
47
#  define apm_parsemsg(...) cli_dbgmsg( __VA_ARGS__)
 
48
#else
 
49
#  define apm_parsemsg(...) ;
 
50
#endif
 
51
 
 
52
static int apm_prtn_intxn(cli_ctx *ctx, struct apm_partition_info *aptable, size_t sectorsize, int old_school);
 
53
 
 
54
int cli_scanapm(cli_ctx *ctx)
 
55
{
 
56
    struct apm_driver_desc_map ddm;
 
57
    struct apm_partition_info aptable, apentry;
 
58
    int ret = CL_CLEAN, detection = CL_CLEAN, old_school = 0;
 
59
    size_t sectorsize, maplen, partsize, sectorcheck;
 
60
    off_t pos = 0, partoff = 0;
 
61
    unsigned i;
 
62
    uint32_t max_prtns = 0;
 
63
 
 
64
    if (!ctx || !ctx->fmap) {
 
65
        cli_errmsg("cli_scanapm: Invalid context\n");
 
66
        return CL_ENULLARG;
 
67
    }
 
68
 
 
69
    /* read driver description map at sector 0  */
 
70
    if (fmap_readn(*ctx->fmap, &ddm, pos, sizeof(ddm)) != sizeof(ddm)) {
 
71
        cli_dbgmsg("cli_scanapm: Invalid Apple driver description map\n");
 
72
        return CL_EFORMAT;
 
73
    }
 
74
 
 
75
    /* convert driver description map big-endian to host */
 
76
    ddm.signature = be16_to_host(ddm.signature);
 
77
    ddm.blockSize = be16_to_host(ddm.blockSize);
 
78
    ddm.blockCount = be32_to_host(ddm.blockCount);
 
79
 
 
80
    /* check DDM signature */
 
81
    if (ddm.signature != DDM_SIGNATURE) {
 
82
        cli_dbgmsg("cli_scanapm: Apple driver description map signature mismatch\n");
 
83
        return CL_EFORMAT;
 
84
    }
 
85
 
 
86
    /* sector size is determined by the ddm */
 
87
    sectorsize = ddm.blockSize;
 
88
 
 
89
    /* size of total file must be described by the ddm */
 
90
    maplen = (*ctx->fmap)->real_len;
 
91
    if ((ddm.blockSize * ddm.blockCount) != maplen) {
 
92
        cli_dbgmsg("cli_scanapm: File described %u size does not match %lu actual size\n",
 
93
                   (ddm.blockSize * ddm.blockCount), (unsigned long)maplen);
 
94
        return CL_EFORMAT;
 
95
    }
 
96
 
 
97
    /* check for old-school partition map */
 
98
    if (sectorsize == 2048) {
 
99
        if (fmap_readn(*ctx->fmap, &aptable, APM_FALLBACK_SECTOR_SIZE, sizeof(aptable)) != sizeof(aptable)) {
 
100
            cli_dbgmsg("cli_scanapm: Invalid Apple partition entry\n");
 
101
            return CL_EFORMAT;
 
102
        }
 
103
 
 
104
        aptable.signature = be16_to_host(aptable.signature);
 
105
        if (aptable.signature == APM_SIGNATURE) {
 
106
            sectorsize = APM_FALLBACK_SECTOR_SIZE;
 
107
            old_school = 1;
 
108
        }
 
109
    }
 
110
 
 
111
    /* read partition table at sector 1 (or after the ddm if old-school) */
 
112
    pos = APM_PTABLE_BLOCK * sectorsize;
 
113
 
 
114
    if (fmap_readn(*ctx->fmap, &aptable, pos, sizeof(aptable)) != sizeof(aptable)) {
 
115
        cli_dbgmsg("cli_scanapm: Invalid Apple partition table\n");
 
116
        return CL_EFORMAT;
 
117
    }
 
118
 
 
119
    /* convert partition table big endian to host */
 
120
    aptable.signature = be16_to_host(aptable.signature);
 
121
    aptable.numPartitions = be32_to_host(aptable.numPartitions);
 
122
    aptable.pBlockStart = be32_to_host(aptable.pBlockStart);
 
123
    aptable.pBlockCount = be32_to_host(aptable.pBlockCount);
 
124
 
 
125
    /* check the partition entry signature */
 
126
    if (aptable.signature != APM_SIGNATURE) {
 
127
        cli_dbgmsg("cli_scanapm: Apple partition table signature mismatch\n");
 
128
        return CL_EFORMAT;
 
129
    }
 
130
 
 
131
    /* check if partition table partition */
 
132
    if (strncmp((char*)aptable.type, "Apple_Partition_Map", 32) &&
 
133
        strncmp((char*)aptable.type, "Apple_partition_map", 32) &&
 
134
        strncmp((char*)aptable.type, "Apple_patition_map", 32)){
 
135
        cli_dbgmsg("cli_scanapm: Initial Apple Partition Map partition is not detected\n");
 
136
        return CL_EFORMAT;
 
137
    }
 
138
 
 
139
    /* check that the partition table fits in the space specified - HEURISTICS */
 
140
    if ((ctx->options & CL_SCAN_PARTITION_INTXN) && (ctx->dconf->other & OTHER_CONF_PRTNINTXN)) {
 
141
        ret = apm_prtn_intxn(ctx, &aptable, sectorsize, old_school);
 
142
        if (ret != CL_CLEAN) {
 
143
            if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))
 
144
                detection = CL_VIRUS;
 
145
            else
 
146
                return ret;
 
147
        }
 
148
    }
 
149
 
 
150
    /* print debugging info on partition tables */
 
151
    cli_dbgmsg("APM Partition Table:\n");
 
152
    cli_dbgmsg("Name: %s\n", (char*)aptable.name);
 
153
    cli_dbgmsg("Type: %s\n", (char*)aptable.type);
 
154
    cli_dbgmsg("Signature: %x\n", aptable.signature);
 
155
    cli_dbgmsg("Partition Count: %u\n", aptable.numPartitions);
 
156
    cli_dbgmsg("Blocks: [%u, +%u), ([%lu, +%lu))\n",
 
157
               aptable.pBlockStart, aptable.pBlockCount,
 
158
               (unsigned long)(aptable.pBlockStart * sectorsize),
 
159
               (unsigned long)(aptable.pBlockCount * sectorsize));
 
160
 
 
161
    /* check engine maxpartitions limit */
 
162
    if (aptable.numPartitions < ctx->engine->maxpartitions) {
 
163
        max_prtns = aptable.numPartitions;
 
164
    }
 
165
    else {
 
166
        max_prtns = ctx->engine->maxpartitions;
 
167
    }
 
168
 
 
169
    /* partition table is a partition [at index 1], so skip it */
 
170
    for (i = 2; i <= max_prtns; ++i) {
 
171
        /* read partition table entry */
 
172
        pos = i * sectorsize;
 
173
        if (fmap_readn(*ctx->fmap, &apentry, pos, sizeof(apentry)) != sizeof(apentry)) {
 
174
            cli_dbgmsg("cli_scanapm: Invalid Apple partition entry\n");
 
175
            return CL_EFORMAT;
 
176
        }
 
177
 
 
178
        /* convert partition entry big endian to host */
 
179
        apentry.signature = be16_to_host(apentry.signature);
 
180
        apentry.reserved = be16_to_host(apentry.reserved);
 
181
        apentry.numPartitions = be32_to_host(apentry.numPartitions);
 
182
        apentry.pBlockStart = be32_to_host(apentry.pBlockStart);
 
183
        apentry.pBlockCount = be32_to_host(apentry.pBlockCount);
 
184
 
 
185
        /* check the partition entry signature */
 
186
        if (aptable.signature != APM_SIGNATURE) {
 
187
            cli_dbgmsg("cli_scanapm: Apple partition entry signature mismatch\n");
 
188
            return CL_EFORMAT;
 
189
        }
 
190
 
 
191
        /* check if a out-of-order partition map */
 
192
        if (!strncmp((char*)apentry.type, "Apple_Partition_Map", 32) ||
 
193
            !strncmp((char*)apentry.type, "Apple_partition_map", 32) ||
 
194
            !strncmp((char*)apentry.type, "Apple_patition_map", 32)) {
 
195
 
 
196
            cli_dbgmsg("cli_scanapm: Out of order Apple Partition Map partition\n");
 
197
            continue;
 
198
        }
 
199
 
 
200
        partoff = apentry.pBlockStart * sectorsize;
 
201
        partsize = apentry.pBlockCount * sectorsize;
 
202
        /* re-calculate if old_school and aligned [512 * 4 => 2048] */
 
203
        if (old_school && ((i % 4) == 0)) {
 
204
            if (!strncmp((char*)apentry.type, "Apple_Driver",       32) ||
 
205
                !strncmp((char*)apentry.type, "Apple_Driver43",     32) ||
 
206
                !strncmp((char*)apentry.type, "Apple_Driver43_CD",  32) ||
 
207
                !strncmp((char*)apentry.type, "Apple_Driver_ATA",   32) ||
 
208
                !strncmp((char*)apentry.type, "Apple_Driver_ATAPI", 32) ||
 
209
                !strncmp((char*)apentry.type, "Apple_Patches",      32)) {
 
210
 
 
211
                partsize = apentry.pBlockCount * 2048;;
 
212
            }
 
213
        }
 
214
 
 
215
        /* check if invalid partition */
 
216
        if ((partoff == 0) || (partoff+partsize > maplen)) {
 
217
            cli_dbgmsg("cli_scanapm: Detected invalid Apple partition entry\n");
 
218
            continue;
 
219
        }
 
220
 
 
221
        /* print debugging info on partition */
 
222
        cli_dbgmsg("APM Partition Entry %u:\n", i);
 
223
        cli_dbgmsg("Name: %s\n", (char*)apentry.name);
 
224
        cli_dbgmsg("Type: %s\n", (char*)apentry.type);
 
225
        cli_dbgmsg("Signature: %x\n", apentry.signature);
 
226
        cli_dbgmsg("Partition Count: %u\n", apentry.numPartitions);
 
227
        cli_dbgmsg("Blocks: [%u, +%u), ([%lu, +%lu))\n",
 
228
                   apentry.pBlockStart, apentry.pBlockCount, (long unsigned)partoff, (long unsigned)partsize);
 
229
 
 
230
        /* send the partition to cli_map_scan */
 
231
        ret = cli_map_scan(*ctx->fmap, partoff, partsize, ctx, CL_TYPE_PART_ANY);
 
232
        if (ret != CL_CLEAN) {
 
233
            if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))
 
234
                detection = CL_VIRUS;
 
235
            else
 
236
                return ret;
 
237
        }
 
238
    } 
 
239
 
 
240
    if (i >= ctx->engine->maxpartitions) {
 
241
        cli_dbgmsg("cli_scanapm: max partitions reached\n");
 
242
    }
 
243
 
 
244
    return detection;
 
245
}
 
246
 
 
247
static int apm_prtn_intxn(cli_ctx *ctx, struct apm_partition_info *aptable, size_t sectorsize, int old_school)
 
248
{
 
249
    prtn_intxn_list_t prtncheck;
 
250
    struct apm_partition_info apentry;
 
251
    unsigned i, pitxn;
 
252
    int ret = CL_CLEAN, tmp = CL_CLEAN;
 
253
    off_t pos;
 
254
    uint32_t max_prtns = 0;
 
255
 
 
256
    prtn_intxn_list_init(&prtncheck);
 
257
 
 
258
    /* check engine maxpartitions limit */
 
259
    if (aptable->numPartitions < ctx->engine->maxpartitions) {
 
260
        max_prtns = aptable->numPartitions;
 
261
    }
 
262
    else {
 
263
        max_prtns = ctx->engine->maxpartitions;
 
264
    }
 
265
 
 
266
    for (i = 1; i <= max_prtns; ++i) {
 
267
        /* read partition table entry */
 
268
        pos = i * sectorsize;
 
269
        if (fmap_readn(*ctx->fmap, &apentry, pos, sizeof(apentry)) != sizeof(apentry)) {
 
270
            cli_dbgmsg("cli_scanapm: Invalid Apple partition entry\n");
 
271
            prtn_intxn_list_free(&prtncheck);
 
272
            return CL_EFORMAT;
 
273
        }
 
274
 
 
275
        /* convert necessary info big endian to host */
 
276
        apentry.pBlockStart = be32_to_host(apentry.pBlockStart);
 
277
        apentry.pBlockCount = be32_to_host(apentry.pBlockCount);
 
278
        /* re-calculate if old_school and aligned [512 * 4 => 2048] */
 
279
        if (old_school && ((i % 4) == 0)) {
 
280
            if (!strncmp((char*)apentry.type, "Apple_Driver",       32) ||
 
281
                !strncmp((char*)apentry.type, "Apple_Driver43",     32) ||
 
282
                !strncmp((char*)apentry.type, "Apple_Driver43_CD",  32) ||
 
283
                !strncmp((char*)apentry.type, "Apple_Driver_ATA",   32) ||
 
284
                !strncmp((char*)apentry.type, "Apple_Driver_ATAPI", 32) ||
 
285
                !strncmp((char*)apentry.type, "Apple_Patches",      32)) {
 
286
 
 
287
                apentry.pBlockCount = apentry.pBlockCount * 4;;
 
288
            }
 
289
        }
 
290
 
 
291
        tmp = prtn_intxn_list_check(&prtncheck, &pitxn, apentry.pBlockStart, apentry.pBlockCount);
 
292
        if (tmp != CL_CLEAN) {
 
293
            if ((ctx->options & CL_SCAN_ALLMATCHES) && (tmp == CL_VIRUS)) {
 
294
                apm_parsemsg("Name: %s\n", (char*)aptable.name);
 
295
                apm_parsemsg("Type: %s\n", (char*)aptable.type);
 
296
 
 
297
                cli_dbgmsg("cli_scanapm: detected intersection with partitions "
 
298
                           "[%u, %u]\n", pitxn, i);
 
299
                cli_append_virus(ctx, PRTN_INTXN_DETECTION);
 
300
                ret = tmp;
 
301
                tmp = 0;
 
302
            }
 
303
            else if (tmp == CL_VIRUS) {
 
304
                apm_parsemsg("Name: %s\n", (char*)aptable.name);
 
305
                apm_parsemsg("Type: %s\n", (char*)aptable.type);
 
306
 
 
307
                cli_dbgmsg("cli_scanapm: detected intersection with partitions "
 
308
                           "[%u, %u]\n", pitxn, i);
 
309
                cli_append_virus(ctx, PRTN_INTXN_DETECTION);
 
310
                prtn_intxn_list_free(&prtncheck);
 
311
                return CL_VIRUS;
 
312
            }
 
313
            else {
 
314
                prtn_intxn_list_free(&prtncheck);
 
315
                return tmp;
 
316
            }
 
317
        }
 
318
 
 
319
        pos += sectorsize;
 
320
    }
 
321
 
 
322
    prtn_intxn_list_free(&prtncheck);
 
323
    return ret;
 
324
}