enum translation_state action_fail(struct translate *ts) { PRINT_DEBUG_FUNCTION_START("action_fail(*ts=%p)", ts); PRINT_DEBUG("unhandled opcode encountered in TU at %p: %s", ts->cur_instr, MEMDUMP(ts->cur_instr, ts->next_instr - ts->cur_instr)); PRINT_DEBUG("giving up!!!"); PRINT_DEBUG_FUNCTION_END("-> FAIL"); #ifdef DEBUG llprintf("\n\n\t\tERROR: unhandled opcode encountered in TU at %p: %s\n\n", ts->cur_instr, MEMDUMP(ts->cur_instr, ts->next_instr - ts->cur_instr)); llprintf("\nERROR: unhandled opcode encountered in TU at %p\nBtOX will " "exit now!\n", ts->cur_instr); #endif #if defined(SLEEP_ON_FAIL) llprintf("Something bad happened (action_fail). Attach a debugger!\n"); while (1); #endif fbt_suicide(255); return CLOSE; }
/** * callback function used to scan the loaded libraries. * This function is used as callback in dl_iterate_phdr(3) to scan the sections * of a loaded library. The first object in the list (position 0) is always the * executable, the second one the vdso ("linux-gate.so"). The third object is * the secuBT library (libfastbt.so), because it is loaded with LD_PRELOAD. * The sections of the objects are added to the red-black-tree structure along * with information on whether they contain executable code. * For more info on dl_iterate_phdr, refer to its man page. * @param info the object info structure provided by dl_iterate_phdr * @param size the size of the info structure * @param data is used to store the position in the list of libraries */ static int fbt_memprotect_callback(struct dl_phdr_info *info, size_t size, void *data) { int libnum = *((int*) data); // look for the base address in the library list int i = 0; for (i = 0; i < lib_list_size; i++) { if (library_list[i].base_addr == (void*) info->dlpi_addr) { // the entry for this object already exists in the library list (*((int*)data))++; return 0; } } if (lib_list_size >= lib_list_capacity) { fbt_lib_list_resize(); } const char *name = info->dlpi_name; /* * The first entry of dl_iterate_phdr's table of objects is always the * executable itself, the second the vdso. They don't have dlpi_addr as * base address and have to be caught in order not to be processed again. * After these two come the shared objects. */ if (0 == libnum) { if (lib_list_size > 0) { // executable has to be already be in the library list (*((int*)data))++; return 0; } name = "/proc/self/exe"; } else if (1 == libnum) { if (lib_list_size > 1) { // vdso has to be already be in the library list (*((int*)data))++; return 0; } // ugly hack to get correct address of vdso void *vdso_addr = (void*) (info->dlpi_addr + info->dlpi_phdr[0].p_vaddr); // add vdso to library table library_list[lib_list_size].base_addr = vdso_addr; library_list[lib_list_size].length = PAGESIZE; library_list[lib_list_size].name = (char *) malloc(5 * sizeof(char)); fbt_strcpy(library_list[lib_list_size].name, "vdso"); lib_list_size++; // add vdso entry to sections tree struct mem_info *info = malloc(sizeof(*info)); info->node.addr_begin = vdso_addr; info->node.addr_end = vdso_addr + PAGESIZE; info->sec_name = library_list[lib_list_size - 1].name; info->lib_index = lib_list_size - 1; info->flags = INFO_RFLAG | INFO_XFLAG; sections_root = rb_insert(sections_root, (struct rb_node*) info); (*((int*)data))++; return 0; } if (0 == fbt_strcmp(name, "")) { (*((int*)data))++; return 0; } // entry in library list library_list[lib_list_size].base_addr = (void*) info->dlpi_addr; library_list[lib_list_size].length = 0; library_list[lib_list_size].name = malloc(fbt_strnlen(name,0) + 1); fbt_strcpy(library_list[lib_list_size].name, name); lib_list_size++; /* * we map library file again to memory, because when it is loaded for execution, the * section header table and the section containing the section name strings are not * mapped to memory. */ // open the file -> file descriptor int fd; fbt_open(name, O_RDONLY, 0x0, fd); if (-1 == fd) { fbt_suicide_str("fbt_iterate_sections: could not open executable or library file (memprotect_callback: fbt_mem_protection.c)\n"); (*((int*)data))++; return -1; } // find out file size int filesize; fbt_lseek(fd, 0, SEEK_END, filesize); if (-1 == filesize) { fbt_suicide_str("fbt_iterate_sections: fstat failure, cannot find out file size (memprotect_callback: fbt_mem_protection.c)\n"); return -1; } void *libmap; fbt_mmap(NULL, filesize, PROT_READ, MAP_PRIVATE, fd, 0, libmap); if ((void*) -1 == libmap) { fbt_suicide_str("fbt_iterate-sections: failed to map library to memory (memprotect_callback: fbt_mem_protection.c)\n"); //fbt_close(fd); //(*((int*)data))++; return -1; } Elf32_Ehdr *header = (Elf32_Ehdr*) libmap; fbt_sym *dyn_symtab = NULL; char *dyn_strtab = NULL; void *dyn_hashtab = NULL; if (0 != header->e_shnum) { Elf32_Shdr *section_header = (Elf32_Shdr*) (libmap + header->e_shoff); int i = 0; for (i = 0; i < header->e_shnum; i++) { // only consider sections loaded into memory on execution if ((section_header[i].sh_size < 1) || ((section_header[i].sh_flags & SHF_ALLOC) == 0)) { continue; } // fill in node information struct mem_info *meminfo = (struct mem_info*) malloc(sizeof(*meminfo)); meminfo->node.addr_begin = (void*) (info->dlpi_addr + section_header[i].sh_addr); meminfo->node.addr_end = meminfo->node.addr_begin + section_header[i].sh_size; // calculate start address of the executable if ((0 == libnum) && (0 == library_list[0].base_addr)) { library_list[0].base_addr = (void*) ((long) (meminfo->node.addr_begin) & ~(PAGESIZE - 1)); } // section name if (SHN_UNDEF != header->e_shstrndx) { const char *name_entry = (const char*) (libmap + section_header[header->e_shstrndx].sh_offset + section_header[i].sh_name); char *section_name = (char*) malloc(fbt_strnlen(name_entry,0) + 1); fbt_strcpy(section_name, name_entry); meminfo->sec_name = section_name; } else { const char* no_sec_names = "no section name string table"; char *section_name = (char*) malloc(fbt_strnlen(no_sec_names,0) + 1); fbt_strcpy(section_name, no_sec_names); meminfo->sec_name = section_name; } // update size in memory int length = meminfo->node.addr_end - library_list[lib_list_size - 1].base_addr; if (length > library_list[lib_list_size - 1].length) { library_list[lib_list_size - 1].length = length; } // flags meminfo->flags = INFO_RFLAG; if (section_header[i].sh_flags & SHF_WRITE) { meminfo->flags |= INFO_WFLAG; } if (2 == libnum) { // memory in libfastbt.so meminfo->flags |= INFO_BTFLAG; } if (section_header[i].sh_flags & SHF_EXECINSTR) { // only mark as executable if we memory not part of libfastbt.so meminfo->flags |= INFO_XFLAG; } meminfo->lib_index = lib_list_size - 1; sections_root = rb_insert(sections_root, (struct rb_node*) meminfo); // code for symbol checking if (SHT_DYNSYM == section_header[i].sh_type) { // we have found the dynamic linking symbol table dyn_symtab = (Elf32_Sym*) (info->dlpi_addr + section_header[i].sh_addr); if (2 == libnum) { // handling libfastbt.so, need to know # of symbols fbt_dyn_nsyms = section_header[i].sh_size / sizeof(fbt_sym); } } if (!fbt_strcmp(".dynstr", meminfo->sec_name)) { // string table for dynamic linking symbols dyn_strtab = (char*) (info->dlpi_addr + section_header[i].sh_addr); } if (!fbt_strcmp(".gnu.hash", meminfo->sec_name)) { // hash table for dynamic linking symbols (gnu format) dyn_hashtab = (void*) (info->dlpi_addr + section_header[i].sh_addr); } } } #ifdef SECU_NX_PROG // only executed on first run of this function if (0 == libnum) { /* * Set the memory of the program non-executable. We cannot do the same * to the libraries, as we need some of them ourselves. */ /* TODO: protect libs as well and compile bt statically */ int ret; fbt_mprotect(library_list[0].base_addr, library_list[0].length, PROT_READ | PROT_WRITE, ret); } #endif #ifdef SECU_DETECT_SYMBOL_COLLISIONS if ((NULL != dyn_symtab) && (NULL != dyn_strtab) && (NULL != dyn_hashtab)) { if (0 == libnum) { /* * we can not check the symbols of the executable now because * libfastbt.so has not been processed yet. */ exe_dyn_symtab = dyn_symtab; exe_dyn_strtab = dyn_strtab; exe_dyn_hashtab = dyn_hashtab; } else if (2 == libnum) { fbt_dyn_symtab = dyn_symtab; fbt_dyn_strtab = dyn_strtab; // ok, now we can check the symbols of the executable if (!fbt_check_sym_collision(exe_dyn_symtab, exe_dyn_strtab, exe_dyn_hashtab)) { // symbol collision detected fbt_suicide_str("Symbol collision in the executable (memprotect_callback: fbt_mem_protection.c)\n"); } } else if (libnum > 2) { // check symbols of library if (!fbt_check_sym_collision(dyn_symtab, dyn_strtab, dyn_hashtab)) { llprintf("Symbol collision in %s\n", name); ffflush(); fbt_suicide(); } } } else { // one of the tables was not found! llprintf("Fatal: One of the tables for symbol checking was not found!\n" "symtab: %p, strtab: %p, hashtab: %p\n", dyn_symtab, dyn_strtab, dyn_hashtab); ffflush(); fbt_suicide(); } #endif (void)dyn_hashtab; (void)dyn_strtab; (void)dyn_symtab; int ret; fbt_munmap(libmap, filesize, ret); fbt_close(fd, ret); (*((int*)data))++; return 0; }