• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  * honggfuzz - architecture dependent code (LINUX/UNWIND)
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 "unwind.h"
25 
26 #include <endian.h>
27 #include <libunwind-ptrace.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 
32 #include "honggfuzz.h"
33 #include "libcommon/common.h"
34 #include "libcommon/log.h"
35 
36 /*
37  * WARNING: Ensure that _UPT-info structs are not shared between threads
38  * http://www.nongnu.org/libunwind/man/libunwind-ptrace(3).html
39  */
40 
41 // libunwind error codes used for debugging
42 static const char* UNW_ER[] = {
43     "UNW_ESUCCESS",     /* no error */
44     "UNW_EUNSPEC",      /* unspecified (general) error */
45     "UNW_ENOMEM",       /* out of memory */
46     "UNW_EBADREG",      /* bad register number */
47     "UNW_EREADONLYREG", /* attempt to write read-only register */
48     "UNW_ESTOPUNWIND",  /* stop unwinding */
49     "UNW_EINVALIDIP",   /* invalid IP */
50     "UNW_EBADFRAME",    /* bad frame */
51     "UNW_EINVAL",       /* unsupported operation or bad value */
52     "UNW_EBADVERSION",  /* unwind info has unsupported version */
53     "UNW_ENOINFO"       /* no unwind info found */
54 };
55 
56 typedef struct {
57     unsigned long start;
58     unsigned long end;
59     char perms[6];
60     unsigned long offset;
61     char dev[8];
62     unsigned long inode;
63     char name[PATH_MAX];
64 } procMap_t;
65 
arch_parsePidMaps(pid_t pid,size_t * mapsCount)66 static procMap_t* arch_parsePidMaps(pid_t pid, size_t* mapsCount) {
67     FILE* f = NULL;
68     char fProcMaps[PATH_MAX] = {0};
69     snprintf(fProcMaps, PATH_MAX, "/proc/%d/maps", pid);
70 
71     if ((f = fopen(fProcMaps, "rb")) == NULL) {
72         PLOG_E("Couldn't open '%s' - R/O mode", fProcMaps);
73         return 0;
74     }
75     defer { fclose(f); };
76 
77     *mapsCount = 0;
78     procMap_t* mapsList = malloc(sizeof(procMap_t));
79     if (mapsList == NULL) {
80         PLOG_W("malloc(size='%zu')", sizeof(procMap_t));
81         return NULL;
82     }
83 
84     while (!feof(f)) {
85         char buf[sizeof(procMap_t) + 1];
86         if (fgets(buf, sizeof(buf), f) == 0) {
87             break;
88         }
89 
90         mapsList[*mapsCount].name[0] = '\0';
91         sscanf(buf, "%lx-%lx %5s %lx %7s %ld %s", &mapsList[*mapsCount].start,
92             &mapsList[*mapsCount].end, mapsList[*mapsCount].perms, &mapsList[*mapsCount].offset,
93             mapsList[*mapsCount].dev, &mapsList[*mapsCount].inode, mapsList[*mapsCount].name);
94 
95         *mapsCount += 1;
96         if ((mapsList = realloc(mapsList, (*mapsCount + 1) * sizeof(procMap_t))) == NULL) {
97             PLOG_W("realloc failed (sz=%zu)", (*mapsCount + 1) * sizeof(procMap_t));
98             free(mapsList);
99             return NULL;
100         }
101     }
102 
103     return mapsList;
104 }
105 
arch_searchMaps(unsigned long addr,size_t mapsCnt,procMap_t * mapsList)106 static char* arch_searchMaps(unsigned long addr, size_t mapsCnt, procMap_t* mapsList) {
107     for (size_t i = 0; i < mapsCnt; i++) {
108         if (addr >= mapsList[i].start && addr <= mapsList[i].end) {
109             return mapsList[i].name;
110         }
111 
112         /* Benefit from maps being sorted by address */
113         if (addr < mapsList[i].start) {
114             break;
115         }
116     }
117     return NULL;
118 }
119 
120 #ifndef __ANDROID__
arch_unwindStack(pid_t pid,funcs_t * funcs)121 size_t arch_unwindStack(pid_t pid, funcs_t* funcs) {
122     size_t num_frames = 0, mapsCnt = 0;
123     procMap_t* mapsList = arch_parsePidMaps(pid, &mapsCnt);
124     defer { free(mapsList); };
125 
126     unw_addr_space_t as = unw_create_addr_space(&_UPT_accessors, __BYTE_ORDER);
127     if (!as) {
128         LOG_E("[pid='%d'] unw_create_addr_space failed", pid);
129         return num_frames;
130     }
131     defer { unw_destroy_addr_space(as); };
132 
133     void* ui = _UPT_create(pid);
134     if (ui == NULL) {
135         LOG_E("[pid='%d'] _UPT_create failed", pid);
136         return num_frames;
137     }
138     defer { _UPT_destroy(ui); };
139 
140     unw_cursor_t c;
141     int ret = unw_init_remote(&c, as, ui);
142     if (ret < 0) {
143         LOG_E("[pid='%d'] unw_init_remote failed (%s)", pid, UNW_ER[-ret]);
144         return num_frames;
145     }
146 
147     for (num_frames = 0; unw_step(&c) > 0 && num_frames < _HF_MAX_FUNCS; num_frames++) {
148         unw_word_t ip;
149         char* mapName = NULL;
150         ret = unw_get_reg(&c, UNW_REG_IP, &ip);
151         if (ret < 0) {
152             LOG_E("[pid='%d'] [%zd] failed to read IP (%s)", pid, num_frames, UNW_ER[-ret]);
153             funcs[num_frames].pc = 0;
154         } else {
155             funcs[num_frames].pc = (void*)(uintptr_t)ip;
156         }
157         if (mapsCnt > 0 && (mapName = arch_searchMaps(ip, mapsCnt, mapsList)) != NULL) {
158             memcpy(funcs[num_frames].mapName, mapName, sizeof(funcs[num_frames].mapName));
159         } else {
160             strncpy(funcs[num_frames].mapName, "UNKNOWN", sizeof(funcs[num_frames].mapName));
161         }
162     }
163 
164     return num_frames;
165 }
166 
167 #else  /* !defined(__ANDROID__) */
arch_unwindStack(pid_t pid,funcs_t * funcs)168 size_t arch_unwindStack(pid_t pid, funcs_t* funcs) {
169     size_t num_frames = 0, mapsCnt = 0;
170     procMap_t* mapsList = arch_parsePidMaps(pid, &mapsCnt);
171     defer { free(mapsList); };
172 
173     unw_addr_space_t as = unw_create_addr_space(&_UPT_accessors, __BYTE_ORDER);
174     if (!as) {
175         LOG_E("[pid='%d'] unw_create_addr_space failed", pid);
176         return num_frames;
177     }
178     defer { unw_destroy_addr_space(as); };
179 
180     struct UPT_info* ui = (struct UPT_info*)_UPT_create(pid);
181     if (ui == NULL) {
182         LOG_E("[pid='%d'] _UPT_create failed", pid);
183         return num_frames;
184     }
185     defer { _UPT_destroy(ui); };
186 
187     unw_cursor_t cursor;
188     int ret = unw_init_remote(&cursor, as, ui);
189     if (ret < 0) {
190         LOG_E("[pid='%d'] unw_init_remote failed (%s)", pid, UNW_ER[-ret]);
191         return num_frames;
192     }
193 
194     do {
195         char* mapName = NULL;
196         unw_word_t pc = 0, offset = 0;
197         char buf[_HF_FUNC_NAME_SZ] = {0};
198 
199         ret = unw_get_reg(&cursor, UNW_REG_IP, &pc);
200         if (ret < 0) {
201             LOG_E("[pid='%d'] [%zd] failed to read IP (%s)", pid, num_frames, UNW_ER[-ret]);
202             // We don't want to try to extract info from an arbitrary IP
203             // TODO: Maybe abort completely (goto out))
204             goto skip_frame_info;
205         }
206 
207         unw_proc_info_t frameInfo;
208         ret = unw_get_proc_info(&cursor, &frameInfo);
209         if (ret < 0) {
210             LOG_D("[pid='%d'] [%zd] unw_get_proc_info (%s)", pid, num_frames, UNW_ER[-ret]);
211             // Not safe to keep parsing frameInfo
212             goto skip_frame_info;
213         }
214 
215         ret = unw_get_proc_name(&cursor, buf, sizeof(buf), &offset);
216         if (ret < 0) {
217             LOG_D(
218                 "[pid='%d'] [%zd] unw_get_proc_name() failed (%s)", pid, num_frames, UNW_ER[-ret]);
219             buf[0] = '\0';
220         }
221 
222     skip_frame_info:
223         // Compared to bfd, line var plays the role of offset from func_name
224         // Reports format is adjusted accordingly to reflect in saved file
225         funcs[num_frames].line = offset;
226         funcs[num_frames].pc = (void*)pc;
227         memcpy(funcs[num_frames].func, buf, sizeof(funcs[num_frames].func));
228         if (mapsCnt > 0 && (mapName = arch_searchMaps(pc, mapsCnt, mapsList)) != NULL) {
229             memcpy(funcs[num_frames].mapName, mapName, sizeof(funcs[num_frames].mapName));
230         } else {
231             strncpy(funcs[num_frames].mapName, "UNKNOWN", sizeof(funcs[num_frames].mapName));
232         }
233 
234         num_frames++;
235 
236         ret = unw_step(&cursor);
237     } while (ret > 0 && num_frames < _HF_MAX_FUNCS);
238 
239     return num_frames;
240 }
241 #endif /* defined(__ANDROID__) */
242 
243 /*
244  * Nested loop not most efficient approach, although it's assumed that list is
245  * usually target specific and thus small.
246  */
arch_btContainsSymbol(size_t symbolsListSz,char ** symbolsList,size_t num_frames,funcs_t * funcs)247 char* arch_btContainsSymbol(
248     size_t symbolsListSz, char** symbolsList, size_t num_frames, funcs_t* funcs) {
249     for (size_t frame = 0; frame < num_frames; frame++) {
250         size_t len = strlen(funcs[frame].func);
251 
252         /* Try only for frames that have symbol name from backtrace */
253         if (strlen(funcs[frame].func) > 0) {
254             for (size_t i = 0; i < symbolsListSz; i++) {
255                 /* Wildcard symbol string special case */
256                 char* wOff = strchr(symbolsList[i], '*');
257                 if (wOff) {
258                     /* Length always > 3 as checked at input file parsing step */
259                     len = wOff - symbolsList[i] - 1;
260                 }
261 
262                 if (strncmp(funcs[frame].func, symbolsList[i], len) == 0) {
263                     return funcs[frame].func;
264                 }
265             }
266         }
267     }
268     return NULL;
269 }
270