aboutsummaryrefslogtreecommitdiff
path: root/gcc/testsuite/gcc.dg/analyzer/taint-write-index-1.c
blob: cc7ab1ca4f6ecc5c24edbf49d545a5e2bd98c252 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// TODO: remove need for this option:
/* { dg-additional-options "-fanalyzer-checker=taint" } */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct foo
{
  signed int i;
  char buf[256];
};

struct foo g;
char test_1(FILE *f)
{
  struct foo tmp;

  if (1 == fread(&tmp, sizeof(tmp), 1, f)) { /* { dg-message "\\(\[0-9\]+\\) 'tmp' gets an unchecked value here" "event: tmp gets unchecked value" { xfail *-*-* } } */
                                             /* { dg-message "\\(\[0-9\]+\\) following 'true' branch\\.\\.\\." "event: following true branch" { target *-*-* } .-1 } */
    /* BUG: the following array lookup trusts that the input data's index is
       in the range 0 <= i < 256; otherwise it's accessing the stack */
    g.buf[tmp.i] = 42; // { dg-warning "use of attacker-controlled value 'tmp.i' in array lookup without bounds checking" "warning" } */
    /* { dg-message "\\(\[0-9\]+\\) \\.\\.\\.to here" "event: to here" { target *-*-* } .-1 } */
    /* { dg-message "\\(\[0-9\]+\\) 'tmp.i' has an unchecked value here \\(from 'tmp'\\)" "event: tmp.i has an unchecked value" { xfail *-*-* } .-2 } */
    /* { dg-message "\\(\[0-9\]+\\) use of attacker-controlled value 'tmp.i' in array lookup without bounds checking" "final event" { target *-*-* } .-3 } */
    
    // TOOD: better messages for state changes
  }
  return 0;
}

char test_2(struct foo *f, int i)
{
  /* not a bug: the data is not known to be tainted: */
  return f->buf[f->i];
}

char test_3(FILE *f)
{
  struct foo tmp;

  if (1 == fread(&tmp, sizeof(tmp), 1, f)) {
    if (tmp.i >= 0 && tmp.i < 256) {
      /* not a bug: the access is guarded by upper and lower bounds: */
      g.buf[tmp.i] = 42;
    }
  }
  return 0;
}

char test_4(FILE *f)
{
  struct foo tmp;

  if (1 == fread(&tmp, sizeof(tmp), 1, f)) {
    if (tmp.i >= 0) { /* { dg-message "'tmp.i' has an unchecked value here \\(from 'tmp'\\)" "event: tmp.i has an unchecked value" { xfail *-*-* } } */
      /* { dg-message "'tmp.i' has its lower bound checked here" "event: lower bound checked" { xfail *-*-* } .-1 } */
      g.buf[tmp.i] = 42; /* { dg-warning "use of attacker-controlled value 'tmp.i' in array lookup without upper-bounds checking" "warning" } */
    }
  }
  return 0;
}

char test_5(FILE *f)
{
  struct foo tmp;

  if (1 == fread(&tmp, sizeof(tmp), 1, f)) {
    if (tmp.i < 256) { /* { dg-message "'tmp.i' has an unchecked value here \\(from 'tmp'\\)" "event: tmp.i has an unchecked value" { xfail *-*-* } } */
      /* { dg-message "'tmp.i' has its upper bound checked here" "event: upper bound checked" { xfail *-*-* } .-1 } */
      g.buf[tmp.i] = 42; /* { dg-warning "use of attacker-controlled value 'tmp.i' in array lookup without checking for negative" "warning" } */
    }
  }
  return 0;
}

/* unsigned types have a natural lower bound of 0 */
struct bar
{
  unsigned int i;
  char buf[256];
};

char test_6(FILE *f)
{
  struct bar tmp;

  if (1 == fread(&tmp, sizeof(tmp), 1, f)) {
    g.buf[tmp.i] = 42; /* { dg-warning "use of attacker-controlled value 'tmp.i' in array lookup without upper-bounds checking" } */
  }
  return 0;
}

char test_7(FILE *f)
{
  struct bar tmp;

  if (1 == fread(&tmp, sizeof(tmp), 1, f)) {
    if (tmp.i >= 0) {
      g.buf[tmp.i] = 42; /* { dg-warning "use of attacker-controlled value 'tmp.i' in array lookup without upper-bounds checking" } */
    }
  }
  return 0;
}

char test_8(FILE *f)
{
  struct bar tmp;

  if (1 == fread(&tmp, sizeof(tmp), 1, f)) {
    if (tmp.i < 256) {
      /* not a bug: has an upper bound, and an implicit lower bound: */
      g.buf[tmp.i] = 42;
    }
  }
  return 0;
}

char test_9(FILE *f)
{
  struct foo tmp;

  if (1 == fread(&tmp, sizeof(tmp), 1, f)) {
    if (tmp.i == 42) {
      /* not a bug: tmp.i compared against a specific value: */
      g.buf[tmp.i] = 42; /* { dg-bogus "attacker-controlled" "" { xfail *-*-* } } */
      // TODO: xfail
    }
  }
  return 0;
}