Newer
Older
*
* This file may be used and modified for non-commercial purposes as long as
* all copyright, permission, and nonwarranty notices are preserved.
* Redistribution is prohibited without prior written consent from Zephyr
* Software.
*
* Please contact the authors for restrictions applying to commercial use.
*
* THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* Author: Zephyr Software
* e-mail: jwd@zephyr-software.com
* URL : http://www.zephyr-software.com/
*
*/
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <link.h>
#include <elf.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <stdio.h>
#include <string.h>
// these must match config.h in AFL source code
#define SHM_ENV_VAR "__AFL_SHM_ID"
#define FORKSRV_FD 198
#define MAP_SIZE_POW2 16
#define MAP_SIZE (1 << MAP_SIZE_POW2)
typedef uint8_t u8;
typedef int32_t s32;
// externally visible so that Zipr transformations can access directly
unsigned int zafl_prev_id = 123;
unsigned int zafl_context = 45678;
#define AFL_VARS_OFFSET (MAP_SIZE + 4096)
#define AFL_VARS_STORAGE_SIZE 1024
#define AFL_VAR_PREVID_OFFSET 32
#define AFL_VAR_CONTEXT_OFFSET 64
s32* zafl_var_map = NULL;
static s32 shm_id;
static int __afl_temp_data;
static pid_t __afl_fork_pid;
static int tracemap_shared_memory_is_setup = 0;
static int aflvars_shared_memory_is_setup = 0;
static void zafl_setupAflTracemapSharedMemory();
#define PRINT_ERROR(string) {int x=write(2, string, my_strlen(string));}
#define PRINT_DEBUG(string) if (debug) {int x=write(1, string, my_strlen(string));}
#ifdef ZAFL_AUTO_INIT_FORK_SERVER
void __attribute__((constructor)) zafl_initAflForkServer();
void __attribute__((constructor)) zafl_setupAflTracemapSharedMemory();
void __attribute__((destructor)) zafl_dumpTracemap();
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
static size_t my_strlen(const char *s)
{
const char *p = s;
while (*s) ++s;
return s - p;
}
static char* my_ull_toa(unsigned long long value, char* result, const int base)
{
if (base < 2 || base > 36)
{
*result = '\0';
return result;
}
char* ptr = result, *ptr1 = result, tmp_char;
unsigned long long tmp_value;
do
{
tmp_value = value;
value /= base;
*ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)];
} while ( value );
*ptr-- = '\0';
while(ptr1 < ptr)
{
tmp_char = *ptr;
*ptr--= *ptr1;
*ptr1++ = tmp_char;
}
return result;
}
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
static void zafl_setupAflVariablesMemory(void *vars_addr)
{
if (aflvars_shared_memory_is_setup)
return;
zafl_var_map = (s32*) mmap(vars_addr, AFL_VARS_STORAGE_SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if (zafl_var_map == MAP_FAILED)
{
perror("mmap of afl variables failed");
return;
}
else if (zafl_var_map != vars_addr)
{
perror("mmap of afl variables failed -- unexpected address");
return;
}
// initialize map
s32* prev_id = vars_addr + AFL_VAR_PREVID_OFFSET;
s32* context_id = vars_addr + AFL_VAR_CONTEXT_OFFSET;
// any values will do here
*prev_id = 0x234;
*context_id = 0xabc;
aflvars_shared_memory_is_setup = 1;
if (debug)
{
char buf[1024];
my_ull_toa((unsigned long long)vars_addr, buf, 16);
PRINT_DEBUG("&var_map: 0x"); PRINT_DEBUG(buf); PRINT_DEBUG("\n");
printf("var_map: 0x%p\n", (void*) vars_addr);
my_ull_toa((unsigned long long)prev_id, buf, 16);
PRINT_DEBUG("&prev_id: 0x"); PRINT_DEBUG(buf); PRINT_DEBUG("\n");
my_ull_toa((unsigned long long)context_id, buf, 16);
PRINT_DEBUG("&context_id: 0x"); PRINT_DEBUG(buf); PRINT_DEBUG("\n");
static int find_map_addr(struct dl_phdr_info *p_info, size_t p_size, void *p_data)
{
#define close_and_err \
{ \
close(fd);\
return 0; \
}
void** trace_map_fixed_addr = (void**)p_data;
*trace_map_fixed_addr = NULL;
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
PRINT_DEBUG ("Name: ");
PRINT_DEBUG(p_info->dlpi_name);
PRINT_DEBUG ("\n");
const char* the_name = (p_info->dlpi_name[0] == '\0') ?
"/proc/self/exe" :
p_info->dlpi_name;
int fd = open(the_name, O_RDONLY);
// no such file
if(fd == -1 ) return 0;
Elf64_Ehdr file_header = {};
const int hdr_size = read(fd, &file_header, sizeof(file_header));
// file too small
if(hdr_size!=sizeof(file_header)) close_and_err;
// magic number check
if(file_header.e_ident[0] != ELFMAG0) close_and_err;
if(file_header.e_ident[1] != ELFMAG1) close_and_err;
if(file_header.e_ident[2] != ELFMAG2) close_and_err;
if(file_header.e_ident[3] != ELFMAG3) close_and_err;
// sanity check section header entry size
if(file_header.e_shentsize != sizeof(Elf64_Shdr)) close_and_err;
// sanity check string table index
if(file_header.e_shstrndx >= file_header.e_shnum) close_and_err;
// read section headers
Elf64_Shdr section_headers[file_header.e_shnum];
memset(section_headers,0,sizeof(section_headers));
const int section_header_offset = lseek(fd, file_header.e_shoff, SEEK_SET);
// sanity check successful seek
if(section_header_offset != file_header.e_shoff) close_and_err;
const int sec_hdr_size = read(fd, section_headers, sizeof(section_headers));
// sanity check we read them all
if(sec_hdr_size != sizeof(section_headers)) close_and_err;
// sanity check string table type
if(section_headers[file_header.e_shstrndx].sh_type != SHT_STRTAB) close_and_err;
// seek to the string section
int string_sec_offset = lseek(fd, section_headers[file_header.e_shstrndx].sh_offset, SEEK_SET);
// declare the string table
char string_table[section_headers[file_header.e_shstrndx].sh_size+1]; // definitely null terminate
memset(string_table,0,sizeof(string_table));
// read the string table
const int string_table_size = read(fd, string_table, section_headers[file_header.e_shstrndx].sh_size);
// sanity check read
if(string_table_size != section_headers[file_header.e_shstrndx].sh_size) close_and_err;
const char* integration_name = "libZaflIntegration";
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
{
const uint64_t sec_name_offset = section_headers[i].sh_name;
// sanity check name -- bail from function if corrupt
if(sec_name_offset >= section_headers[file_header.e_shstrndx].sh_size) close_and_err;
// check if right section, try next if not.
if(strcmp(integration_name, string_table+sec_name_offset) != 0) continue;
// sanity check size
if(section_headers[i].sh_size != sizeof(void*)) close_and_err;
// found! seek to section's data.
int integration_table_pos = lseek(fd, section_headers[i].sh_offset, SEEK_SET);
if(integration_table_pos != section_headers[i].sh_offset) close_and_err;
// now read
char integration_table[section_headers[i].sh_size];
memset(integration_table,0,sizeof(integration_table));
// read the data table
const int integration_table_size = read(fd, integration_table, section_headers[i].sh_size);
// sanity check read, bail on function if corrupt.
if(integration_table_size != section_headers[i].sh_size) close_and_err;
// extract the value
*trace_map_fixed_addr = *(void**)(integration_table);
close(fd);
return 1;
}
close_and_err;
}
// always setup a trace map so that an instrumented application will run
static void zafl_setupAflTracemapSharedMemory()
if (tracemap_shared_memory_is_setup)
void* trace_map_fixed_addr = (void*) NULL;
dl_iterate_phdr(find_map_addr, (void*)&trace_map_fixed_addr);
const int do_fixed_addr_optimization = (trace_map_fixed_addr != NULL);
void* shmat_addr = trace_map_fixed_addr;
if (do_fixed_addr_optimization)
{
// setup the area for storing prev_id and context_id 4K away from the end of the trace map
void* vars_addr = (void*)(shmat_addr + AFL_VARS_OFFSET);
zafl_setupAflVariablesMemory(vars_addr);
}
if(!shm_env_var)
{
PRINT_DEBUG("Error getting shm environment variable - fake allocate AFL trace map\n");
// fake allocate until someone calls zafl_initAflForkServer()
zafl_trace_map = (u8*)mmap(shmat_addr, MAP_SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if(zafl_trace_map == MAP_FAILED)
{
exit(1);
}
else
{
PRINT_DEBUG("Success at mmap!\n");
if(shmat_addr!=0)
assert(zafl_trace_map==shmat_addr);
tracemap_shared_memory_is_setup = 1;
zafl_trace_map = (u8*)shmat(shm_id, shmat_addr, 0);
return;
}
PRINT_DEBUG("libzafl: shared memory segment is setup\n");
tracemap_shared_memory_is_setup = 1;
if (getenv("ZAFL_DEBUG")) debug = 1;
PRINT_DEBUG("libautozafl: auto-initialize fork server\n");
if (fork_server_initialized) return;
zafl_setupAflTracemapSharedMemory();
// force map entry to get past afl sanity checks
if (debug)
zafl_trace_map[MAP_SIZE-1] = 1;
perror("Error on fork()\n");
close(FORKSRV_FD);
close(FORKSRV_FD+1);
break;
n = write(FORKSRV_FD+1,&__afl_fork_pid, 4);
pid_t temp_pid = waitpid(__afl_fork_pid,&__afl_temp_data,2);
return;
}
n = write(FORKSRV_FD+1,&__afl_temp_data,4);
}
}
}
//
void zafl_bbInstrument(unsigned short id)
{
if (!debug) return;
if (!zafl_trace_map) return;
{
PRINT_DEBUG(my_ull_toa(i, buf, 16));
PRINT_DEBUG(":")
PRINT_DEBUG(my_ull_toa(zafl_trace_map[i], buf, 10));
PRINT_DEBUG("\n")
}