github.com/anchore/syft@v1.4.2-0.20240516191711-1bec1fc5d397/syft/file/cataloger/executable/test-fixtures/elf/project/main.c (about)

     1  #include <stdio.h>
     2  #include <stdlib.h>
     3  #include <stdint.h>
     4  
     5  // source: https://github.com/trailofbits/clang-cfi-showcase/blob/master/cfi_icall.c
     6  
     7  typedef int (*int_arg_fn)(int);
     8  typedef int (*float_arg_fn)(float);
     9  
    10  static int int_arg(int arg) {
    11      printf("In %s: (%d)\n", __FUNCTION__, arg);
    12      return 0;
    13  }
    14  
    15  static int float_arg(float arg) {
    16      printf("CFI should protect transfer to here\n");
    17      printf("In %s: (%f)\n", __FUNCTION__, (double)arg);
    18      return 0;
    19  }
    20  
    21  static int bad_int_arg(int arg) {
    22      printf("CFI will not protect transfer to here\n");
    23      printf("In %s: (%d)\n", __FUNCTION__, arg);
    24      return 0;
    25  }
    26  
    27  static int not_entry_point(int arg) {
    28      // nop sled for x86 / x86-64
    29      // these instructions act as a buffer
    30      // for an indirect control flow transfer to skip
    31      // a valid function entry point, but continue
    32      // to execute normal code
    33      __asm__ volatile (
    34              "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n"
    35              "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n"
    36              "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n"
    37              "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n"
    38              "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n"
    39              "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n"
    40              "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n"
    41              "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n"
    42              );
    43      printf("CFI ensures control flow only transfers to potentially valid destinations\n");
    44      printf("In %s: (%d)\n", __FUNCTION__, arg);
    45      // need to exit or the program will segfault anyway,
    46      // since the indirect call skipped the function preamble
    47      exit(arg);
    48  }
    49  
    50  struct foo {
    51      int_arg_fn int_funcs[1];
    52      int_arg_fn bad_int_funcs[1];
    53      float_arg_fn float_funcs[1];
    54      int_arg_fn not_entries[1];
    55  };
    56  
    57  // the struct aligns the function pointer arrays
    58  // so indexing past the end will reliably
    59  // call working function pointers
    60  static struct foo f = {
    61      .int_funcs = {int_arg},
    62      .bad_int_funcs = {bad_int_arg},
    63      .float_funcs = {float_arg},
    64      .not_entries = {(int_arg_fn)((uintptr_t)(not_entry_point)+0x20)}
    65  };
    66  
    67  void simple1() {
    68      char buf[16];
    69      fgets(buf, sizeof(buf), stdin);
    70      printf(buf);
    71  }
    72  
    73  void simple2() {
    74      char buf[16];
    75      scanf("%s", buf);
    76  }
    77  
    78  
    79  int main(int argc, char **argv) {
    80      if(argc != 2) {
    81          printf("Usage: %s <option>\n", argv[0]);
    82          printf("Option values:\n");
    83          printf("\t0\tCall correct function\n");
    84          printf("\t1\tCall the wrong function but with the same signature\n");
    85          printf("\t2\tCall a float function with an int function signature\n");
    86          printf("\t3\tCall into the middle of a function\n");
    87          printf("\n");
    88          printf("\tAll other options are undefined, but should be caught by CFI :)\n");
    89          printf("\n\n");
    90          printf("Here are some pointers so clang doesn't optimize away members of `struct foo f`:\n");
    91          printf("\tint_funcs: %p\n", (void*)f.int_funcs);
    92          printf("\tbad_int_funcs: %p\n", (void*)f.bad_int_funcs);
    93          printf("\tfloat_funcs: %p\n", (void*)f.float_funcs);
    94          printf("\tnot_entries: %p\n", (void*)f.not_entries);
    95          return 1;
    96      }
    97  
    98      simple1();
    99      simple2();
   100  
   101      printf("Calling a function:\n");
   102  
   103      int idx = argv[1][0] - '0';
   104  
   105      return f.int_funcs[idx](idx);
   106  }