aboutsummaryrefslogtreecommitdiff
path: root/gcc/testsuite/gcc.dg/plugin/infoleak-antipatterns-1.c
blob: 84789a7f157e7e4a57dfcd4e9fc4c089447ed524 (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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/* Adapted and simplified decls from linux kernel headers.  */

/* { dg-do compile } */
/* { dg-options "-fanalyzer" } */
/* { dg-require-effective-target analyzer } */
/* { dg-skip-if "structure layout assumption not met" { default_packed } } */

typedef unsigned char u8;
typedef unsigned __INT16_TYPE__ u16;
typedef unsigned __INT32_TYPE__ u32;
typedef __SIZE_TYPE__ size_t;

#define   EFAULT          14

#include "test-uaccess.h"

typedef unsigned int gfp_t;
#define GFP_KERNEL 0

void kfree(const void *);
void *kmalloc(size_t size, gfp_t flags)
  __attribute__((malloc (kfree)));

/* Adapted from antipatterns.ko:infoleak.c (GPL-v2.0).   */

struct infoleak_buf
{
  char buf[256];
};

int infoleak_stack_no_init(void __user *dst)
{
  struct infoleak_buf st; /* { dg-message "region created on stack here" "where" } */
  /* { dg-message "capacity: 256 bytes" "capacity" { target *-*-* } .-1 } */
  
  /* No initialization of "st" at all.  */
  if (copy_to_user(dst, &st, sizeof(st))) /* { dg-warning "potential exposure of sensitive information by copying uninitialized data from stack" "warning" } */
    /* { dg-message "256 bytes are uninitialized" "note how much" { target *-*-* } .-1 } */
    return -EFAULT;
  return 0;
}

int infoleak_heap_no_init(void __user *dst)
{
  struct infoleak_buf *heapbuf = kmalloc(sizeof(*heapbuf), GFP_KERNEL);
  /* No initialization of "heapbuf" at all.  */

  /* TODO: we also don't check that heapbuf could be NULL when copying
     from it.  */
  if (copy_to_user(dst, heapbuf, sizeof(*heapbuf))) /* { dg-warning "exposure" "warning" { xfail *-*-* } } */
    /* TODO(xfail).  */
    return -EFAULT; /* { dg-warning "leak of 'heapbuf'" } */

  kfree(heapbuf);
  return 0;
}

struct infoleak_2
{
  u32 a;
  u32 b; /* { dg-message "field 'b' is uninitialized \\(4 bytes\\)" } */
};

int infoleak_stack_missing_a_field(void __user *dst, u32 v)
{
  struct infoleak_2 st; /* { dg-message "region created on stack here" "where" } */
  /* { dg-message "capacity: 8 bytes" "capacity" { target *-*-* } .-1 } */
  
  st.a = v;
  /* No initialization of "st.b".  */
  if (copy_to_user(dst, &st, sizeof(st))) /* { dg-warning "potential exposure of sensitive information by copying uninitialized data from stack" "warning" } */
    /* { dg-message "4 bytes are uninitialized" "note how much" { target *-*-* } .-1 } */
    return -EFAULT;
  return 0;
}

int infoleak_heap_missing_a_field(void __user *dst, u32 v)
{
  struct infoleak_2 *heapbuf = kmalloc(sizeof(*heapbuf), GFP_KERNEL);
  heapbuf->a = v; /* { dg-warning "dereference of possibly-NULL 'heapbuf'" } */
  /* No initialization of "heapbuf->b".  */
  if (copy_to_user(dst, heapbuf, sizeof(*heapbuf))) /* { dg-warning "exposure" "warning" { xfail *-*-* } } */
    /* TODO(xfail).  */
    {
      kfree(heapbuf);
      return -EFAULT;
    }
  kfree(heapbuf);
  return 0;
}

struct infoleak_3
{
  u8 a; /* { dg-message "padding after field 'a' is uninitialized \\(3 bytes\\)" } */
  /* padding here */
  u32 b;
};

int infoleak_stack_padding(void __user *dst, u8 p, u32 q)
{
  struct infoleak_3 st; /* { dg-message "region created on stack here" "where" } */
  /* { dg-message "capacity: 8 bytes" "capacity" { target *-*-* } .-1 } */

  st.a = p;
  st.b = q;
  /* No initialization of padding.  */
  if (copy_to_user(dst, &st, sizeof(st))) /* { dg-warning "potential exposure of sensitive information by copying uninitialized data from stack" "warning" } */
    /* { dg-message "3 bytes are uninitialized" "note how much" { target *-*-* } .-1 } */
    return -EFAULT;
  return 0;
}

int infoleak_stack_unchecked_err(void __user *dst, void __user *src)
{
  struct infoleak_buf st;  /* { dg-message "region created on stack here" "where" } */
  /* { dg-message "capacity: 256 bytes" "capacity" { target *-*-* } .-1 } */

  /*
   * If the copy_from_user call fails, then st is still uninitialized,
   * and if the copy_to_user call succeds, we have an infoleak.
   */
  int err = copy_from_user (&st, src, sizeof(st)); /* { dg-message "when 'copy_from_user' fails" } */
  err |= copy_to_user (dst, &st, sizeof(st)); /* { dg-warning "exposure" "warning" } */
  /* { dg-message "256 bytes are uninitialized" "note how much" { target *-*-* } .-1 } */
  /* Actually, it's *up to* 256 bytes.  */

  if (err)
    return -EFAULT;
  return 0;
}

struct infoleak_4
{
  union {
    u8 f1;
    u32 f2;
  } u;
};

int infoleak_stack_union(void __user *dst, u8 v)
{
  struct infoleak_4 st;
  /*
   * This write only initializes the u8 within the union "u",
   * leaving the remaining 3 bytes uninitialized.
   */
  st.u.f1 = v;
  if (copy_to_user(dst, &st, sizeof(st))) /* { dg-warning "potential exposure of sensitive information by copying uninitialized data from stack" "warning" } */
    /* { dg-message "3 bytes are uninitialized" "note how much" { target *-*-* } .-1 } */
    return -EFAULT;
  return 0;
}

struct infoleak_5
{
  void *ptr;
};

int infoleak_stack_kernel_ptr(void __user *dst, void *kp)
{
  struct infoleak_5 st;
  /* This writes a kernel-space pointer into a user space buffer.  */
  st.ptr = kp;
  if (copy_to_user(dst, &st, sizeof(st))) // TODO: we don't complain about this yet
    return -EFAULT;
  return 0;
}