Browse code

libclamav/elf.[ch]: add support for 64-bit ELF files (bb#1593)

git-svn: trunk@5076

Tomasz Kojm authored on 2009/06/12 19:31:24
Showing 3 changed files
... ...
@@ -1,3 +1,7 @@
1
+Fri Jun 12 12:30:15 CEST 2009 (tk)
2
+----------------------------------
3
+ * libclamav/elf.[ch]: add support for 64-bit ELF files (bb#1593)
4
+
1 5
 Wed Jun 10 19:01:11 CEST 2009 (tk)
2 6
 ----------------------------------
3 7
  * V 0.95.2
... ...
@@ -1,5 +1,5 @@
1 1
 /*
2
- *  Copyright (C) 2007-2008 Sourcefire, Inc.
2
+ *  Copyright (C) 2007-2009 Sourcefire, Inc.
3 3
  *
4 4
  *  Authors: Tomasz Kojm
5 5
  *
... ...
@@ -84,6 +84,7 @@ int cli_scanelf(int desc, cli_ctx *ctx)
84 84
 	uint16_t shnum, phnum, shentsize, phentsize;
85 85
 	uint32_t entry, fentry, shoff, phoff, i;
86 86
 	uint8_t conv = 0, err;
87
+	unsigned int format;
87 88
 
88 89
 
89 90
     cli_dbgmsg("in cli_scanelf\n");
... ...
@@ -99,9 +100,35 @@ int cli_scanelf(int desc, cli_ctx *ctx)
99 99
 	return CL_CLEAN;
100 100
     }
101 101
 
102
-    if(file_hdr.e_ident[4] != 1) {
103
-	cli_dbgmsg("ELF: 64-bit binaries are not supported (yet)\n");
104
-	return CL_CLEAN;
102
+    format = file_hdr.e_ident[4];
103
+    if(format != 1 && format != 2) {
104
+	cli_dbgmsg("ELF: Unknown ELF class (%u)\n", file_hdr.e_ident[4]);
105
+	return CL_EFORMAT;
106
+    }
107
+
108
+    if(format == 2) {
109
+	    struct elf_file_hdr64 file_hdr64;
110
+	lseek(desc, 0, SEEK_SET);
111
+	if(read(desc, &file_hdr64, sizeof(file_hdr64)) != sizeof(file_hdr64)) {
112
+	    /* Not an ELF file? */
113
+	    cli_dbgmsg("ELF: Can't read file header\n");
114
+	    return CL_CLEAN;
115
+	}
116
+	/* it's enough for us to handle ELF64 as 32 */
117
+	file_hdr.e_entry = file_hdr64.e_entry;
118
+        file_hdr.e_phoff = file_hdr64.e_phoff;
119
+        file_hdr.e_shoff = file_hdr64.e_shoff;
120
+	file_hdr.e_flags = file_hdr64.e_flags;
121
+	file_hdr.e_ehsize = file_hdr64.e_ehsize;
122
+	file_hdr.e_phentsize = file_hdr64.e_phentsize;
123
+	if(file_hdr.e_phentsize == sizeof(struct elf_program_hdr64))
124
+	    file_hdr.e_phentsize = sizeof(struct elf_program_hdr32);
125
+	file_hdr.e_phnum = file_hdr64.e_phnum;
126
+	file_hdr.e_shentsize = file_hdr64.e_shentsize;
127
+	if(file_hdr.e_shentsize == sizeof(struct elf_section_hdr64))
128
+	    file_hdr.e_shentsize = sizeof(struct elf_section_hdr32);
129
+	file_hdr.e_shnum = file_hdr64.e_shnum;
130
+	file_hdr.e_shstrndx = file_hdr64.e_shstrndx;
105 131
     }
106 132
 
