Ver Fonte

Use libelf to find the location of the settings struct

Bryan Drewery há 12 anos atrás
pai
commit
bb221cf874
2 ficheiros alterados com 78 adições e 27 exclusões
  1. 1 0
      doc/UPDATES
  2. 77 27
      src/binary.c

+ 1 - 0
doc/UPDATES

@@ -10,6 +10,7 @@ maint
   * Fix build detecting invalid openssl installations (ones with only static libs)
   * Give hint on bot when disconnected from hub for reason
   * Fix cmd_netnick formatting issue with offline bots
+  * Fix crash when built with clang (FreeBSD)
 
 1.4.3
   * Default 'set promisc' to ignore since it's usually a false positive

+ 77 - 27
src/binary.c

@@ -49,6 +49,9 @@
 #include <fcntl.h>
 #include <termios.h>
 
+#include <libelf.h>
+#include <gelf.h>
+
 settings_t settings = {
   SETTINGS_HEADER,
   /* -- STATIC -- */
@@ -69,31 +72,78 @@ static void tellconfig(settings_t *);
 
 int checked_bin_buf = 0;
 
-#define MMAP_LOOP(_offset, _block_len, _total)		\
-  for ((_offset) = 0; 					\
-       (_offset) < (_total); 				\
-       (_offset) += (_block_len)/*,			\
-       (_len) = ((_total) - (_offset)) < (_block_len) ? \
-              ((_total) - (_offset)) : 			\
-              (_block_len)*/				\
-      )
-
-static inline size_t
-memmem_aligned(unsigned char *buf, size_t buf_size, size_t offset, void *mem,
-    size_t mem_size)
-{
-  MMAP_LOOP(offset, mem_size, buf_size) {
-    if (!memcmp(&buf[offset], mem, mem_size)) {
-      return offset;
-    }
-  }
-  return buf_size;
-}
-
 #define MMAP_READ(_map, _dest, _offset, _len)	\
   memcpy((_dest), &(_map)[(_offset)], (_len));	\
   (_offset) += (_len);
 
+static size_t
+elf_find_data_offset(int fd) {
+  Elf *elf = NULL;
+  GElf_Shdr shdr;
+  Elf_Scn *scn = NULL;
+  const char *sh_name;
+  size_t shstrndx;
+  size_t offset = 0;
+
+  if (elf_version(EV_CURRENT) == EV_NONE)
+    goto failure;
+
+  if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
+    goto failure;
+
+  if (elf_kind(elf) != ELF_K_ELF)
+    goto failure;
+
+  elf_getshdrstrndx(elf, &shstrndx);
+
+  while ((scn = elf_nextscn(elf, scn)) != NULL) {
+    if (gelf_getshdr(scn, &shdr) != &shdr)
+      goto failure;
+    if (shdr.sh_type != SHT_PROGBITS)
+      continue;
+    if ((sh_name = elf_strptr(elf, shstrndx, shdr.sh_name)) == NULL)
+      goto failure;
+    if (strcmp(sh_name, ".data"))
+      continue;
+    offset = shdr.sh_offset;
+    break;
+  }
+
+  goto cleanup;
+
+failure:
+  offset = 0;
+#ifdef DEBUG
+  printf("Elf error: %s\n", elf_errmsg(-1));
+#endif
+
+cleanup:
+
+  if (elf != NULL)
+    elf_end(elf);
+  lseek(fd, 0, SEEK_SET);
+
+  return offset;
+}
+
+static size_t
+elf_find_data_mem_offset(int fd, unsigned char *map, size_t map_size,
+    void *symbol_header, size_t symbol_header_len) {
+  size_t data_offset;
+  unsigned char *symbol_start;
+
+  if ((data_offset = elf_find_data_offset(fd)) == 0)
+    return 0;
+
+  symbol_start = (unsigned char*)memmem(map + data_offset,
+      map_size - data_offset, symbol_header, symbol_header_len);
+
+  if (symbol_start == NULL)
+    return 0;
+
+  return symbol_start - map;
+}
+
 static char *
 bin_checksum(const char *fname, int todo)
 {
@@ -120,8 +170,8 @@ bin_checksum(const char *fname, int todo)
     size = lseek(fd, 0, SEEK_END);
     map = (unsigned char*) mmap(0, size, PROT_READ, MAP_SHARED, fd, 0);
     if ((void*)map == MAP_FAILED) goto fatal;
-    if ((offset = memmem_aligned(map, size, offset, &settings.prefix,
-        PREFIXLEN)) >= size) {
+    if ((offset = elf_find_data_mem_offset(fd, map, size, &settings.prefix,
+        PREFIXLEN)) == 0) {
       goto fatal;
     }
     MD5_Update(&ctx, map, offset);
@@ -146,8 +196,8 @@ bin_checksum(const char *fname, int todo)
     if ((void*)map == MAP_FAILED) goto fatal;
 
     /* Find the packdata */
-    if ((offset = memmem_aligned(map, size, offset, &settings.prefix,
-        PREFIXLEN)) >= size) {
+    if ((offset = elf_find_data_mem_offset(fd, map, size, &settings.prefix,
+        PREFIXLEN)) == 0) {
       goto fatal;
     }
     MD5_Update(&ctx, map, offset);
@@ -193,8 +243,8 @@ bin_checksum(const char *fname, int todo)
     if ((void*)map == MAP_FAILED) goto fatal;
 
     /* Find settings struct in original binary */
-    if ((offset = memmem_aligned(map, size, offset, &settings.prefix,
-        PREFIXLEN)) >= size) {
+    if ((offset = elf_find_data_mem_offset(fd, map, size, &settings.prefix,
+        PREFIXLEN)) == 0) {
       goto fatal;
     }
     MD5_Update(&ctx, map, offset);