Browse code

Merge remote-tracking branch 'origin/master' into 0.98

David Raynor authored on 2013/10/16 05:04:48
Showing 4 changed files
... ...
@@ -1,3 +1,11 @@
1
+Tue Oct 15 16:03:25 2013 EDT 2013 (dar)
2
+------------------------------------
3
+ * libclamav: bb #9154 - ELF handling re-write
4
+
5
+Tue Oct 15 16:00:14 2013 EDT 2013 (dar)
6
+------------------------------------
7
+ * libclamav: bb #8696 - Bug reported by NIW Solutions
8
+
1 9
 Fri Oct 11 16:50:34 2013 EDT 2013 (dar)
2 10
 ------------------------------------
3 11
  * bb #9072: clamscan message separator fix
... ...
@@ -1,5 +1,5 @@
1 1
 /*
2
- *  Copyright (C) 2007-2009 Sourcefire, Inc.
2
+ *  Copyright (C) 2007-2013 Sourcefire, Inc.
3 3
  *
4 4
  *  Authors: Tomasz Kojm
5 5
  *
... ...
@@ -41,12 +41,14 @@
41 41
 
42 42
 #define EC16(v, conv)   (conv ? cbswap16(v) : v)
43 43
 #define EC32(v, conv)   (conv ? cbswap32(v) : v)
44
+#define EC64(v, conv)   (conv ? cbswap64(v) : v)
44 45
 
45
-static uint32_t cli_rawaddr(uint32_t vaddr, struct elf_program_hdr32 *ph, uint16_t phnum, uint8_t conv, uint8_t *err)
46
+static void cli_elf_sectionlog(uint32_t sh_type, uint32_t sh_flags);
47
+
48
+static uint32_t cli_rawaddr32(uint32_t vaddr, struct elf_program_hdr32 *ph, uint16_t phnum, uint8_t conv, uint8_t *err)
46 49
 {
47 50
 	uint16_t i, found = 0;
48 51
 
49
-
50 52
     for(i = 0; i < phnum; i++) {
51 53
 	if(EC32(ph[i].p_vaddr, conv) <= vaddr && EC32(ph[i].p_vaddr, conv) + EC32(ph[i].p_memsz, conv) > vaddr) {
52 54
 	    found = 1;
... ...
@@ -63,78 +65,649 @@ static uint32_t cli_rawaddr(uint32_t vaddr, struct elf_program_hdr32 *ph, uint16
63 63
     return vaddr - EC32(ph[i].p_vaddr, conv) + EC32(ph[i].p_offset, conv);
64 64
 }
65 65
 
66
-int cli_scanelf(cli_ctx *ctx)
66
+static uint64_t cli_rawaddr64(uint64_t vaddr, struct elf_program_hdr64 *ph, uint16_t phnum, uint8_t conv, uint8_t *err)
67 67
 {
68
-	struct elf_file_hdr32 file_hdr;
69
-	struct elf_section_hdr32 *section_hdr = NULL;
70
-	struct elf_program_hdr32 *program_hdr = NULL;
71
-	uint16_t shnum, phnum, shentsize, phentsize;
72
-	uint32_t entry, fentry, shoff, phoff, i;
73
-	uint8_t conv = 0, err;
74
-	unsigned int format;
75
-	fmap_t *map = *ctx->fmap;
76
-	uint32_t viruses_found = 0;
68
+	uint16_t i, found = 0;
77 69
 
78
-    cli_dbgmsg("in cli_scanelf\n");
70
+    for(i = 0; i < phnum; i++) {
71
+	if(EC64(ph[i].p_vaddr, conv) <= vaddr && EC64(ph[i].p_vaddr, conv) + EC64(ph[i].p_memsz, conv) > vaddr) {
72
+	    found = 1;
73
+	    break;
74
+	}
75
+    }
76
+
77
+    if(!found) {
78
+	*err = 1;
79
+	return 0;
80
+    }
81
+
82
+    *err = 0;
83
+    return vaddr - EC64(ph[i].p_vaddr, conv) + EC64(ph[i].p_offset, conv);
84
+}
85
+
86
+/* Return converted endian-fixed header, or error code */
87
+static int cli_elf_fileheader(cli_ctx *ctx, fmap_t *map, union elf_file_hdr *file_hdr,
88
+    uint8_t *do_convert, uint8_t *is64)
89
+{
90
+	uint8_t format64, conv;
79 91
 
80
-    if(fmap_readn(map, &file_hdr, 0, sizeof(file_hdr)) != sizeof(file_hdr)) {
92
+    /* Load enough for smaller header first */
93
+    if(fmap_readn(map, file_hdr, 0, sizeof(struct elf_file_hdr32)) != sizeof(struct elf_file_hdr32)) {
81 94
 	/* Not an ELF file? */
82 95
 	cli_dbgmsg("ELF: Can't read file header\n");
83
-	return CL_CLEAN;
96
+	return CL_BREAK;
84 97
     }
85 98
 
86
-    if(memcmp(file_hdr.e_ident, "\x7f\x45\x4c\x46", 4)) {
99
+    if(memcmp(file_hdr->hdr64.e_ident, "\x7f\x45\x4c\x46", 4)) {
87 100
 	cli_dbgmsg("ELF: Not an ELF file\n");
88
-	return CL_CLEAN;
101
+	return CL_BREAK;
89 102
     }
90 103
 
91
-    format = file_hdr.e_ident[4];
92
-    if(format != 1 && format != 2) {
93
-	cli_dbgmsg("ELF: Unknown ELF class (%u)\n", file_hdr.e_ident[4]);
94
-	return CL_EFORMAT;
104
+    switch(file_hdr->hdr64.e_ident[4]) {
105
+	case 1:
106
+	    cli_dbgmsg("ELF: ELF class 1 (32-bit)\n");
107
+	    format64 = 0;
108
+	    break;
109
+        case 2:
110
+	    cli_dbgmsg("ELF: ELF class 2 (64-bit)\n");
111
+	    format64 = 1;
112
+	    break;
113
+        default:
114
+	    cli_dbgmsg("ELF: Unknown ELF class (%u)\n", file_hdr->hdr64.e_ident[4]);
115
+	    return CL_EFORMAT;
95 116
     }
96 117
 
97
-    if(format == 2) {
98
-	    struct elf_file_hdr64 file_hdr64;
99
-	if(fmap_readn(map, &file_hdr64, 0, sizeof(file_hdr64)) != sizeof(file_hdr64)) {
100
-	    /* Not an ELF file? */
101
-	    cli_dbgmsg("ELF: Can't read file header\n");
102
-	    return CL_CLEAN;
103
-	}
104
-	/* it's enough for us to handle ELF64 as 32 */
105
-	file_hdr.e_entry = file_hdr64.e_entry;
106
-        file_hdr.e_phoff = file_hdr64.e_phoff;
107
-        file_hdr.e_shoff = file_hdr64.e_shoff;
108
-	file_hdr.e_flags = file_hdr64.e_flags;
109
-	file_hdr.e_ehsize = file_hdr64.e_ehsize;
110
-	file_hdr.e_phentsize = file_hdr64.e_phentsize;
111
-	if(file_hdr.e_phentsize == sizeof(struct elf_program_hdr64))
112
-	    file_hdr.e_phentsize = sizeof(struct elf_program_hdr32);
113
-	file_hdr.e_phnum = file_hdr64.e_phnum;
114
-	file_hdr.e_shentsize = file_hdr64.e_shentsize;
115
-	if(file_hdr.e_shentsize == sizeof(struct elf_section_hdr64))
116
-	    file_hdr.e_shentsize = sizeof(struct elf_section_hdr32);
117
-	file_hdr.e_shnum = file_hdr64.e_shnum;
118
-	file_hdr.e_shstrndx = file_hdr64.e_shstrndx;
119
-    }
120
-
121
-    if(file_hdr.e_ident[5] == 1) {
118
+    /* Need to know to endian convert */
119
+    if(file_hdr->hdr64.e_ident[5] == 1) {
122 120
 #if WORDS_BIGENDIAN == 0
123
-	cli_dbgmsg("ELF: File is little-endian - conversion not required\n");
121
+	if(ctx)
122
+            cli_dbgmsg("ELF: File is little-endian - conversion not required\n");
123
+	conv = 0;
124 124
 #else
125
-	cli_dbgmsg("ELF: File is little-endian - data conversion enabled\n");
125
+	if(ctx)
126
+            cli_dbgmsg("ELF: File is little-endian - data conversion enabled\n");
126 127
 	conv = 1;
127 128
 #endif
128 129
     } else {
129 130
 #if WORDS_BIGENDIAN == 0
130
-	cli_dbgmsg("ELF: File is big-endian - data conversion enabled\n");
131
+	if(ctx)
132
+            cli_dbgmsg("ELF: File is big-endian - data conversion enabled\n");
131 133
 	conv = 1;
132 134
 #else
133
-	cli_dbgmsg("ELF: File is big-endian - conversion not required\n");
135
+	if(ctx)
136
+            cli_dbgmsg("ELF: File is big-endian - conversion not required\n");
137
+	conv = 0;
134 138
 #endif
135 139
     }
136 140
 
137
-    switch(EC16(file_hdr.e_type, conv)) {
141
+    *do_convert = conv;
142
+    *is64 = format64;
143
+
144
+    /* Solve bit-size and conversion pronto */
145
+    file_hdr->hdr64.e_type = EC16(file_hdr->hdr64.e_type, conv);
146
+    file_hdr->hdr64.e_machine = EC16(file_hdr->hdr64.e_machine, conv);
147
+    file_hdr->hdr64.e_version = EC32(file_hdr->hdr64.e_version, conv);
148
+
149
+    if(format64) {
150
+	/* Read rest of 64-bit header */
151
+	if(fmap_readn(map, file_hdr->hdr32.pad, sizeof(struct elf_file_hdr32), ELF_HDR_SIZEDIFF)
152
+                != ELF_HDR_SIZEDIFF) {
153
+	    /* Not an ELF file? */
154
+	    cli_dbgmsg("ELF: Can't read file header\n");
155
+	    return CL_BREAK;
156
+	}
157
+	/* Now endian convert, if needed */
158
+	if(conv) {
159
+	    file_hdr->hdr64.e_entry = EC64(file_hdr->hdr64.e_entry, conv);
160
+            file_hdr->hdr64.e_phoff = EC64(file_hdr->hdr64.e_phoff, conv);
161
+            file_hdr->hdr64.e_shoff = EC64(file_hdr->hdr64.e_shoff, conv);
162
+	    file_hdr->hdr64.e_flags = EC32(file_hdr->hdr64.e_flags, conv);
163
+	    file_hdr->hdr64.e_ehsize = EC16(file_hdr->hdr64.e_ehsize, conv);
164
+	    file_hdr->hdr64.e_phentsize = EC16(file_hdr->hdr64.e_phentsize, conv);
165
+	    file_hdr->hdr64.e_phnum = EC16(file_hdr->hdr64.e_phnum, conv);
166
+	    file_hdr->hdr64.e_shentsize = EC16(file_hdr->hdr64.e_shentsize, conv);
167
+	    file_hdr->hdr64.e_shnum = EC16(file_hdr->hdr64.e_shnum, conv);
168
+	    file_hdr->hdr64.e_shstrndx = EC16(file_hdr->hdr64.e_shstrndx, conv);
169
+	}
170
+    }
171
+    else {
172
+	/* Convert 32-bit structure, if needed */
173
+	if(conv) {
174
+	    file_hdr->hdr32.hdr.e_entry = EC32(file_hdr->hdr32.hdr.e_entry, conv);
175
+            file_hdr->hdr32.hdr.e_phoff = EC32(file_hdr->hdr32.hdr.e_phoff, conv);
176
+            file_hdr->hdr32.hdr.e_shoff = EC32(file_hdr->hdr32.hdr.e_shoff, conv);
177
+	    file_hdr->hdr32.hdr.e_flags = EC32(file_hdr->hdr32.hdr.e_flags, conv);
178
+	    file_hdr->hdr32.hdr.e_ehsize = EC16(file_hdr->hdr32.hdr.e_ehsize, conv);
179
+	    file_hdr->hdr32.hdr.e_phentsize = EC16(file_hdr->hdr32.hdr.e_phentsize, conv);
180
+	    file_hdr->hdr32.hdr.e_phnum = EC16(file_hdr->hdr32.hdr.e_phnum, conv);
181
+	    file_hdr->hdr32.hdr.e_shentsize = EC16(file_hdr->hdr32.hdr.e_shentsize, conv);
182
+	    file_hdr->hdr32.hdr.e_shnum = EC16(file_hdr->hdr32.hdr.e_shnum, conv);
183
+	    file_hdr->hdr32.hdr.e_shstrndx = EC16(file_hdr->hdr32.hdr.e_shstrndx, conv);
184
+        }
185
+        /* Wipe pad for safety */
186
+        memset(file_hdr->hdr32.pad, 0, ELF_HDR_SIZEDIFF);
187
+    }
188
+
189
+    return CL_CLEAN;
190
+}
191
+
192
+/* Read 32-bit program headers */
193
+static int cli_elf_ph32(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
194
+    struct elf_file_hdr32 *file_hdr, uint8_t conv)
195
+{
196
+	struct elf_program_hdr32 *program_hdr = NULL;
197
+	uint16_t phnum, phentsize;
198
+	uint32_t entry, fentry, phoff;
199
+	uint32_t i;
200
+	uint8_t err;
201
+
202
+    /* Program headers and Entry */
203
+    phnum = file_hdr->e_phnum;
204
+    cli_dbgmsg("ELF: Number of program headers: %d\n", phnum);
205
+    if(phnum > 128) {
206
+        cli_dbgmsg("ELF: Suspicious number of program headers\n");
207
+        if(ctx && DETECT_BROKEN) {
208
+            cli_append_virus(ctx, "Heuristics.Broken.Executable");
209
+            return CL_VIRUS;
210
+        }
211
+        return CL_EFORMAT;
212
+    }
213
+    entry = file_hdr->e_entry;
214
+
215
+    if(phnum && entry) {
216
+        phentsize = file_hdr->e_phentsize;
217
+        /* Sanity check */
218
+        if(phentsize != sizeof(struct elf_program_hdr32)) {
219
+            cli_dbgmsg("ELF: phentsize != sizeof(struct elf_program_hdr32)\n");
220
+            if(ctx && DETECT_BROKEN) {
221
+                cli_append_virus(ctx, "Heuristics.Broken.Executable");
222
+                return CL_VIRUS;
223
+            }
224
+            return CL_EFORMAT;
225
+        }
226
+
227
+        phoff = file_hdr->e_phoff;
228
+        if(ctx) {
229
+            cli_dbgmsg("ELF: Program header table offset: %d\n", phoff);
230
+        }
231
+
232
+        if(phnum) {
233
+            program_hdr = (struct elf_program_hdr32 *) cli_calloc(phnum, sizeof(struct elf_program_hdr32));
234
+            if(!program_hdr) {
235
+                cli_errmsg("ELF: Can't allocate memory for program headers\n");
236
+                return CL_EMEM;
237
+            }
238
+            if(ctx) {
239
+                cli_dbgmsg("------------------------------------\n");
240
+            }
241
+        }
242
+
243
+        for(i = 0; i < phnum; i++) {
244
+            err = 0;
245
+            if(fmap_readn(map, &program_hdr[i], phoff, sizeof(struct elf_program_hdr32)) != sizeof(struct elf_program_hdr32))
246
+                err = 1;
247
+            phoff += sizeof(struct elf_program_hdr32);
248
+
249
+            if(err) {
250
+                cli_dbgmsg("ELF: Can't read segment #%d\n", i);
251
+                if(ctx) {
252
+                    cli_dbgmsg("ELF: Possibly broken ELF file\n");
253
+                }
254
+                free(program_hdr);
255
+                if(ctx && DETECT_BROKEN) {
256
+                    cli_append_virus(ctx, "Heuristics.Broken.Executable");
257
+                    return CL_VIRUS;
258
+                }
259
+                return CL_BREAK;
260
+            }
261
+
262
+            if(ctx) {
263
+                cli_dbgmsg("ELF: Segment #%d\n", i);
264
+                cli_dbgmsg("ELF: Segment type: 0x%x\n", EC32(program_hdr[i].p_type, conv));
265
+                cli_dbgmsg("ELF: Segment offset: 0x%x\n", EC32(program_hdr[i].p_offset, conv));
266
+                cli_dbgmsg("ELF: Segment virtual address: 0x%x\n", EC32(program_hdr[i].p_vaddr, conv));
267
+                cli_dbgmsg("ELF: Segment real size: 0x%x\n", EC32(program_hdr[i].p_filesz, conv));
268
+                cli_dbgmsg("ELF: Segment virtual size: 0x%x\n", EC32(program_hdr[i].p_memsz, conv));
269
+                cli_dbgmsg("------------------------------------\n");
270
+            }
271
+        }
272
+
273
+        fentry = cli_rawaddr32(entry, program_hdr, phnum, conv, &err);
274
+        free(program_hdr);
275
+        if(err) {
276
+            cli_dbgmsg("ELF: Can't calculate file offset of entry point\n");
277
+            if(ctx && DETECT_BROKEN) {
278
+                cli_append_virus(ctx, "Heuristics.Broken.Executable");
279
+                return CL_VIRUS;
280
+            }
281
+            return CL_EFORMAT;
282
+        }
283
+        if(ctx) {
284
+            cli_dbgmsg("ELF: Entry point address: 0x%.8x\n", entry);
285
+            cli_dbgmsg("ELF: Entry point offset: 0x%.8x (%d)\n", fentry, fentry);
286
+        }
287
+    }
288
+
289
+    if(elfinfo) {
290
+        elfinfo->ep = fentry;
291
+    }
292
+
293
+    return CL_CLEAN;
294
+}
295
+
296
+/* Read 64-bit program headers */
297
+static int cli_elf_ph64(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
298
+    struct elf_file_hdr64 *file_hdr, uint8_t conv)
299
+{
300
+	struct elf_program_hdr64 *program_hdr = NULL;
301
+	uint16_t phnum, phentsize;
302
+	uint64_t entry, fentry, phoff;
303
+	uint32_t i;
304
+	uint8_t err;
305
+
306
+    /* Program headers and Entry */
307
+    phnum = file_hdr->e_phnum;
308
+    cli_dbgmsg("ELF: Number of program headers: %d\n", phnum);
309
+    if(phnum > 128) {
310
+        cli_dbgmsg("ELF: Suspicious number of program headers\n");
311
+        if(ctx && DETECT_BROKEN) {
312
+            cli_append_virus(ctx, "Heuristics.Broken.Executable");
313
+            return CL_VIRUS;
314
+        }
315
+        return CL_EFORMAT;
316
+    }
317
+    entry = file_hdr->e_entry;
318
+
319
+    if(phnum && entry) {
320
+        phentsize = file_hdr->e_phentsize;
321
+        /* Sanity check */
322
+        if (phentsize != sizeof(struct elf_program_hdr64)) {
323
+            cli_dbgmsg("ELF: phentsize != sizeof(struct elf_program_hdr64)\n");
324
+            if(ctx && DETECT_BROKEN) {
325
+                cli_append_virus(ctx, "Heuristics.Broken.Executable");
326
+                return CL_VIRUS;
327
+            }
328
+            return CL_EFORMAT;
329
+        }
330
+
331
+        phoff = file_hdr->e_phoff;
332
+        if(ctx) {
333
+            cli_dbgmsg("ELF: Program header table offset: %d\n", phoff);
334
+        }
335
+
336
+        if(phnum) {
337
+            program_hdr = (struct elf_program_hdr64 *) cli_calloc(phnum, sizeof(struct elf_program_hdr64));
338
+            if(!program_hdr) {
339
+                cli_errmsg("ELF: Can't allocate memory for program headers\n");
340
+                return CL_EMEM;
341
+            }
342
+            if(ctx) {
343
+                cli_dbgmsg("------------------------------------\n");
344
+            }
345
+        }
346
+
347
+        for(i = 0; i < phnum; i++) {
348
+            err = 0;
349
+            if(fmap_readn(map, &program_hdr[i], phoff, sizeof(struct elf_program_hdr64)) != sizeof(struct elf_program_hdr64))
350
+                err = 1;
351
+            phoff += sizeof(struct elf_program_hdr64);
352
+
353
+            if(err) {
354
+                cli_dbgmsg("ELF: Can't read segment #%d\n", i);
355
+                if(ctx) {
356
+                    cli_dbgmsg("ELF: Possibly broken ELF file\n");
357
+                }
358
+                free(program_hdr);
359
+                if(ctx && DETECT_BROKEN) {
360
+                    cli_append_virus(ctx, "Heuristics.Broken.Executable");
361
+                    return CL_VIRUS;
362
+                }
363
+                return CL_BREAK;
364
+            }
365
+
366
+            if(ctx) {
367
+                cli_dbgmsg("ELF: Segment #%d\n", i);
368
+                cli_dbgmsg("ELF: Segment type: 0x%x\n", EC32(program_hdr[i].p_type, conv));
369
+                cli_dbgmsg("ELF: Segment offset: 0x%x\n", EC64(program_hdr[i].p_offset, conv));
370
+                cli_dbgmsg("ELF: Segment virtual address: 0x%x\n", EC64(program_hdr[i].p_vaddr, conv));
371
+                cli_dbgmsg("ELF: Segment real size: 0x%x\n", EC64(program_hdr[i].p_filesz, conv));
372
+                cli_dbgmsg("ELF: Segment virtual size: 0x%x\n", EC64(program_hdr[i].p_memsz, conv));
373
+                cli_dbgmsg("------------------------------------\n");
374
+            }
375
+        }
376
+
377
+        fentry = cli_rawaddr64(entry, program_hdr, phnum, conv, &err);
378
+        free(program_hdr);
379
+        if(err) {
380
+            cli_dbgmsg("ELF: Can't calculate file offset of entry point\n");
381
+            if(ctx && DETECT_BROKEN) {
382
+                cli_append_virus(ctx, "Heuristics.Broken.Executable");
383
+                return CL_VIRUS;
384
+            }
385
+            return CL_EFORMAT;
386
+        }
387
+        if(ctx) {
388
+            cli_dbgmsg("ELF: Entry point address: 0x%.16x\n", entry);
389
+            cli_dbgmsg("ELF: Entry point offset: 0x%.16x (%d)\n", fentry, fentry);
390
+        }
391
+    }
392
+
393
+    if(elfinfo) {
394
+        elfinfo->ep = fentry;
395
+    }
396
+
397
+    return CL_CLEAN;
398
+}
399
+
400
+/* 32-bit version of section header parsing */
401
+static int cli_elf_sh32(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
402
+    struct elf_file_hdr32 *file_hdr, uint8_t conv)
403
+{
404
+	struct elf_section_hdr32 *section_hdr = NULL;
405
+	uint16_t shnum, shentsize;
406
+	uint32_t shoff, i;
407
+
408
+    shnum = file_hdr->e_shnum;
409
+    cli_dbgmsg("ELF: Number of sections: %d\n", shnum);
410
+    if(ctx && (shnum > 2048)) {
411
+	cli_dbgmsg("ELF: Number of sections > 2048, skipping\n");
412
+	return CL_BREAK;
413
+    }
414
+    else if(elfinfo && (shnum > 256)) {
415
+	cli_dbgmsg("ELF: Suspicious number of sections\n");
416
+	return CL_BREAK;
417
+    }
418
+    if(elfinfo) {
419
+        elfinfo->nsections = shnum;
420
+    }
421
+
422
+    shentsize = file_hdr->e_shentsize;
423
+    /* Sanity check */
424
+    if(shentsize != sizeof(struct elf_section_hdr32)) {
425
+	cli_dbgmsg("ELF: shentsize != sizeof(struct elf_section_hdr32)\n");
426
+        if(ctx && DETECT_BROKEN) {
427
+	    cli_append_virus(ctx, "Heuristics.Broken.Executable");
428
+	    return CL_VIRUS;
429
+        }
430
+	return CL_EFORMAT;
431
+    }
432
+
433
+    if(elfinfo && !shnum) {
434
+        return CL_CLEAN;
435
+    }
436
+
437
+    shoff = file_hdr->e_shoff;
438
+    if(ctx)
439
+        cli_dbgmsg("ELF: Section header table offset: %d\n", shoff);
440
+
441
+    if(elfinfo) {
442
+        elfinfo->section = (struct cli_exe_section *)cli_calloc(shnum, sizeof(struct cli_exe_section));
443
+        if(!elfinfo->section) {
444
+            cli_dbgmsg("ELF: Can't allocate memory for section headers\n");
445
+            return CL_EMEM;
446
+        }
447
+    }
448
+
449
+    if(shnum) {
450
+	section_hdr = (struct elf_section_hdr32 *) cli_calloc(shnum, shentsize);
451
+	if(!section_hdr) {
452
+	    cli_errmsg("ELF: Can't allocate memory for section headers\n");
453
+	    if(elfinfo) {
454
+                free(elfinfo->section);
455
+                elfinfo->section = NULL;
456
+	    }
457
+	    return CL_EMEM;
458
+	}
459
+	if(ctx) {
460
+            cli_dbgmsg("------------------------------------\n");
461
+	}
462
+    }
463
+
464
+    /* Loop over section headers */
465
+    for(i = 0; i < shnum; i++) {
466
+        uint32_t sh_type, sh_flags;
467
+
468
+	if(fmap_readn(map, &section_hdr[i], shoff, sizeof(struct elf_section_hdr32)) != sizeof(struct elf_section_hdr32)) {
469
+            cli_dbgmsg("ELF: Can't read section header\n");
470
+            if(ctx) {
471
+                cli_dbgmsg("ELF: Possibly broken ELF file\n");
472
+            }
473
+            free(section_hdr);
474
+            if(elfinfo) {
475
+                free(elfinfo->section);
476
+                elfinfo->section = NULL;
477
+	    }
478
+            if(ctx && DETECT_BROKEN) {
479
+                cli_append_virus(ctx, "Heuristics.Broken.Executable");
480
+		return CL_VIRUS;
481
+            }
482
+            return CL_BREAK;
483
+        }
484
+
485
+	shoff += sizeof(struct elf_section_hdr32);
486
+
487
+        if(elfinfo) {
488
+            elfinfo->section[i].rva = EC32(section_hdr[i].sh_addr, conv);
489
+            elfinfo->section[i].raw = EC32(section_hdr[i].sh_offset, conv);
490
+            elfinfo->section[i].rsz = EC32(section_hdr[i].sh_size, conv);
491
+        }
492
+        if(ctx) {
493
+	    cli_dbgmsg("ELF: Section %u\n", i);
494
+	    cli_dbgmsg("ELF: Section offset: %u\n", EC32(section_hdr[i].sh_offset, conv));
495
+	    cli_dbgmsg("ELF: Section size: %u\n", EC32(section_hdr[i].sh_size, conv));
496
+
497
+            sh_type = EC32(section_hdr[i].sh_type, conv);
498
+            sh_flags = EC32(section_hdr[i].sh_flags, conv) & ELF_SHF_MASK;
499
+            cli_elf_sectionlog(sh_type, sh_flags);
500
+
501
+	    cli_dbgmsg("------------------------------------\n");
502
+        }
503
+    }
504
+
505
+    free(section_hdr);
506
+    return CL_CLEAN;
507
+}
508
+
509
+/* 64-bit version of section header parsing */
510
+static int cli_elf_sh64(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
511
+    struct elf_file_hdr64 *file_hdr, uint8_t conv)
512
+{
513
+	struct elf_section_hdr64 *section_hdr = NULL;
514
+	uint16_t shnum, shentsize;
515
+	uint32_t i;
516
+	uint64_t shoff;
517
+
518
+    shnum = file_hdr->e_shnum;
519
+    cli_dbgmsg("ELF: Number of sections: %d\n", shnum);
520
+    if(ctx && (shnum > 2048)) {
521
+	cli_dbgmsg("ELF: Number of sections > 2048, skipping\n");
522
+	return CL_BREAK;
523
+    }
524
+    else if(elfinfo && (shnum > 256)) {
525
+	cli_dbgmsg("ELF: Suspicious number of sections\n");
526
+	return CL_BREAK;
527
+    }
528
+    if(elfinfo) {
529
+        elfinfo->nsections = shnum;
530
+    }
531
+
532
+    shentsize = file_hdr->e_shentsize;
533
+    /* Sanity check */
534
+    if(shentsize != sizeof(struct elf_section_hdr64)) {
535
+	cli_dbgmsg("ELF: shentsize != sizeof(struct elf_section_hdr64)\n");
536
+        if(ctx && DETECT_BROKEN) {
537
+	    cli_append_virus(ctx, "Heuristics.Broken.Executable");
538
+	    return CL_VIRUS;
539
+        }
540
+	return CL_EFORMAT;
541
+    }
542
+
543
+    if(elfinfo && !shnum) {
544
+        return CL_CLEAN;
545
+    }
546
+
547
+    shoff = file_hdr->e_shoff;
548
+    if(ctx)
549
+        cli_dbgmsg("ELF: Section header table offset: %d\n", shoff);
550
+
551
+    if(elfinfo) {
552
+        elfinfo->section = (struct cli_exe_section *)cli_calloc(shnum, sizeof(struct cli_exe_section));
553
+        if(!elfinfo->section) {
554
+            cli_dbgmsg("ELF: Can't allocate memory for section headers\n");
555
+            return CL_EMEM;
556
+        }
557
+    }
558
+
559
+    if(shnum) {
560
+	section_hdr = (struct elf_section_hdr64 *) cli_calloc(shnum, shentsize);
561
+	if(!section_hdr) {
562
+	    cli_errmsg("ELF: Can't allocate memory for section headers\n");
563
+	    if(elfinfo) {
564
+                free(elfinfo->section);
565
+                elfinfo->section = NULL;
566
+	    }
567
+	    return CL_EMEM;
568
+	}
569
+	if(ctx) {
570
+            cli_dbgmsg("------------------------------------\n");
571
+	}
572
+    }
573
+
574
+    /* Loop over section headers */
575
+    for(i = 0; i < shnum; i++) {
576
+        uint32_t sh_type, sh_flags;
577
+
578
+	if(fmap_readn(map, &section_hdr[i], shoff, sizeof(struct elf_section_hdr64)) != sizeof(struct elf_section_hdr64)) {
579
+            cli_dbgmsg("ELF: Can't read section header\n");
580
+            if(ctx) {
581
+                cli_dbgmsg("ELF: Possibly broken ELF file\n");
582
+            }
583
+            free(section_hdr);
584
+            if(elfinfo) {
585
+                free(elfinfo->section);
586
+                elfinfo->section = NULL;
587
+	    }
588
+            if(ctx && DETECT_BROKEN) {
589
+                cli_append_virus(ctx, "Heuristics.Broken.Executable");
590
+		return CL_VIRUS;
591
+            }
592
+            return CL_BREAK;
593
+        }
594
+
595
+	shoff += sizeof(struct elf_section_hdr64);
596
+
597
+        if(elfinfo) {
598
+            elfinfo->section[i].rva = EC64(section_hdr[i].sh_addr, conv);
599
+            elfinfo->section[i].raw = EC64(section_hdr[i].sh_offset, conv);
600
+            elfinfo->section[i].rsz = EC64(section_hdr[i].sh_size, conv);
601
+        }
602
+        if(ctx) {
603
+	    cli_dbgmsg("ELF: Section %u\n", i);
604
+	    cli_dbgmsg("ELF: Section offset: %u\n", EC64(section_hdr[i].sh_offset, conv));
605
+	    cli_dbgmsg("ELF: Section size: %u\n", EC64(section_hdr[i].sh_size, conv));
606
+
607
+            sh_type = EC32(section_hdr[i].sh_type, conv);
608
+            sh_flags = (uint32_t)(EC64(section_hdr[i].sh_flags, conv) & ELF_SHF_MASK);
609
+            cli_elf_sectionlog(sh_type, sh_flags);
610
+
611
+	    cli_dbgmsg("------------------------------------\n");
612
+        }
613
+    }
614
+
615
+    free(section_hdr);
616
+    return CL_CLEAN;
617
+}
618
+
619
+/* Print section type and selected flags to the log */
620
+static void cli_elf_sectionlog(uint32_t sh_type, uint32_t sh_flags)
621
+{
622
+    switch(sh_type) {
623
+        case 0x6: /* SHT_DYNAMIC */
624
+            cli_dbgmsg("ELF: Section type: Dynamic linking information\n");
625
+            break;
626
+        case 0xb: /* SHT_DYNSYM */
627
+            cli_dbgmsg("ELF: Section type: Symbols for dynamic linking\n");
628
+            break;
629
+        case 0xf: /* SHT_FINI_ARRAY */
630
+            cli_dbgmsg("ELF: Section type: Array of pointers to termination functions\n");
631
+            break;
632
+        case 0x5: /* SHT_HASH */
633
+            cli_dbgmsg("ELF: Section type: Symbol hash table\n");
634
+            break;
635
+        case 0xe: /* SHT_INIT_ARRAY */
636
+            cli_dbgmsg("ELF: Section type: Array of pointers to initialization functions\n");
637
+            break;
638
+        case 0x8: /* SHT_NOBITS */
639
+            cli_dbgmsg("ELF: Section type: Empty section (NOBITS)\n");
640
+            break;
641
+        case 0x7: /* SHT_NOTE */
642
+            cli_dbgmsg("ELF: Section type: Note section\n");
643
+            break;
644
+        case 0x0: /* SHT_NULL */
645
+            cli_dbgmsg("ELF: Section type: Null (no associated section)\n");
646
+            break;
647
+        case 0x10: /* SHT_PREINIT_ARRAY */
648
+            cli_dbgmsg("ELF: Section type: Array of pointers to preinit functions\n");
649
+            break;
650
+        case 0x1: /* SHT_PROGBITS */
651
+            cli_dbgmsg("ELF: Section type: Program information\n");
652
+            break;
653
+        case 0x9: /* SHT_REL */
654
+            cli_dbgmsg("ELF: Section type: Relocation entries w/o explicit addends\n");
655
+            break;
656
+        case 0x4: /* SHT_RELA */
657
+            cli_dbgmsg("ELF: Section type: Relocation entries with explicit addends\n");
658
+            break;
659
+        case 0x3: /* SHT_STRTAB */
660
+            cli_dbgmsg("ELF: Section type: String table\n");
661
+            break;
662
+        case 0x2: /* SHT_SYMTAB */
663
+            cli_dbgmsg("ELF: Section type: Symbol table\n");
664
+            break;
665
+        case 0x6ffffffd: /* SHT_GNU_verdef */
666
+            cli_dbgmsg("ELF: Section type: Provided symbol versions\n");
667
+            break;
668
+        case 0x6ffffffe: /* SHT_GNU_verneed */
669
+            cli_dbgmsg("ELF: Section type: Required symbol versions\n");
670
+            break;
671
+        case 0x6fffffff: /* SHT_GNU_versym */
672
+            cli_dbgmsg("ELF: Section type: Symbol Version Table\n");
673
+            break;
674
+        default :
675
+            cli_dbgmsg("ELF: Section type: Unknown\n");
676
+    }
677
+
678
+    if(sh_flags & ELF_SHF_WRITE)
679
+        cli_dbgmsg("ELF: Section contains writable data\n");
680
+
681
+    if(sh_flags & ELF_SHF_ALLOC)
682
+        cli_dbgmsg("ELF: Section occupies memory\n");
683
+
684
+    if(sh_flags & ELF_SHF_EXECINSTR)
685
+        cli_dbgmsg("ELF: Section contains executable code\n");
686
+}
687
+
688
+/* Scan function for ELF */
689
+int cli_scanelf(cli_ctx *ctx)
690
+{
691
+	union elf_file_hdr file_hdr;
692
+	fmap_t *map = *ctx->fmap;
693
+	int ret;
694
+	uint8_t conv = 0, is64 = 0;
695
+
696
+    cli_dbgmsg("in cli_scanelf\n");
697
+
698
+    /* Load header to determine size and class */
699
+    ret = cli_elf_fileheader(ctx, map, &file_hdr, &conv, &is64);
700
+    if(ret == CL_BREAK) {
701
+	return CL_CLEAN; /* here, break means "exit but report clean" */
702
+    }
703
+    else if(ret != CL_CLEAN) {
704
+	return ret;
705
+    }
706
+
707
+    /* Log File type and machine type */
708
+    switch(file_hdr.hdr64.e_type) {
138 709
 	case 0x0: /* ET_NONE */
139 710
 	    cli_dbgmsg("ELF: File type: None\n");
140 711
 	    break;
... ...
@@ -151,10 +724,10 @@ int cli_scanelf(cli_ctx *ctx)
151 151
 	    cli_dbgmsg("ELF: File type: Core\n");
152 152
 	    break;
153 153
 	default:
154
-	    cli_dbgmsg("ELF: File type: Unknown (%d)\n", EC16(file_hdr.e_type, conv));
154
+	    cli_dbgmsg("ELF: File type: Unknown (%d)\n", file_hdr.hdr64.e_type);
155 155
     }
156 156
 
157
-    switch(EC16(file_hdr.e_machine, conv)) {
157
+    switch(file_hdr.hdr64.e_machine) {
158 158
 	/* Due to a huge list, we only include the most popular machines here */
159 159
 	case 0: /* EM_NONE */
160 160
 	    cli_dbgmsg("ELF: Machine type: None\n");
... ...
@@ -202,448 +775,81 @@ int cli_scanelf(cli_ctx *ctx)
202 202
 	    cli_dbgmsg("ELF: Machine type: AMD x86-64\n");
203 203
 	    break;
204 204
 	default:
205
-	    cli_dbgmsg("ELF: Machine type: Unknown (0x%x)\n", EC16(file_hdr.e_machine, conv));
205
+	    cli_dbgmsg("ELF: Machine type: Unknown (0x%x)\n", file_hdr.hdr64.e_machine);
206 206
     }
207 207
 
208
-    entry = EC32(file_hdr.e_entry, conv);
209
-
210
-    /* Program headers */
211
-
212
-    phnum = EC16(file_hdr.e_phnum, conv);
213
-    cli_dbgmsg("ELF: Number of program headers: %d\n", phnum);
214
-    if(phnum > 128) {
215
-	cli_dbgmsg("ELF: Suspicious number of program headers\n");
216
-        if(DETECT_BROKEN) {
217
-	    cli_append_virus(ctx, "Heuristics.Broken.Executable");
218
-	    return CL_VIRUS;
219
-        }
220
-	return CL_EFORMAT;
208
+    /* Program headers and Entry */
209
+    if(is64) {
210
+        ret = cli_elf_ph64(ctx, map, NULL, &(file_hdr.hdr64), conv);
221 211
     }
222
-
223
-    if(phnum && entry) {
224
-
225
-	phentsize = EC16(file_hdr.e_phentsize, conv);
226
-	if(phentsize != sizeof(struct elf_program_hdr32)) {
227
-	    cli_dbgmsg("ELF: phentsize != sizeof(struct elf_program_hdr32)\n");
228
-	    if(DETECT_BROKEN) {
229
-		cli_append_virus(ctx, "Heuristics.Broken.Executable");
230
-		return CL_VIRUS;
231
-	    }
232
-	    return CL_EFORMAT;
233
-	}
234
-
235
-	phoff = EC32(file_hdr.e_phoff, conv);
236
-	cli_dbgmsg("ELF: Program header table offset: %d\n", phoff);
237
-
238
-	if(phnum) {
239
-	    program_hdr = (struct elf_program_hdr32 *) cli_calloc(phnum, phentsize);
240
-	    if(!program_hdr) {
241
-		cli_errmsg("ELF: Can't allocate memory for program headers\n");
242
-		return CL_EMEM;
243
-	    }
244
-	    cli_dbgmsg("------------------------------------\n");
245
-	}
246
-
247
-	for(i = 0; i < phnum; i++) {
248
-	    err = 0;
249
-	    if(format == 1) {
250
-		if(fmap_readn(map, &program_hdr[i], phoff, sizeof(struct elf_program_hdr32)) != sizeof(struct elf_program_hdr32))
251
-		    err = 1;
252
-		phoff += sizeof(struct elf_program_hdr32);
253
-	    } else {
254
-		    struct elf_program_hdr64 program_hdr64;
255
-
256
-		if(fmap_readn(map, &program_hdr64, phoff, sizeof(program_hdr64)) != sizeof(program_hdr64)) {
257
-		    err = 1;
258
-		} else {
259
-		    program_hdr[i].p_type = program_hdr64.p_type;
260
-		    program_hdr[i].p_offset = program_hdr64.p_offset;
261
-		    program_hdr[i].p_vaddr = program_hdr64.p_vaddr;
262
-		    program_hdr[i].p_paddr = program_hdr64.p_paddr;
263
-		    program_hdr[i].p_filesz = program_hdr64.p_filesz;
264
-		    program_hdr[i].p_memsz = program_hdr64.p_memsz;
265
-		    program_hdr[i].p_flags = program_hdr64.p_flags;
266
-		    program_hdr[i].p_align = program_hdr64.p_align;
267
-		}
268
-		phoff += sizeof(program_hdr64);
269
-	    }
270
-
271
-	    if(err) {
272
-		cli_dbgmsg("ELF: Can't read segment #%d\n", i);
273
-		cli_dbgmsg("ELF: Possibly broken ELF file\n");
274
-		free(program_hdr);
275
-		if(DETECT_BROKEN) {
276
-		    cli_append_virus(ctx, "Heuristics.Broken.Executable");
277
-		    return CL_VIRUS;
278
-		}
279
-		return CL_CLEAN;
280
-	    }
281
-
282
-	    cli_dbgmsg("ELF: Segment #%d\n", i);
283
-	    cli_dbgmsg("ELF: Segment type: 0x%x\n", EC32(program_hdr[i].p_type, conv));
284
-	    cli_dbgmsg("ELF: Segment offset: 0x%x\n", EC32(program_hdr[i].p_offset, conv));
285
-	    cli_dbgmsg("ELF: Segment virtual address: 0x%x\n", EC32(program_hdr[i].p_vaddr, conv));
286
-	    cli_dbgmsg("ELF: Segment real size: 0x%x\n", EC32(program_hdr[i].p_filesz, conv));
287
-	    cli_dbgmsg("ELF: Segment virtual size: 0x%x\n", EC32(program_hdr[i].p_memsz, conv));
288
-	    cli_dbgmsg("------------------------------------\n");
289
-	}
290
-
291
-	fentry = cli_rawaddr(entry, program_hdr, phnum, conv, &err);
292
-	free(program_hdr);
293
-	if(err) {
294
-	    cli_dbgmsg("ELF: Can't calculate file offset of entry point\n");
295
-	    if(DETECT_BROKEN) {
296
-                cli_append_virus(ctx, "Heuristics.Broken.Executable");
297
-		return CL_VIRUS;
298
-	    }
299
-	    return CL_EFORMAT;
300
-	}
301
-	cli_dbgmsg("ELF: Entry point address: 0x%.8x\n", entry);
302
-	cli_dbgmsg("ELF: Entry point offset: 0x%.8x (%d)\n", fentry, fentry);
212
+    else {
213
+        ret = cli_elf_ph32(ctx, map, NULL, &(file_hdr.hdr32.hdr), conv);
214
+    }
215
+    if(ret == CL_BREAK) {
216
+	return CL_CLEAN; /* break means "exit but report clean" */
217
+    }
218
+    else if(ret != CL_CLEAN) {
219
+	return ret;
303 220
     }
304 221
 
305 222
     /* Sections */
306
-
307
-    shnum = EC16(file_hdr.e_shnum, conv);
308
-    cli_dbgmsg("ELF: Number of sections: %d\n", shnum);
309
-    if(shnum > 2048) {
310
-	cli_dbgmsg("ELF: Number of sections > 2048, skipping\n");
311
-	return CL_CLEAN;
223
+    if(is64) {
224
+        ret = cli_elf_sh64(ctx, map, NULL, &(file_hdr.hdr64), conv);
312 225
     }
313
-
314
-    shentsize = EC16(file_hdr.e_shentsize, conv);
315
-    if(shentsize != sizeof(struct elf_section_hdr32)) {
316
-	cli_dbgmsg("ELF: shentsize != sizeof(struct elf_section_hdr32)\n");
317
-        if(DETECT_BROKEN) {
318
-	    cli_append_virus(ctx, "Heuristics.Broken.Executable");
319
-	    return CL_VIRUS;
320
-        }
321
-	return CL_EFORMAT;
226
+    else {
227
+        ret = cli_elf_sh32(ctx, map, NULL, &(file_hdr.hdr32.hdr), conv);
322 228
     }
323
-
324
-    shoff = EC32(file_hdr.e_shoff, conv);
325
-    cli_dbgmsg("ELF: Section header table offset: %d\n", shoff);
326
-
327
-    if(shnum) {
328
-	section_hdr = (struct elf_section_hdr32 *) cli_calloc(shnum, shentsize);
329
-	if(!section_hdr) {
330
-	    cli_errmsg("ELF: Can't allocate memory for section headers\n");
331
-	    return CL_EMEM;
332
-	}
333
-	cli_dbgmsg("------------------------------------\n");
229
+    if(ret == CL_BREAK) {
230
+	return CL_CLEAN; /* break means "exit but report clean" */
334 231
     }
335
-
336
-    for(i = 0; i < shnum; i++) {
337
-	err = 0;
338
-	if(format == 1) {
339
-	    if(fmap_readn(map, &section_hdr[i], shoff, sizeof(struct elf_section_hdr32)) != sizeof(struct elf_section_hdr32))
340
-		err = 1;
341
-	    shoff += sizeof(struct elf_section_hdr32);
342
-	} else {
343
-		struct elf_section_hdr64 section_hdr64;
344
-
345
-	    if(fmap_readn(map, &section_hdr64, shoff, sizeof(section_hdr64)) != sizeof(section_hdr64)) {
346
-		err = 1;
347
-	    } else {
348
-		section_hdr[i].sh_name = section_hdr64.sh_name;
349
-		section_hdr[i].sh_type = section_hdr64.sh_type;
350
-		section_hdr[i].sh_flags = section_hdr64.sh_flags;
351
-		section_hdr[i].sh_addr = section_hdr64.sh_addr;
352
-		section_hdr[i].sh_offset = section_hdr64.sh_offset;
353
-		section_hdr[i].sh_size = section_hdr64.sh_size;
354
-		section_hdr[i].sh_link = section_hdr64.sh_link;
355
-		section_hdr[i].sh_info = section_hdr64.sh_info;
356
-		section_hdr[i].sh_addralign = section_hdr64.sh_addralign;
357
-		section_hdr[i].sh_entsize = section_hdr64.sh_entsize;
358
-	    }
359
-	    shoff += sizeof(section_hdr64);
360
-	}
361
-
362
-	if(err) {
363
-            cli_dbgmsg("ELF: Can't read section header\n");
364
-            cli_dbgmsg("ELF: Possibly broken ELF file\n");
365
-            free(section_hdr);
366
-            if(DETECT_BROKEN) {
367
-                cli_append_virus(ctx, "Heuristics.Broken.Executable");
368
-		return CL_VIRUS;
369
-            }
370
-            return CL_CLEAN;
371
-        }
372
-
373
-	cli_dbgmsg("ELF: Section %d\n", i);
374
-	cli_dbgmsg("ELF: Section offset: %d\n", EC32(section_hdr[i].sh_offset, conv));
375
-	cli_dbgmsg("ELF: Section size: %d\n", EC32(section_hdr[i].sh_size, conv));
376
-
377
-	switch(EC32(section_hdr[i].sh_type, conv)) {
378
-	    case 0x6: /* SHT_DYNAMIC */
379
-		cli_dbgmsg("ELF: Section type: Dynamic linking information\n");
380
-		break;
381
-	    case 0xb: /* SHT_DYNSYM */
382
-		cli_dbgmsg("ELF: Section type: Symbols for dynamic linking\n");
383
-		break;
384
-	    case 0xf: /* SHT_FINI_ARRAY */
385
-		cli_dbgmsg("ELF: Section type: Array of pointers to termination functions\n");
386
-		break;
387
-	    case 0x5: /* SHT_HASH */
388
-		cli_dbgmsg("ELF: Section type: Symbol hash table\n");
389
-		break;
390
-	    case 0xe: /* SHT_INIT_ARRAY */
391
-		cli_dbgmsg("ELF: Section type: Array of pointers to initialization functions\n");
392
-		break;
393
-	    case 0x8: /* SHT_NOBITS */
394
-		cli_dbgmsg("ELF: Section type: Empty section (NOBITS)\n");
395
-		break;
396
-	    case 0x7: /* SHT_NOTE */
397
-		cli_dbgmsg("ELF: Section type: Note section\n");
398
-		break;
399
-	    case 0x0: /* SHT_NULL */
400
-		cli_dbgmsg("ELF: Section type: Null (no associated section)\n");
401
-		break;
402
-	    case 0x10: /* SHT_PREINIT_ARRAY */
403
-		cli_dbgmsg("ELF: Section type: Array of pointers to preinit functions\n");
404
-		break;
405
-	    case 0x1: /* SHT_PROGBITS */
406
-		cli_dbgmsg("ELF: Section type: Program information\n");
407
-		break;
408
-	    case 0x9: /* SHT_REL */
409
-		cli_dbgmsg("ELF: Section type: Relocation entries w/o explicit addends\n");
410
-		break;
411
-	    case 0x4: /* SHT_RELA */
412
-		cli_dbgmsg("ELF: Section type: Relocation entries with explicit addends\n");
413
-		break;
414
-	    case 0x3: /* SHT_STRTAB */
415
-		cli_dbgmsg("ELF: Section type: String table\n");
416
-		break;
417
-	    case 0x2: /* SHT_SYMTAB */
418
-		cli_dbgmsg("ELF: Section type: Symbol table\n");
419
-		break;
420
-	    case 0x6ffffffd: /* SHT_GNU_verdef */
421
-		cli_dbgmsg("ELF: Section type: Provided symbol versions\n");
422
-		break;
423
-	    case 0x6ffffffe: /* SHT_GNU_verneed */
424
-		cli_dbgmsg("ELF: Section type: Required symbol versions\n");
425
-		break;
426
-	    case 0x6fffffff: /* SHT_GNU_versym */
427
-		cli_dbgmsg("ELF: Section type: Symbol Version Table\n");
428
-		break;
429
-	    default :
430
-		cli_dbgmsg("ELF: Section type: Unknown\n");
431
-	}
432
-
433
-	if(EC32(section_hdr[i].sh_flags, conv) & 0x1) /* SHF_WRITE */
434
-	    cli_dbgmsg("ELF: Section contains writable data\n");
435
-
436
-	if(EC32(section_hdr[i].sh_flags, conv) & 0x2) /* SHF_ALLOC */
437
-	    cli_dbgmsg("ELF: Section occupies memory\n");
438
-
439
-	if(EC32(section_hdr[i].sh_flags, conv) & 0x4) /* SHF_EXECINSTR */
440
-	    cli_dbgmsg("ELF: Section contains executable code\n");
441
-
442
-	cli_dbgmsg("------------------------------------\n");
232
+    else if(ret != CL_CLEAN) {
233
+	return ret;
443 234
     }
444 235
 
445
-    free(section_hdr);
446 236
     return CL_CLEAN;
447 237
 }
448 238
 
239
+/* ELF header parsing only
240
+ * Returns 0 on success, -1 on error
241
+ */
449 242
 int cli_elfheader(fmap_t *map, struct cli_exe_info *elfinfo)
450 243
 {
451
-	struct elf_file_hdr32 file_hdr;
244
+	union elf_file_hdr file_hdr;
452 245
 	struct elf_section_hdr32 *section_hdr = NULL;
453 246
 	struct elf_program_hdr32 *program_hdr = NULL;
454 247
 	uint16_t shnum, phnum, shentsize, phentsize, i;
455
-	uint32_t entry, fentry = 0, shoff, phoff;
456
-	uint8_t conv = 0, err;
457
-	unsigned int format;
248
+	uint64_t entry, fentry = 0, shoff, phoff;
249
+	uint8_t conv = 0, err, is64 = 0;
250
+    int ret;
458 251
 
459 252
     cli_dbgmsg("in cli_elfheader\n");
460 253
 
461
-    if(fmap_readn(map, &file_hdr, 0, sizeof(file_hdr)) != sizeof(file_hdr)) {
462
-	/* Not an ELF file? */
463
-	cli_dbgmsg("ELF: Can't read file header\n");
254
+    ret = cli_elf_fileheader(NULL, map, &file_hdr, &conv, &is64);
255
+    if(ret != CL_CLEAN) {
464 256
 	return -1;
465 257
     }
466 258
 
467
-    if(memcmp(file_hdr.e_ident, "\x7f\x45\x4c\x46", 4)) {
468
-	cli_dbgmsg("ELF: Not an ELF file\n");
469
-	return -1;
470
-    }
471
-
472
-    format = file_hdr.e_ident[4];
473
-    if(format != 1 && format != 2) {
474
-	cli_dbgmsg("ELF: Unknown ELF class (%u)\n", file_hdr.e_ident[4]);
475
-	return -1;
259
+    /* Program headers and Entry */
260
+    if(is64) {
261
+        ret = cli_elf_ph64(NULL, map, elfinfo, &(file_hdr.hdr64), conv);
476 262
     }
477
-
478
-    if(format == 2) {
479
-        struct elf_file_hdr64 file_hdr64;
480
-        if(fmap_readn(map, &file_hdr64, 0, sizeof(file_hdr64)) != sizeof(file_hdr64)) {
481
-            /* Not an ELF file? */
482
-            cli_dbgmsg("ELF: Can't read file header\n");
483
-            return -1;
484
-        }
485
-	/* it's enough for us to handle ELF64 as 32 */
486
-	file_hdr.e_entry = file_hdr64.e_entry;
487
-        file_hdr.e_phoff = file_hdr64.e_phoff;
488
-        file_hdr.e_shoff = file_hdr64.e_shoff;
489
-	file_hdr.e_flags = file_hdr64.e_flags;
490
-	file_hdr.e_ehsize = file_hdr64.e_ehsize;
491
-	file_hdr.e_phentsize = file_hdr64.e_phentsize;
492
-	if(file_hdr.e_phentsize == sizeof(struct elf_program_hdr64))
493
-	    file_hdr.e_phentsize = sizeof(struct elf_program_hdr32);
494
-	file_hdr.e_phnum = file_hdr64.e_phnum;
495
-	file_hdr.e_shentsize = file_hdr64.e_shentsize;
496
-	if(file_hdr.e_shentsize == sizeof(struct elf_section_hdr64))
497
-	    file_hdr.e_shentsize = sizeof(struct elf_section_hdr32);
498
-	file_hdr.e_shnum = file_hdr64.e_shnum;
499
-	file_hdr.e_shstrndx = file_hdr64.e_shstrndx;
500
-    }
501
-
502
-    if(file_hdr.e_ident[5] == 1) {
503
-#if WORDS_BIGENDIAN == 1
504
-	conv = 1;
505
-#endif
506
-    } else {
507
-#if WORDS_BIGENDIAN == 0
508
-	conv = 1;
509
-#endif
263
+    else {
264
+        ret = cli_elf_ph32(NULL, map, elfinfo, &(file_hdr.hdr32.hdr), conv);
510 265
     }
511
-
512
-    phnum = EC16(file_hdr.e_phnum, conv);
513
-    if(phnum > 128) {
514
-	cli_dbgmsg("ELF: Suspicious number of program headers\n");
266
+    if(ret != CL_CLEAN) {
515 267
 	return -1;
516 268
     }
517
-    entry = EC32(file_hdr.e_entry, conv);
518
-
519
-    if(phnum && entry) {
520
-	phentsize = EC16(file_hdr.e_phentsize, conv);
521
-	if(phentsize != sizeof(struct elf_program_hdr32)) {
522
-	    cli_dbgmsg("ELF: phentsize != sizeof(struct elf_program_hdr32)\n");
523
-	    return -1;
524
-	}
525
-
526
-	phoff = EC32(file_hdr.e_phoff, conv);
527
-
528
-	program_hdr = (struct elf_program_hdr32 *) cli_calloc(phnum, phentsize);
529
-	if(!program_hdr) {
530
-	    cli_errmsg("ELF: Can't allocate memory for program headers\n");
531
-	    return -1;
532
-	}
533
-
534
-	for(i = 0; i < phnum; i++) {
535
-	    err = 0;
536
-	    if(format == 1) {
537
-		if(fmap_readn(map, &program_hdr[i], phoff, sizeof(struct elf_program_hdr32)) != sizeof(struct elf_program_hdr32))
538
-		    err = 1;
539
-		phoff += sizeof(struct elf_program_hdr32);
540
-	    } else {
541
-		    struct elf_program_hdr64 program_hdr64;
542
-
543
-		if(fmap_readn(map, &program_hdr64, phoff, sizeof(program_hdr64)) != sizeof(program_hdr64)) {
544
-		    err = 1;
545
-		} else {
546
-		    program_hdr[i].p_type = program_hdr64.p_type;
547
-		    program_hdr[i].p_offset = program_hdr64.p_offset;
548
-		    program_hdr[i].p_vaddr = program_hdr64.p_vaddr;
549
-		    program_hdr[i].p_paddr = program_hdr64.p_paddr;
550
-		    program_hdr[i].p_filesz = program_hdr64.p_filesz;
551
-		    program_hdr[i].p_memsz = program_hdr64.p_memsz;
552
-		    program_hdr[i].p_flags = program_hdr64.p_flags;
553
-		    program_hdr[i].p_align = program_hdr64.p_align;
554
-		}
555
-		phoff += sizeof(program_hdr64);
556
-	    }
557 269
 
558
-	    if(err) {
559
-		cli_dbgmsg("ELF: Can't read segment #%d\n", i);
560
-		free(program_hdr);
561
-		return -1;
562
-	    }
563
-	}
564
-
565
-	fentry = cli_rawaddr(entry, program_hdr, phnum, conv, &err);
566
-	free(program_hdr);
567
-	if(err) {
568
-	    cli_dbgmsg("ELF: Can't calculate file offset of entry point\n");
569
-	    return -1;
570
-	}
270
+    /* Section Headers */
271
+    if(is64) {
272
+        ret = cli_elf_sh64(NULL, map, elfinfo, &(file_hdr.hdr64), conv);
571 273
     }
572
-
573
-    elfinfo->ep = fentry;
574
-
575
-    shnum = EC16(file_hdr.e_shnum, conv);
576
-    if(shnum > 256) {
577
-	cli_dbgmsg("ELF: Suspicious number of sections\n");
578
-	return -1;
579
-    }
580
-    elfinfo->nsections = shnum;
581
-
582
-    shentsize = EC16(file_hdr.e_shentsize, conv);
583
-    if(shentsize != sizeof(struct elf_section_hdr32)) {
584
-	cli_dbgmsg("ELF: shentsize != sizeof(struct elf_section_hdr32)\n");
585
-	return -1;
274
+    else {
275
+        ret = cli_elf_sh32(NULL, map, elfinfo, &(file_hdr.hdr32.hdr), conv);
586 276
     }
587
-
588
-    if(!shnum)
589
-	return 0;
590
-
591
-    shoff = EC32(file_hdr.e_shoff, conv);
592
-
593
-    elfinfo->section = (struct cli_exe_section *) cli_calloc(elfinfo->nsections, sizeof(struct cli_exe_section));
594
-    if(!elfinfo->section) {
595
-	cli_dbgmsg("ELF: Can't allocate memory for section headers\n");
277
+    if(ret != CL_CLEAN) {
596 278
 	return -1;
597 279
     }
598 280
 
599
-    if(shnum) {
600
-	section_hdr = (struct elf_section_hdr32 *) cli_calloc(shnum, shentsize);
601
-	if(!section_hdr) {
602
-	    cli_errmsg("ELF: Can't allocate memory for section headers\n");
603
-	    free(elfinfo->section);
604
-	    elfinfo->section = NULL;
605
-	    return -1;
606
-	}
607
-    }
608
-
609
-    for(i = 0; i < shnum; i++) {
610
-	err = 0;
611
-	if(format == 1) {
612
-	    if(fmap_readn(map, &section_hdr[i], shoff, sizeof(struct elf_section_hdr32)) != sizeof(struct elf_section_hdr32))
613
-		err = 1;
614
-	    shoff += sizeof(struct elf_section_hdr32);
615
-	} else {
616
-		struct elf_section_hdr64 section_hdr64;
617
-
618
-	    if(fmap_readn(map, &section_hdr64, shoff, sizeof(section_hdr64)) != sizeof(section_hdr64)) {
619
-		err = 1;
620
-	    } else {
621
-		section_hdr[i].sh_name = section_hdr64.sh_name;
622
-		section_hdr[i].sh_type = section_hdr64.sh_type;
623
-		section_hdr[i].sh_flags = section_hdr64.sh_flags;
624
-		section_hdr[i].sh_addr = section_hdr64.sh_addr;
625
-		section_hdr[i].sh_offset = section_hdr64.sh_offset;
626
-		section_hdr[i].sh_size = section_hdr64.sh_size;
627
-		section_hdr[i].sh_link = section_hdr64.sh_link;
628
-		section_hdr[i].sh_info = section_hdr64.sh_info;
629
-		section_hdr[i].sh_addralign = section_hdr64.sh_addralign;
630
-		section_hdr[i].sh_entsize = section_hdr64.sh_entsize;
631
-	    }
632
-	    shoff += sizeof(section_hdr64);
633
-	}
634
-
635
-	if(err) {
636
-            cli_dbgmsg("ELF: Can't read section header\n");
637
-            free(section_hdr);
638
-	    free(elfinfo->section);
639
-	    elfinfo->section = NULL;
640
-            return -1;
641
-        }
642
-	elfinfo->section[i].rva = EC32(section_hdr[i].sh_addr, conv);
643
-	elfinfo->section[i].raw = EC32(section_hdr[i].sh_offset, conv);
644
-	elfinfo->section[i].rsz = EC32(section_hdr[i].sh_size, conv);
645
-    }
646
-
647
-    free(section_hdr);
648 281
     return 0;
649 282
 }
... ...
@@ -1,5 +1,5 @@
1 1
 /*
2
- *  Copyright (C) 2007-2009 Sourcefire, Inc.
2
+ *  Copyright (C) 2007-2013 Sourcefire, Inc.
3 3
  *
4 4
  *  Authors: Tomasz Kojm
5 5
  *
... ...
@@ -27,11 +27,13 @@
27 27
 #include "others.h"
28 28
 #include "fmap.h"
29 29
 
30
+/* ELF File Headers */
30 31
 struct elf_file_hdr32 {
31
-    unsigned char e_ident[16];
32
+    uint8_t  e_ident[16];
32 33
     uint16_t e_type;
33 34
     uint16_t e_machine;
34 35
     uint32_t e_version;
36
+    /* fields after here are NOT aligned the same as 64 */
35 37
     uint32_t e_entry;
36 38
     uint32_t e_phoff;
37 39
     uint32_t e_shoff;
... ...
@@ -45,10 +47,11 @@ struct elf_file_hdr32 {
45 45
 };
46 46
 
47 47
 struct elf_file_hdr64 {
48
-    unsigned char e_ident[16];
48
+    uint8_t  e_ident[16];
49 49
     uint16_t e_type;
50 50
     uint16_t e_machine;
51 51
     uint32_t e_version;
52
+    /* fields after here are NOT aligned the same as 32 */
52 53
     uint64_t e_entry;
53 54
     uint64_t e_phoff;
54 55
     uint64_t e_shoff;
... ...
@@ -61,6 +64,21 @@ struct elf_file_hdr64 {
61 61
     uint16_t e_shstrndx;
62 62
 };
63 63
 
64
+/* ELF File Header Helpers */
65
+#define ELF_HDR_SIZEDIFF 12
66
+
67
+/* This part is the same on both headers */
68
+struct elf_file_hdr32plus {
69
+    struct elf_file_hdr32 hdr;
70
+    uint8_t pad[ELF_HDR_SIZEDIFF];
71
+};
72
+
73
+union elf_file_hdr {
74
+    struct elf_file_hdr32plus hdr32;
75
+    struct elf_file_hdr64 hdr64;
76
+};
77
+
78
+/* ELF Program Headers */
64 79
 struct elf_program_hdr32 {
65 80
     uint32_t p_type;
66 81
     uint32_t p_offset;
... ...
@@ -83,6 +101,16 @@ struct elf_program_hdr64 {
83 83
     uint64_t p_align;
84 84
 };
85 85
 
86
+/* ELF Section Headers */
87
+
88
+/* Notable ELF section header flags */
89
+#define ELF_SHF_WRITE (1 << 0)
90
+#define ELF_SHF_ALLOC (1 << 1)
91
+#define ELF_SHF_EXECINSTR  (1 << 2)
92
+
93
+/* There are more section header flags, but these are the ones we log */
94
+#define ELF_SHF_MASK (ELF_SHF_WRITE | ELF_SHF_ALLOC | ELF_SHF_EXECINSTR)
95
+
86 96
 struct elf_section_hdr32 {
87 97
     uint32_t sh_name;
88 98
     uint32_t sh_type;
... ...
@@ -109,6 +137,8 @@ struct elf_section_hdr64 {
109 109
     uint64_t sh_entsize;
110 110
 };
111 111
 
112
+/* Exposed functions */
113
+
112 114
 int cli_scanelf(cli_ctx *ctx);
113 115
 
114 116
 int cli_elfheader(fmap_t *map, struct cli_exe_info *elfinfo);
... ...
@@ -154,9 +154,9 @@ static int find_stream_bounds(const char *start, off_t bytesleft, off_t byteslef
154 154
 	    return 0;
155 155
 	if (bytesleft >= 2 && q2[0] == '\xd' && q2[1] == '\xa') {
156 156
 	    q2 += 2;
157
-	    if (newline_hack && q2[0] == '\xa')
157
+	    if (newline_hack && (bytesleft > 2) && q2[0] == '\xa')
158 158
 		q2++;
159
-	} else if (q2[0] == '\xa')
159
+	} else if (bytesleft && q2[0] == '\xa')
160 160
 	    q2++;
161 161
 	*stream = q2 - start;
162 162
 	bytesleft2 -= q2 - start;