107 133
     if(file_hdr.e_ident[5] == 1) {
... ...
@@ -142,47 +169,53 @@ int cli_scanelf(int desc, cli_ctx *ctx)
142 142
 
143 143
     switch(EC16(file_hdr.e_machine, conv)) {
144 144
 	/* Due to a huge list, we only include the most popular machines here */
145
-	case 0x0: /* EM_NONE */
145
+	case 0: /* EM_NONE */
146 146
 	    cli_dbgmsg("ELF: Machine type: None\n");
147 147
 	    break;
148
-	case 0x2: /* EM_SPARC */
148
+	case 2: /* EM_SPARC */
149 149
 	    cli_dbgmsg("ELF: Machine type: SPARC\n");
150 150
 	    break;
151
-	case 0x3: /* EM_386 */
151
+	case 3: /* EM_386 */
152 152
 	    cli_dbgmsg("ELF: Machine type: Intel 80386\n");
153 153
 	    break;
154
-	case 0x4: /* EM_68K */
154
+	case 4: /* EM_68K */
155 155
 	    cli_dbgmsg("ELF: Machine type: Motorola 68000\n");
156 156
 	    break;
157
-	case 0x8: /* EM_MIPS */
157
+	case 8: /* EM_MIPS */
158 158
 	    cli_dbgmsg("ELF: Machine type: MIPS RS3000\n");
159 159
 	    break;
160
-	case 0x15: /* EM_PARISC */
160
+	case 9: /* EM_S370 */
161
+	    cli_dbgmsg("ELF: Machine type: IBM System/370\n");
162
+	    break;
163
+	case 15: /* EM_PARISC */
161 164
 	    cli_dbgmsg("ELF: Machine type: HPPA\n");
162 165
 	    break;
163
-	case 0x20: /* EM_PPC */
166
+	case 20: /* EM_PPC */
164 167
 	    cli_dbgmsg("ELF: Machine type: PowerPC\n");
165 168
 	    break;
166
-	case 0x21: /* EM_PPC64 */
169
+	case 21: /* EM_PPC64 */
167 170
 	    cli_dbgmsg("ELF: Machine type: PowerPC 64-bit\n");
168 171
 	    break;
169
-	case 0x22: /* EM_S390 */
172
+	case 22: /* EM_S390 */
170 173
 	    cli_dbgmsg("ELF: Machine type: IBM S390\n");
171 174
 	    break;
172
-	case 0x40: /* EM_ARM */
175
+	case 40: /* EM_ARM */
173 176
 	    cli_dbgmsg("ELF: Machine type: ARM\n");
174 177
 	    break;
175
-	case 0x41: /* EM_FAKE_ALPHA */
178
+	case 41: /* EM_FAKE_ALPHA */
176 179
 	    cli_dbgmsg("ELF: Machine type: Digital Alpha\n");
177 180
 	    break;
178
-	case 0x43: /* EM_SPARCV9 */
181
+	case 43: /* EM_SPARCV9 */
179 182
 	    cli_dbgmsg("ELF: Machine type: SPARC v9 64-bit\n");
180 183
 	    break;
181
-	case 0x50: /* EM_IA_64 */
184
+	case 50: /* EM_IA_64 */
182 185
 	    cli_dbgmsg("ELF: Machine type: IA64\n");
183 186
 	    break;
187
+	case 62: /* EM_X86_64 */
188
+	    cli_dbgmsg("ELF: Machine type: AMD x86-64\n");
189
+	    break;
184 190
 	default:
185
-	    cli_dbgmsg("ELF: Machine type: Unknown (%d)\n", EC16(file_hdr.e_machine, conv));
191
+	    cli_dbgmsg("ELF: Machine type: Unknown (0x%x)\n", EC16(file_hdr.e_machine, conv));
186 192
     }
187 193
 
188 194
     entry = EC32(file_hdr.e_entry, conv);
... ...
@@ -234,8 +267,28 @@ int cli_scanelf(int desc, cli_ctx *ctx)
234 234
 	cli_dbgmsg("------------------------------------\n");
235 235
 
236 236
 	for(i = 0; i < phnum; i++) {
237
+	    err = 0;
238
+	    if(format == 1) {
239
+		if(read(desc, &program_hdr[i], sizeof(struct elf_program_hdr32)) != sizeof(struct elf_program_hdr32))
240
+		    err = 1;
241
+	    } else {
242
+		    struct elf_program_hdr64 program_hdr64;
243
+
244
+		if(read(desc, &program_hdr64, sizeof(program_hdr64)) != sizeof(program_hdr64)) {
245
+		    err = 1;
246
+		} else {
247
+		    program_hdr[i].p_type = program_hdr64.p_type;
248
+		    program_hdr[i].p_offset = program_hdr64.p_offset;
249
+		    program_hdr[i].p_vaddr = program_hdr64.p_vaddr;
250
+		    program_hdr[i].p_paddr = program_hdr64.p_paddr;
251
+		    program_hdr[i].p_filesz = program_hdr64.p_filesz;
252
+		    program_hdr[i].p_memsz = program_hdr64.p_memsz;
253
+		    program_hdr[i].p_flags = program_hdr64.p_flags;
254
+		    program_hdr[i].p_align = program_hdr64.p_align;
255
+		}
256
+	    }
237 257
 
238
-	    if(read(desc, &program_hdr[i], sizeof(struct elf_program_hdr32)) != sizeof(struct elf_program_hdr32)) {
258
+	    if(err) {
239 259
 		cli_dbgmsg("ELF: Can't read segment #%d\n", i);
240 260
 		cli_dbgmsg("ELF: Possibly broken ELF file\n");
241 261
 		free(program_hdr);
... ...
@@ -317,8 +370,30 @@ int cli_scanelf(int desc, cli_ctx *ctx)
317 317
     cli_dbgmsg("------------------------------------\n");
318 318
 
319 319
     for(i = 0; i < shnum; i++) {
320
+	err = 0;
321
+	if(format == 1) {
322
+	    if(read(desc, &section_hdr[i], sizeof(struct elf_section_hdr32)) != sizeof(struct elf_section_hdr32))
323
+		err = 1;
324
+	} else {
325
+		struct elf_section_hdr64 section_hdr64;
326
+
327
+	    if(read(desc, &section_hdr64, sizeof(section_hdr64)) != sizeof(section_hdr64)) {
328
+		err = 1;
329
+	    } else {
330
+		section_hdr[i].sh_name = section_hdr64.sh_name;
331
+		section_hdr[i].sh_type = section_hdr64.sh_type;
332
+		section_hdr[i].sh_flags = section_hdr64.sh_flags;
333
+		section_hdr[i].sh_addr = section_hdr64.sh_addr;
334
+		section_hdr[i].sh_offset = section_hdr64.sh_offset;
335
+		section_hdr[i].sh_size = section_hdr64.sh_size;
336
+		section_hdr[i].sh_link = section_hdr64.sh_link;
337
+		section_hdr[i].sh_info = section_hdr64.sh_info;
338
+		section_hdr[i].sh_addralign = section_hdr64.sh_addralign;
339
+		section_hdr[i].sh_entsize = section_hdr64.sh_entsize;
340
+	    }
341
+	}
320 342
 
321
-	if(read(desc, &section_hdr[i], sizeof(struct elf_section_hdr32)) != sizeof(struct elf_section_hdr32)) {
343
+	if(err) {
322 344
             cli_dbgmsg("ELF: Can't read section header\n");
323 345
             cli_dbgmsg("ELF: Possibly broken ELF file\n");
324 346
             free(section_hdr);
... ...
@@ -414,7 +489,7 @@ int cli_elfheader(int desc, struct cli_exe_info *elfinfo)
414 414
 	uint16_t shnum, phnum, shentsize, phentsize, i;
415 415
 	uint32_t entry, fentry = 0, shoff, phoff;
416 416
 	uint8_t conv = 0, err;
417
-
417
+	unsigned int format;
418 418
 
419 419
     cli_dbgmsg("in cli_elfheader\n");
420 420
 
... ...
@@ -429,11 +504,37 @@ int cli_elfheader(int desc, struct cli_exe_info *elfinfo)
429 429
 	return -1;
430 430
     }
431 431
 
432
-    if(file_hdr.e_ident[4] != 1) {
433
-	cli_dbgmsg("ELF: 64-bit binaries are not supported (yet)\n");
432
+    format = file_hdr.e_ident[4];
433
+    if(format != 1 && format != 2) {
434
+	cli_dbgmsg("ELF: Unknown ELF class (%u)\n", file_hdr.e_ident[4]);
434 435
 	return -1;
435 436
     }
436 437
 
438
+    if(format == 2) {
439
+	    struct elf_file_hdr64 file_hdr64;
440
+	lseek(desc, 0, SEEK_SET);
441
+	if(read(desc, &file_hdr64, sizeof(file_hdr64)) != sizeof(file_hdr64)) {
442
+	    /* Not an ELF file? */
443
+	    cli_dbgmsg("ELF: Can't read file header\n");
444
+	    return -1; 
445
+	}
446
+	/* it's enough for us to handle ELF64 as 32 */
447
+	file_hdr.e_entry = file_hdr64.e_entry;
448
+        file_hdr.e_phoff = file_hdr64.e_phoff;
449
+        file_hdr.e_shoff = file_hdr64.e_shoff;
450
+	file_hdr.e_flags = file_hdr64.e_flags;
451
+	file_hdr.e_ehsize = file_hdr64.e_ehsize;
452
+	file_hdr.e_phentsize = file_hdr64.e_phentsize;
453
+	if(file_hdr.e_phentsize == sizeof(struct elf_program_hdr64))
454
+	    file_hdr.e_phentsize = sizeof(struct elf_program_hdr32);
455
+	file_hdr.e_phnum = file_hdr64.e_phnum;
456
+	file_hdr.e_shentsize = file_hdr64.e_shentsize;
457
+	if(file_hdr.e_shentsize == sizeof(struct elf_section_hdr64))
458
+	    file_hdr.e_shentsize = sizeof(struct elf_section_hdr32);
459
+	file_hdr.e_shnum = file_hdr64.e_shnum;
460
+	file_hdr.e_shstrndx = file_hdr64.e_shstrndx;
461
+    }
462
+
437 463
     if(file_hdr.e_ident[5] == 1) {
438 464
 #if WORDS_BIGENDIAN == 1
439 465
 	conv = 1;
... ...
@@ -470,7 +571,28 @@ int cli_elfheader(int desc, struct cli_exe_info *elfinfo)
470 470
 	}
471 471
 
472 472
 	for(i = 0; i < phnum; i++) {
473
-	    if(read(desc, &program_hdr[i], sizeof(struct elf_program_hdr32)) != sizeof(struct elf_program_hdr32)) {
473
+	    err = 0;
474
+	    if(format == 1) {
475
+		if(read(desc, &program_hdr[i], sizeof(struct elf_program_hdr32)) != sizeof(struct elf_program_hdr32))
476
+		    err = 1;
477
+	    } else {
478
+		    struct elf_program_hdr64 program_hdr64;
479
+
480
+		if(read(desc, &program_hdr64, sizeof(program_hdr64)) != sizeof(program_hdr64)) {
481
+		    err = 1;
482
+		} else {
483
+		    program_hdr[i].p_type = program_hdr64.p_type;
484
+		    program_hdr[i].p_offset = program_hdr64.p_offset;
485
+		    program_hdr[i].p_vaddr = program_hdr64.p_vaddr;
486
+		    program_hdr[i].p_paddr = program_hdr64.p_paddr;
487
+		    program_hdr[i].p_filesz = program_hdr64.p_filesz;
488
+		    program_hdr[i].p_memsz = program_hdr64.p_memsz;
489
+		    program_hdr[i].p_flags = program_hdr64.p_flags;
490
+		    program_hdr[i].p_align = program_hdr64.p_align;
491
+		}
492
+	    }
493
+
494
+	    if(err) {
474 495
 		cli_dbgmsg("ELF: Can't read segment #%d\n", i);
475 496
 		free(program_hdr);
476 497
 		return -1;
... ...
@@ -521,14 +643,36 @@ int cli_elfheader(int desc, struct cli_exe_info *elfinfo)
521 521
     }
522 522
 
523 523
     for(i = 0; i < shnum; i++) {
524
+	err = 0;
525
+	if(format == 1) {
526
+	    if(read(desc, &section_hdr[i], sizeof(struct elf_section_hdr32)) != sizeof(struct elf_section_hdr32))
527
+		err = 1;
528
+	} else {
529
+		struct elf_section_hdr64 section_hdr64;
530
+
531
+	    if(read(desc, &section_hdr64, sizeof(section_hdr64)) != sizeof(section_hdr64)) {
532
+		err = 1;
533
+	    } else {
534
+		section_hdr[i].sh_name = section_hdr64.sh_name;
535
+		section_hdr[i].sh_type = section_hdr64.sh_type;
536
+		section_hdr[i].sh_flags = section_hdr64.sh_flags;
537
+		section_hdr[i].sh_addr = section_hdr64.sh_addr;
538
+		section_hdr[i].sh_offset = section_hdr64.sh_offset;
539
+		section_hdr[i].sh_size = section_hdr64.sh_size;
540
+		section_hdr[i].sh_link = section_hdr64.sh_link;
541
+		section_hdr[i].sh_info = section_hdr64.sh_info;
542
+		section_hdr[i].sh_addralign = section_hdr64.sh_addralign;
543
+		section_hdr[i].sh_entsize = section_hdr64.sh_entsize;
544
+	    }
545
+	}
524 546
 
525
-	if(read(desc, &section_hdr[i], sizeof(struct elf_section_hdr32)) != sizeof(struct elf_section_hdr32)) {
547
+	if(err) {
548
+            cli_dbgmsg("ELF: Can't read section header\n");
526 549
             free(section_hdr);
527 550
 	    free(elfinfo->section);
528 551
 	    elfinfo->section = NULL;
529 552
             return -1;
530 553
         }
531
-
532 554
 	elfinfo->section[i].rva = EC32(section_hdr[i].sh_addr, conv);
533 555
 	elfinfo->section[i].raw = EC32(section_hdr[i].sh_offset, conv);
534 556
 	elfinfo->section[i].rsz = EC32(section_hdr[i].sh_size, conv);
... ...
@@ -1,5 +1,5 @@
1 1
 /*
2
- *  Copyright (C) 2007-2008 Sourcefire, Inc.
2
+ *  Copyright (C) 2007-2009 Sourcefire, Inc.
3 3
  *
4 4
  *  Authors: Tomasz Kojm
5 5
  *
... ...
@@ -43,6 +43,23 @@ struct elf_file_hdr32 {
43 43
     uint16_t e_shstrndx;
44 44
 };
45 45
 
46
+struct elf_file_hdr64 {
47
+    unsigned char e_ident[16];
48
+    uint16_t e_type;
49
+    uint16_t e_machine;
50
+    uint32_t e_version;
51
+    uint64_t e_entry;
52
+    uint64_t e_phoff;
53
+    uint64_t e_shoff;
54
+    uint32_t e_flags;
55
+    uint16_t e_ehsize;
56
+    uint16_t e_phentsize;
57
+    uint16_t e_phnum;
58
+    uint16_t e_shentsize;
59
+    uint16_t e_shnum;
60
+    uint16_t e_shstrndx;
61
+};
62
+
46 63
 struct elf_program_hdr32 {
47 64
     uint32_t p_type;
48 65
     uint32_t p_offset;
... ...
@@ -54,6 +71,17 @@ struct elf_program_hdr32 {
54 54
     uint32_t p_align;
55 55
 };
56 56
 
57
+struct elf_program_hdr64 {
58
+    uint32_t p_type;
59
+    uint32_t p_flags;
60
+    uint64_t p_offset;
61
+    uint64_t p_vaddr;
62
+    uint64_t p_paddr;
63
+    uint64_t p_filesz;
64
+    uint64_t p_memsz;
65
+    uint64_t p_align;
66
+};
67
+
57 68
 struct elf_section_hdr32 {
58 69
     uint32_t sh_name;
59 70
     uint32_t sh_type;
... ...
@@ -67,6 +95,19 @@ struct elf_section_hdr32 {
67 67
     uint32_t sh_entsize;
68 68
 };
69 69
 
70
+struct elf_section_hdr64 {
71
+    uint32_t sh_name;
72
+    uint32_t sh_type;
73
+    uint64_t sh_flags;
74
+    uint64_t sh_addr;
75
+    uint64_t sh_offset;
76
+    uint64_t sh_size;
77
+    uint32_t sh_link;
78
+    uint32_t sh_info;
79
+    uint64_t sh_addralign;
80
+    uint64_t sh_entsize;
81
+};
82
+
70 83
 int cli_scanelf(int desc, cli_ctx *ctx);
71 84
 
72 85
 int cli_elfheader(int desc, struct cli_exe_info *elfinfo);