(root)/
gcc-13.2.0/
gcc/
testsuite/
gcc.dg/
analyzer/
taint-write-offset-1.c
       1  // TODO: remove need for this option:
       2  /* { dg-additional-options "-fanalyzer-checker=taint" } */
       3  
       4  #include <stdio.h>
       5  #include <stdlib.h>
       6  #include <string.h>
       7  
       8  struct foo
       9  {
      10    ssize_t offset;
      11  };
      12  
      13  char *p;
      14  
      15  char test_1(FILE *f)
      16  {
      17    struct foo tmp;
      18  
      19    if (1 == fread(&tmp, sizeof(tmp), 1, f)) { /* { dg-message "\\(\[0-9\]+\\) 'tmp' gets an unchecked value here" "event: tmp gets unchecked value" { xfail *-*-* } } */
      20                                               /* { dg-message "\\(\[0-9\]+\\) following 'true' branch\\.\\.\\." "event: following true branch" { target *-*-* } .-1 } */
      21      /* BUG: the following array lookup trusts that the input data's index is
      22         in the range 0 <= i < 256; otherwise it's accessing the stack */
      23      *(p + tmp.offset) = 42; // { dg-warning "use of attacker-controlled value 'tmp.offset' as offset without bounds checking" "warning" } */
      24      /* { dg-message "\\(\[0-9\]+\\) \\.\\.\\.to here" "event: to here" { target *-*-* } .-1 } */
      25      /* { dg-message "\\(\[0-9\]+\\) 'tmp.offset' has an unchecked value here \\(from 'tmp'\\)" "event: tmp.offset has an unchecked value" { xfail *-*-* } .-2 } */
      26      /* { dg-message "\\(\[0-9\]+\\) use of attacker-controlled value 'tmp.offset' as offset without bounds checking" "final event" { target *-*-* } .-3 } */
      27      
      28      // TOOD: better messages for state changes
      29    }
      30    return 0;
      31  }
      32  
      33  char test_2(struct foo *f)
      34  {
      35    /* not a bug: the data is not known to be tainted: */
      36    *(p + f->offset) = 42;
      37  }
      38  
      39  char test_3(FILE *f)
      40  {
      41    struct foo tmp;
      42  
      43    if (1 == fread(&tmp, sizeof(tmp), 1, f)) {
      44      if (tmp.offset >= 0 && tmp.offset < 256) {
      45        /* not a bug: the access is guarded by upper and lower bounds: */
      46        *(p + tmp.offset) = 42;
      47      }
      48    }
      49    return 0;
      50  }
      51  
      52  char test_4(FILE *f)
      53  {
      54    struct foo tmp;
      55  
      56    if (1 == fread(&tmp, sizeof(tmp), 1, f)) {
      57      if (tmp.offset >= 0) { /* { dg-message "'tmp.offset' has an unchecked value here \\(from 'tmp'\\)" "event: tmp.offset has an unchecked value" { xfail *-*-* } } */
      58        /* { dg-message "'tmp.offset' has its lower bound checked here" "event: lower bound checked" { xfail *-*-* } .-1 } */
      59        *(p + tmp.offset) = 42; /* { dg-warning "use of attacker-controlled value 'tmp.offset' as offset without upper-bounds checking" "warning" } */
      60      }
      61    }
      62    return 0;
      63  }
      64  
      65  char test_5(FILE *f)
      66  {
      67    struct foo tmp;
      68  
      69    if (1 == fread(&tmp, sizeof(tmp), 1, f)) {
      70      if (tmp.offset < 256) { /* { dg-message "'tmp.offset' has an unchecked value here \\(from 'tmp'\\)" "event: tmp.offset has an unchecked value" { xfail *-*-* } } */
      71        /* { dg-message "'tmp.offset' has its upper bound checked here" "event: upper bound checked" { xfail *-*-* } .-1 } */
      72        *(p + tmp.offset) = 42; /* { dg-warning "use of attacker-controlled value 'tmp.offset' as offset without lower-bounds checking" "warning" } */
      73      }
      74    }
      75    return 0;
      76  }
      77  
      78  /* unsigned types have a natural lower bound of 0 */
      79  struct bar
      80  {
      81    unsigned int offset;
      82    char buf[256];
      83  };
      84  
      85  char test_6(FILE *f)
      86  {
      87    struct bar tmp;
      88  
      89    if (1 == fread(&tmp, sizeof(tmp), 1, f)) {
      90      *(p + tmp.offset) = 42; /* { dg-warning "use of attacker-controlled value 'tmp.offset' as offset without upper-bounds checking" } */
      91    }
      92    return 0;
      93  }
      94  
      95  char test_7(FILE *f)
      96  {
      97    struct bar tmp;
      98  
      99    if (1 == fread(&tmp, sizeof(tmp), 1, f)) {
     100      if (tmp.offset >= 0) {
     101        *(p + tmp.offset) = 42; /* { dg-warning "use of attacker-controlled value 'tmp.offset' as offset without upper-bounds checking" } */
     102      }
     103    }
     104    return 0;
     105  }
     106  
     107  char test_8(FILE *f)
     108  {
     109    struct bar tmp;
     110  
     111    if (1 == fread(&tmp, sizeof(tmp), 1, f)) {
     112      if (tmp.offset < 256) {
     113        /* not a bug: has an upper bound, and an implicit lower bound: */
     114        *(p + tmp.offset) = 42;
     115      }
     116    }
     117    return 0;
     118  }
     119  
     120  char test_9(FILE *f)
     121  {
     122    struct foo tmp;
     123  
     124    if (1 == fread(&tmp, sizeof(tmp), 1, f)) {
     125      if (tmp.offset == 42) {
     126        /* not a bug: tmp.offset compared against a specific value: */
     127        *(p + tmp.offset) = 42; /* { dg-bogus "tainted" "" { xfail *-*-* } } */
     128        // TODO: xfail
     129      }
     130    }
     131    return 0;
     132  }