vestigia

Detect where execution depends on secrets.
git clone git://git.ppad.tech/vestigia.git
Log | Files | Refs | README | LICENSE

vestigia.c (1919B)


      1 /*
      2  * vestigia.c: the marks vestigia.h declares.
      3  *
      4  * Copyright (c) 2026 Jared Tobin
      5  * License: MIT
      6  *
      7  * A site is reported at a run-time address, and only the loader
      8  * knows where it put the object holding it. On Linux, when the
      9  * environment names a file in VESTIGIA_OBJECTS (vestigia sets it),
     10  * the first secret mark of any bytes writes there each loaded
     11  * object's load bias and path, so a site can be named by its object
     12  * and its address in it; that the file was written is also how
     13  * vestigia knows a secret was marked at all. That needs
     14  * dl_iterate_phdr, which glibc declares only under _GNU_SOURCE, set
     15  * here before any header can settle the feature set; this is why
     16  * the marks are a compilation unit, not a header.
     17  */
     18 #ifdef __linux__
     19 #define _GNU_SOURCE
     20 #include <link.h>
     21 #include <stdio.h>
     22 #include <stdlib.h>
     23 #include <unistd.h>
     24 #endif
     25 
     26 #include <valgrind/memcheck.h>
     27 
     28 #include "vestigia.h"
     29 
     30 #ifdef __linux__
     31 static int object_(struct dl_phdr_info *info, size_t size, void *data) {
     32   FILE *f = data;
     33   char exe[4096];
     34   const char *name = info->dlpi_name;
     35   (void)size;
     36   /* the main program is listed unnamed */
     37   if (name == NULL || name[0] == '\0') {
     38     ssize_t n = readlink("/proc/self/exe", exe, sizeof exe - 1);
     39     if (n <= 0) return 0;
     40     exe[n] = '\0';
     41     name = exe;
     42   }
     43   fprintf(f, "%lx %s\n", (unsigned long)info->dlpi_addr, name);
     44   return 0;
     45 }
     46 
     47 static void objects_(void) {
     48   static int written = 0;
     49   const char *path;
     50   FILE *f;
     51   if (written) return;
     52   written = 1;
     53   path = getenv("VESTIGIA_OBJECTS");
     54   if (path == NULL) return;
     55   f = fopen(path, "w");
     56   if (f == NULL) return;
     57   dl_iterate_phdr(object_, f);
     58   fclose(f);
     59 }
     60 #else
     61 static void objects_(void) {}
     62 #endif
     63 
     64 void vestigia_secret(void *p, size_t n) {
     65   if (n > 0) objects_();
     66   (void)VALGRIND_MAKE_MEM_UNDEFINED(p, n);
     67 }
     68 
     69 void vestigia_public(void *p, size_t n) {
     70   (void)VALGRIND_MAKE_MEM_DEFINED(p, n);
     71 }