Example #1
0
int fllwrite(int fd, const char* str)
{
  int written = 0;
  int length = fbt_strnlen(str, 0);
  while (written < length) {
    int64_t retval = fbt_write(fd, (uint64_t)(str + written), (length - written), "error in write");
    written += retval;
  }
  return written;
}
/**
 * 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;
}
Example #3
0
int fllprintfva(int fd, const char* format, va_list app)
{
  char buf[BUFSIZE_L+1];
  int bi = 0;     // index in the output string
  int fi = 0;     // index in the format string
  int end = 0;
  while ((bi < (BUFSIZE_L)) && !end) {
    // parse format string and write contents to buffer
    switch (format[fi]) {
    case '%':
      fi++;
      unsigned char len = 0;
      /* limit len of output/datatype? */
      if (format[fi]=='.') {
        len=format[++fi]-0x30;
        if (len>BUFSIZE_S) len=0;
        fi++;
        if (format[fi]-0x30>=0 && format[fi]-0x30<=9) {
          /* two digit number */
          len*=10;
          len+=format[fi]-0x30;
          fi++;
        }
      }
      char *pointer;
      char revbuf[BUFSIZE_S+1];
      int i, val, length;
      unsigned int abs_d;
      for (i=0; i<BUFSIZE_S+1; i++) revbuf[i]=0x0;
      i=BUFSIZE_S; // initialize to back of buffer;
      switch (format[fi]) {
      case '%':
        buf[bi++] = '%';
        break;
      case 'd':
      case 'i':
        val = va_arg(app, int);
        abs_d = ABS(val);
        while ((abs_d > 0) && (i > 0)) {
          revbuf[--i] = (char) (0x30 + abs_d % 10);
          abs_d /= 10;
        }
        if (val == 0) revbuf[--i] = '0';
        else if (val < 0) revbuf[--i] = '-';
        // if enough space in large buffer copy all
        length = MIN(BUFSIZE_L - bi, BUFSIZE_S - i);
        fbt_strncpy(&buf[bi], &revbuf[i], length);
        bi += length;
        break;
      case 'p':
        buf[bi++]='0';
        buf[bi++]='x';
        if (len<2) len=10;  /* ensure that len is large enough */
        if (len!=0) len-=2;  /* make len smaller (preceding '0x') */
      case 'x':
        abs_d =  va_arg(app, unsigned int);
        while ((abs_d > 0) && (i > 0)) {
          if ((abs_d&0xf) < 0xa) {
            revbuf[--i] = 0x30 + (abs_d&0xf);
          } else {
            revbuf[--i] = 0x57 + (abs_d&0xf);
          }
          abs_d /= 16;
        }
        if (abs_d == 0) revbuf[--i] = '0';
        /* fill leading 0s */
        if (len!=0) while (len>(BUFSIZE_S-i)) revbuf[--i]='0'; 
        length = MIN(BUFSIZE_L - bi, BUFSIZE_S - i);
        if (length>len && len!=0) {
          /* ensure that we stay in buffer */
          i=BUFSIZE_S-len;
          length = len;
        }
        fbt_strncpy(&buf[bi], &revbuf[i], length);
        bi += length;
        break;
      case 's':
        pointer = va_arg(app, char*);
        /* ensure that we stay in buffer */
        int slen = fbt_strnlen(pointer, BUFSIZE_L - bi);
        if (slen>len && len!=0) slen=len;
        fbt_strncpy(&buf[bi], pointer, slen);
        bi += slen;
        break;
      case '\0':
        /* end of format string, break out of while loop */
        buf[bi]=format[fi];
        end = 1;
        break;
      default:
        /* we have a % but no valid conversion specifier
           -> we copy the '%' and the following character verbatim */
        buf[bi] = '%';
        bi++;
        buf[bi] = format[fi];
        bi++;
      }
      break;
      case '\0':
        /* end of format string, break out of while loop */
        buf[bi] = '\0';
        end = 1;
        break;
      default:
        buf[bi] = format[fi];
        bi++;
    }
    fi++;
  }
  buf[BUFSIZE_L]=0x0;  /* guard */
  return fllwrite(fd, buf);
}