diff options
Diffstat (limited to 'llvm_mode/afl-ld.c')
-rw-r--r-- | llvm_mode/afl-ld.c | 98 |
1 files changed, 65 insertions, 33 deletions
diff --git a/llvm_mode/afl-ld.c b/llvm_mode/afl-ld.c index 7cbf89dc..0e85795a 100644 --- a/llvm_mode/afl-ld.c +++ b/llvm_mode/afl-ld.c @@ -44,6 +44,8 @@ #include <dirent.h> +#define MAX_PARAM_COUNT 4096 + static u8 **ld_params, /* Parameters passed to the real 'ld' */ **link_params, /* Parameters passed to 'llvm-link' */ **opt_params, /* Parameters passed to 'opt' opt */ @@ -145,15 +147,21 @@ int is_llvm_file(const char* file) { int fd; u8 buf[5]; - if ((fd = open(file, O_RDONLY)) < 0) return 0; + if ((fd = open(file, O_RDONLY)) < 0) { + + if (debug) SAYF(cMGN "[D] " cRST "File %s not found", file); + return 0; - if (read(fd, buf, sizeof(buf)) != sizeof(buf)) return 0; + } + + if (read(fd, buf, 4) != 4) return 0; buf[sizeof(buf) - 1] = 0; close(fd); if (strncmp(buf, "; Mo", 4) == 0) return 1; - if (buf[0] == 'B' && buf[1] == 'C' && buf[2] == 0xC0 && buf[3] == 0xDE) + + if (buf[0] == 'B' && buf[1] == 'C' && buf[2] == 0xc0 && buf[3] == 0xde) return 1; return 0; @@ -186,7 +194,7 @@ int is_duplicate(u8** params, u32 ld_param_cnt, u8* ar_file) { static void edit_params(int argc, char** argv) { u32 i, have_lto = 0, libdir_index; - u8 libdir_file[4096]; + u8 libdir_file[4096]; if (tmp_dir == NULL) { @@ -204,13 +212,13 @@ static void edit_params(int argc, char** argv) { final_file = alloc_printf("%s/.afl-%u-%u-3.bc", tmp_dir, getpid(), (u32)time(NULL)); - ld_params = ck_alloc((argc + 4096) * sizeof(u8*)); - link_params = ck_alloc((argc + 4096) * sizeof(u8*)); + ld_params = ck_alloc(4096 * sizeof(u8*)); + link_params = ck_alloc(4096 * sizeof(u8*)); inst_params = ck_alloc(12 * sizeof(u8*)); opt_params = ck_alloc(12 * sizeof(u8*)); ld_params[0] = (u8*)real_ld; - ld_params[argc] = 0; + ld_params[ld_param_cnt++] = "--allow-multiple-definition"; link_params[0] = alloc_printf("%s/%s", LLVM_BINDIR, "llvm-link"); link_params[link_param_cnt++] = "-S"; // we create the linked file as .ll @@ -224,6 +232,7 @@ static void edit_params(int argc, char** argv) { opt_params[opt_param_cnt++] = "--polly"; } else + opt_params[opt_param_cnt++] = "-O0"; // opt_params[opt_param_cnt++] = "-S"; // only when debugging opt_params[opt_param_cnt++] = linked_file; // input: .ll file @@ -243,11 +252,16 @@ static void edit_params(int argc, char** argv) { // first we must collect all library search paths for (i = 1; i < argc; i++) if (strlen(argv[i]) > 2 && argv[i][0] == '-' && argv[i][1] == 'L') - libdirs[libdir_cnt++] = argv[i] + 2; + libdirs[libdir_cnt++] = argv[i] + 2; // then we inspect all options to the target linker for (i = 1; i < argc; i++) { + if (ld_param_cnt >= MAX_PARAM_COUNT || link_param_cnt >= MAX_PARAM_COUNT) + FATAL( + "Too many command line parameters because of unpacking .a archives, " + "this would need to be done by hand ... sorry! :-("); + if (strncmp(argv[i], "-flto", 5) == 0) have_lto = 1; if (!strcmp(argv[i], "-version")) { @@ -266,23 +280,26 @@ static void edit_params(int argc, char** argv) { exit(0); } - + // if a -l library is linked and no .so is found but an .a archive is there // then the archive will be used. So we have to emulate this and check // if an archive will be used and if yes we will instrument it too libdir_file[0] = 0; libdir_index = libdir_cnt; - if (strncmp(argv[i], "-l", 2) == 0 && libdir_cnt > 0 && strncmp(argv[i], "-lgcc", 5) != 0) { - + if (strncmp(argv[i], "-l", 2) == 0 && libdir_cnt > 0 && + strncmp(argv[i], "-lgcc", 5) != 0) { + u8 found = 0; - + for (uint32_t j = 0; j < libdir_cnt && !found; j++) { - snprintf(libdir_file, sizeof(libdir_file), "%s/lib%s%s", libdirs[j], argv[i] + 2, ".so"); - if (access(libdir_file, R_OK) != 0) { // no .so found? + snprintf(libdir_file, sizeof(libdir_file), "%s/lib%s%s", libdirs[j], + argv[i] + 2, ".so"); + if (access(libdir_file, R_OK) != 0) { // no .so found? - snprintf(libdir_file, sizeof(libdir_file), "%s/lib%s%s", libdirs[j], argv[i] + 2, ".a"); - if (access(libdir_file, R_OK) == 0) { // but .a found? + snprintf(libdir_file, sizeof(libdir_file), "%s/lib%s%s", libdirs[j], + argv[i] + 2, ".a"); + if (access(libdir_file, R_OK) == 0) { // but .a found? libdir_index = j; found = 1; @@ -294,16 +311,18 @@ static void edit_params(int argc, char** argv) { found = 1; if (debug) SAYF(cMGN "[D] " cRST "Found %s\n", libdir_file); - + } } - + } // is the parameter an .a AR archive? If so, unpack and check its files - if (libdir_index < libdir_cnt || (argv[i][0] != '-' && strlen(argv[i]) > 2 && - argv[i][strlen(argv[i]) - 1] == 'a' && argv[i][strlen(argv[i]) - 2] == '.')) { + if (libdir_index < libdir_cnt || + (argv[i][0] != '-' && strlen(argv[i]) > 2 && + argv[i][strlen(argv[i]) - 1] == 'a' && + argv[i][strlen(argv[i]) - 2] == '.')) { // This gets a bit odd. I encountered several .a files being linked and // where the same "foo.o" was in both .a archives. llvm-link does not @@ -317,8 +336,7 @@ static void edit_params(int argc, char** argv) { DIR* arx; struct dirent* dir_ent; - if (libdir_index < libdir_cnt) - file = libdir_file; + if (libdir_index < libdir_cnt) file = libdir_file; if (ar_dir_cnt == 0) { // first archive, we setup up the basics @@ -376,7 +394,7 @@ static void edit_params(int argc, char** argv) { if (dir_ent->d_name[strlen(dir_ent->d_name) - 1] == 'o' && dir_ent->d_name[strlen(dir_ent->d_name) - 2] == '.') { - if (passthrough || argv[i][0] == '-' || is_llvm_file(ar_file) == 0) { + if (passthrough || is_llvm_file(ar_file) == 0) { if (is_duplicate(ld_params, ld_param_cnt, ar_file) == 0) { @@ -428,7 +446,7 @@ static void edit_params(int argc, char** argv) { ld_params[ld_param_cnt++] = "-plugin-opt=O2"; else ld_params[ld_param_cnt++] = argv[i]; - + } else { if (we_link == 0) { // we have to honor order ... @@ -618,7 +636,11 @@ int main(int argc, char** argv) { edit_params(argc, argv); // here most of the magic happens :-) - if (debug) SAYF(cMGN "[D] " cRST "param counts: ar:%u lib:%u ld:%u link:%u opt:%u instr:%u\n", ar_dir_cnt, libdir_cnt, ld_param_cnt, link_param_cnt, opt_param_cnt, inst_param_cnt); + if (debug) + SAYF(cMGN "[D] " cRST + "param counts: ar:%u lib:%u ld:%u link:%u opt:%u instr:%u\n", + ar_dir_cnt, libdir_cnt, ld_param_cnt, link_param_cnt, opt_param_cnt, + inst_param_cnt); if (!just_version) { @@ -650,15 +672,25 @@ int main(int argc, char** argv) { if (pid < 0) PFATAL("fork() failed"); if (waitpid(pid, &status, 0) <= 0) PFATAL("waitpid() failed"); - if (WEXITSTATUS(status) != 0) { - - SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \ - "\n[-] PROGRAM ABORT : " cRST); - SAYF( "llvm-link failed, if this is because of a \"linking globals\n" - " named '...': symbol multiply defined\" error then there is nothing we can do -\n" - "llvm-link is missing an important feature :-(\n\n"); + if (WEXITSTATUS(status) != 0) { + + SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD + "\n[-] PROGRAM ABORT : " cRST); + SAYF( + "llvm-link failed! Probable causes:\n\n" + " #1 If the error is \"linking globals named '...': symbol " + "multiply defined\"\n" + " then there is nothing we can do - llvm-link is missing an " + "important feature\n\n" + " #2 If the error is \"expected top-level entity\" and then " + "binary output, this\n" + " is because the same file is present in different .a archives " + "in different\n" + " formats. This can be fixed by manual doing the steps afl-ld " + "is doing but\n" + " programmatically - sorry!\n\n"); exit(WEXITSTATUS(status)); - + } /* then we perform an optimization on the collected objects files */ |