• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  * honggfuzz - architecture dependent code (LINUX/BFD)
4  * -----------------------------------------
5  *
6  * Author: Robert Swiecki <swiecki@google.com>
7  *
8  * Copyright 2010-2015 by Google Inc. All Rights Reserved.
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License"); you may
11  * not use this file except in compliance with the License. You may obtain
12  * a copy of the License at
13  *
14  * http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
19  * implied. See the License for the specific language governing
20  * permissions and limitations under the License.
21  *
22  */
23 
24 #include "linux/bfd.h"
25 
26 #include <bfd.h>
27 #include <dis-asm.h>
28 #include <inttypes.h>
29 #include <pthread.h>
30 #include <stdarg.h>
31 #include <stddef.h>
32 #include <stdint.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37 
38 #include "honggfuzz.h"
39 #include "libcommon/common.h"
40 #include "libcommon/files.h"
41 #include "libcommon/log.h"
42 #include "libcommon/util.h"
43 
44 typedef struct {
45     bfd* bfdh;
46     asection* section;
47     asymbol** syms;
48 } bfd_t;
49 
50 /*
51  * This is probably the only define which was added with binutils 2.29, so we us
52  * it, do decide which disassembler() prototype from dis-asm.h to use
53  */
54 #if defined(FOR_EACH_DISASSEMBLER_OPTION)
55 #define _HF_BFD_GE_2_29
56 #endif
57 
58 static pthread_mutex_t arch_bfd_mutex = PTHREAD_MUTEX_INITIALIZER;
59 
arch_bfdInit(pid_t pid,bfd_t * bfdParams)60 static bool arch_bfdInit(pid_t pid, bfd_t* bfdParams) {
61     char fname[PATH_MAX];
62     snprintf(fname, sizeof(fname), "/proc/%d/exe", pid);
63     if ((bfdParams->bfdh = bfd_openr(fname, 0)) == NULL) {
64         LOG_E("bfd_openr(%s) failed", fname);
65         return false;
66     }
67 
68     if (!bfd_check_format(bfdParams->bfdh, bfd_object)) {
69         LOG_E("bfd_check_format() failed");
70         return false;
71     }
72 
73     int storage_needed = bfd_get_symtab_upper_bound(bfdParams->bfdh);
74     if (storage_needed <= 0) {
75         LOG_E("bfd_get_symtab_upper_bound() returned '%d'", storage_needed);
76         return false;
77     }
78 
79     bfdParams->syms = (asymbol**)util_Malloc(storage_needed);
80     bfd_canonicalize_symtab(bfdParams->bfdh, bfdParams->syms);
81 
82     if ((bfdParams->section = bfd_get_section_by_name(bfdParams->bfdh, ".text")) == NULL) {
83         LOG_E("bfd_get_section_by_name('.text') failed");
84         return false;
85     }
86 
87     return true;
88 }
89 
arch_bfdDestroy(bfd_t * bfdParams)90 static void arch_bfdDestroy(bfd_t* bfdParams) {
91     if (bfdParams->syms) {
92         free(bfdParams->syms);
93     }
94     if (bfdParams->bfdh) {
95         bfd_close(bfdParams->bfdh);
96     }
97 }
98 
arch_bfdResolveSyms(pid_t pid,funcs_t * funcs,size_t num)99 void arch_bfdResolveSyms(pid_t pid, funcs_t* funcs, size_t num) {
100     /* Guess what? libbfd is not multi-threading safe */
101     MX_SCOPED_LOCK(&arch_bfd_mutex);
102 
103     bfd_init();
104 
105     __block bfd_t bfdParams = {
106         .bfdh = NULL,
107         .section = NULL,
108         .syms = NULL,
109     };
110 
111     if (arch_bfdInit(pid, &bfdParams) == false) {
112         return;
113     }
114 
115     const char* func;
116     const char* file;
117     unsigned int line;
118     for (unsigned int i = 0; i < num; i++) {
119         snprintf(funcs[i].func, sizeof(funcs->func), "[UNKNOWN]");
120         if (funcs[i].pc == NULL) {
121             continue;
122         }
123         long offset = (long)funcs[i].pc - bfdParams.section->vma;
124         if ((offset < 0 || (unsigned long)offset > bfdParams.section->size)) {
125             continue;
126         }
127         if (bfd_find_nearest_line(
128                 bfdParams.bfdh, bfdParams.section, bfdParams.syms, offset, &file, &func, &line)) {
129             snprintf(funcs[i].func, sizeof(funcs->func), "%s", func);
130             funcs[i].line = line;
131         }
132     }
133 
134     arch_bfdDestroy(&bfdParams);
135 }
136 
arch_bfdFPrintF(void * buf,const char * fmt,...)137 static int arch_bfdFPrintF(void* buf, const char* fmt, ...) {
138     va_list args;
139     va_start(args, fmt);
140     int ret = util_vssnprintf(buf, _HF_INSTR_SZ, fmt, args);
141     va_end(args);
142 
143     return ret;
144 }
145 
arch_bfdDisasm(pid_t pid,uint8_t * mem,size_t size,char * instr)146 void arch_bfdDisasm(pid_t pid, uint8_t* mem, size_t size, char* instr) {
147     MX_SCOPED_LOCK(&arch_bfd_mutex);
148 
149     bfd_init();
150 
151     char fname[PATH_MAX];
152     snprintf(fname, sizeof(fname), "/proc/%d/exe", pid);
153     bfd* bfdh = bfd_openr(fname, NULL);
154     if (bfdh == NULL) {
155         LOG_W("bfd_openr('/proc/%d/exe') failed", pid);
156         return;
157     }
158 
159     if (!bfd_check_format(bfdh, bfd_object)) {
160         LOG_W("bfd_check_format() failed");
161         bfd_close(bfdh);
162         return;
163     }
164 #if defined(_HF_BFD_GE_2_29)
165     disassembler_ftype disassemble =
166         disassembler(bfd_get_arch(bfdh), bfd_little_endian(bfdh) ? FALSE : TRUE, 0, NULL);
167 #else
168     disassembler_ftype disassemble = disassembler(bfdh);
169 #endif  // defined(_HD_BFD_GE_2_29)
170     if (disassemble == NULL) {
171         LOG_W("disassembler() failed");
172         bfd_close(bfdh);
173         return;
174     }
175 
176     struct disassemble_info info;
177     init_disassemble_info(&info, instr, arch_bfdFPrintF);
178     info.arch = bfd_get_arch(bfdh);
179     info.mach = bfd_get_mach(bfdh);
180     info.buffer = mem;
181     info.buffer_length = size;
182     info.section = NULL;
183     info.endian = bfd_little_endian(bfdh) ? BFD_ENDIAN_LITTLE : BFD_ENDIAN_BIG;
184     disassemble_init_for_target(&info);
185 
186     strcpy(instr, "");
187     if (disassemble(0, &info) <= 0) {
188         snprintf(instr, _HF_INSTR_SZ, "[DIS-ASM_FAILURE]");
189     }
190 
191     bfd_close(bfdh);
192 }
193