Skip to content

Commit

Permalink
Merge pull request #913 from criblio/feat-terraform-test
Browse files Browse the repository at this point in the history
Support Go static stripped executables
  • Loading branch information
jrcheli authored May 6, 2022
2 parents f1cf9d4 + 03fd6ff commit 311a77e
Show file tree
Hide file tree
Showing 11 changed files with 531 additions and 202 deletions.
120 changes: 0 additions & 120 deletions src/scopeelf.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@
#include "fn.h"
#include "scopeelf.h"

#define GOPCLNTAB_MAGIC_112 0xfffffffb
#define GOPCLNTAB_MAGIC_116 0xfffffffa

void
freeElf(char *buf, size_t len)
{
Expand Down Expand Up @@ -336,123 +333,6 @@ getSymbol(const char *buf, char *sname)
return (void *)symaddr;
}

void *
getGoSymbol(const char *buf, char *sname)
{
int i;
Elf64_Addr symaddr = 0;
Elf64_Ehdr *ehdr;
Elf64_Shdr *sections;
const char *section_strtab = NULL;
const char *sec_name = NULL;

if (!buf || !sname) return NULL;

ehdr = (Elf64_Ehdr *)buf;
sections = (Elf64_Shdr *)((char *)buf + ehdr->e_shoff);
section_strtab = (char *)buf + sections[ehdr->e_shstrndx].sh_offset;

for (i = 0; i < ehdr->e_shnum; i++) {
sec_name = section_strtab + sections[i].sh_name;
if (scope_strcmp(".gopclntab", sec_name) == 0) {
const void *pclntab_addr = buf + sections[i].sh_offset;
/*
Go symbol table is stored in the .gopclntab section
More info: https://docs.google.com/document/d/1lyPIbmsYbXnpNj57a261hgOYVpNRcgydurVQIyZOz_o/pub
*/
uint32_t magic = *((const uint32_t *)(pclntab_addr));
if (magic == GOPCLNTAB_MAGIC_112) {
uint64_t sym_count = *((const uint64_t *)(pclntab_addr + 8));
const void *symtab_addr = pclntab_addr + 16;

for(i=0; i<sym_count; i++) {
uint64_t sym_addr = *((const uint64_t *)(symtab_addr));
uint64_t func_offset = *((const uint64_t *)(symtab_addr + 8));
uint32_t name_offset = *((const uint32_t *)(pclntab_addr + func_offset + 8));
const char *func_name = (const char *)(pclntab_addr + name_offset);

if (scope_strcmp(sname, func_name) == 0) {
symaddr = sym_addr;
scopeLog(CFG_LOG_TRACE, "symbol found %s = 0x%08lx\n", func_name, sym_addr);
break;
}
symtab_addr += 16;
}
} else if (magic == GOPCLNTAB_MAGIC_116) {
uint64_t sym_count = *((const uint64_t *)(pclntab_addr + 8));
uint64_t funcnametab_offset = *((const uint64_t *)(pclntab_addr + (3 * 8)));
uint64_t pclntab_offset = *((const uint64_t *)(pclntab_addr + (7 * 8)));
const void *symtab_addr = pclntab_addr + pclntab_offset;
for (i = 0; i < sym_count; i++) {
uint64_t sym_addr = *((const uint64_t *)(symtab_addr));
uint64_t func_offset = *((const uint64_t *)(symtab_addr + 8));
uint32_t name_offset = *((const uint32_t *)(pclntab_addr + pclntab_offset + func_offset + 8));
const char *func_name = (const char *)(pclntab_addr + funcnametab_offset + name_offset);
if (scope_strcmp(sname, func_name) == 0) {
symaddr = sym_addr;
scopeLog(CFG_LOG_TRACE, "symbol found %s = 0x%08lx\n", func_name, sym_addr);
break;
}
symtab_addr += 16;
}
} else {
scopeLog(CFG_LOG_DEBUG, "Invalid header in .gopclntab");
break;
}
break;
}
}

return (void *)symaddr;
}

void *
getGoVersionAddr(const char* buf)
{
int i;
Elf64_Ehdr *ehdr;
Elf64_Shdr *sections;
const char *section_strtab = NULL;
const char *sec_name;
const char *sec_data;

ehdr = (Elf64_Ehdr *)buf;
sections = (Elf64_Shdr *)(buf + ehdr->e_shoff);
section_strtab = (char *)buf + sections[ehdr->e_shstrndx].sh_offset;
const char magic[0xe] = "\xff Go buildinf:";
void *go_build_ver_addr = NULL;

for (i = 0; i < ehdr->e_shnum; i++) {
sec_name = section_strtab + sections[i].sh_name;
sec_data = (const char *)buf + sections[i].sh_offset;
// Since go1.13, the .go.buildinfo section has been added to
// identify where runtime.buildVersion exists, for the case where
// go apps have been stripped of their symbols.

// offset into sec_data field contents
// -----------------------------------------------------------
// 0x0 build info magic = "\xff Go buildinf:"
// 0xe binary ptrSize
// 0xf endianness
// 0x10 pointer to string runtime.buildVersion
// 0x10 + ptrSize pointer to runtime.modinfo
// 0x10 + 2 * ptr size pointer to build flags

if (!scope_strcmp(sec_name, ".go.buildinfo") &&
(sections[i].sh_size >= 0x18) &&
(!scope_memcmp(&sec_data[0], magic, sizeof(magic))) &&
(sec_data[0xe] == 0x08) && // 64 bit executables only
(sec_data[0xf] == 0x00)) { // little-endian

uint64_t *addressPtr = (uint64_t*)&sec_data[0x10];

go_build_ver_addr = (void*)*addressPtr;
}
}

return go_build_ver_addr;
}

bool
is_static(char *buf)
{
Expand Down
2 changes: 0 additions & 2 deletions src/scopeelf.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ int doGotcha(struct link_map *, got_list_t *, Elf64_Rela *, Elf64_Sym *, char *,
int getElfEntries(struct link_map *, Elf64_Rela **, Elf64_Sym **, char **, int *rsz);
Elf64_Shdr* getElfSection(char *, const char *);
void * getSymbol(const char *, char *);
void * getGoSymbol(const char *, char *);
void * getGoVersionAddr(const char*);
bool is_static(char *);
bool is_go(char *);
bool is_musl(char *);
Expand Down
Loading

0 comments on commit 311a77e

Please sign in to comment.