aboutsummaryrefslogtreecommitdiff
path: root/gcc/testsuite/gcc.dg/plugin/taint-antipatterns-1.c
blob: cdd9a4f1f50f2f9fe4b28d21afcba817c5d304ba (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
/* { dg-do compile } */
/* { dg-options "-fanalyzer" } */
/* { dg-require-effective-target analyzer } */

#include "test-uaccess.h"

/* Adapted and simplified decls from linux kernel headers.  */

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

#define   EFAULT          14

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:taint.c (GPL-v2.0).   */

struct cmd_1
{
  u32 idx;
  u32 val;
};

static u32 arr[16];

int taint_array_access(void __user *src)
{
  struct cmd_1 cmd;
  if (copy_from_user(&cmd, src, sizeof(cmd)))
    return -EFAULT;
  /*
   * cmd.idx is an unsanitized value from user-space, hence
   * this is an arbitrary kernel memory access.
   */
  arr[cmd.idx] = cmd.val; /* { dg-warning "use of attacker-controlled value 'cmd.idx' in array lookup without upper-bounds checking" } */
  return 0;
}

struct cmd_2
{
  s32 idx;
  u32 val;
};

int taint_signed_array_access(void __user *src)
{
  struct cmd_2 cmd;
  if (copy_from_user(&cmd, src, sizeof(cmd)))
    return -EFAULT;
  if (cmd.idx >= 16)
    return -EFAULT;

  /*
   * cmd.idx hasn't been checked for being negative, hence
   * this is an arbitrary kernel memory access.
   */
  arr[cmd.idx] = cmd.val; /* { dg-warning "use of attacker-controlled value 'cmd.idx' in array lookup without checking for negative" } */
  return 0;
}

struct cmd_s32_binop
{
  s32 a;
  s32 b;
  s32 result;
};

int taint_divide_by_zero_direct(void __user *uptr)
{
  struct cmd_s32_binop cmd;
  if (copy_from_user(&cmd, uptr, sizeof(cmd)))
    return -EFAULT;

  /* cmd.b is attacker-controlled and could be zero */
  cmd.result = cmd.a / cmd.b; /* { dg-warning "use of attacker-controlled value 'cmd.b' as divisor without checking for zero" } */

  if (copy_to_user (uptr, &cmd, sizeof(cmd)))
    return -EFAULT;
  return 0;
}

int taint_divide_by_zero_compound(void __user *uptr)
{
  struct cmd_s32_binop cmd;
  if (copy_from_user(&cmd, uptr, sizeof(cmd)))
    return -EFAULT;

  /*
   * cmd.b is attacker-controlled and could be -1, hence
   * the divisor could be zero
   */
  cmd.result = cmd.a / (cmd.b + 1); /* { dg-warning "use of attacker-controlled value 'cmd.b \\+ 1' as divisor without checking for zero" } */

  if (copy_to_user (uptr, &cmd, sizeof(cmd)))
    return -EFAULT;
  return 0;
}

int taint_mod_by_zero_direct(void __user *uptr)
{
  struct cmd_s32_binop cmd;
  if (copy_from_user(&cmd, uptr, sizeof(cmd)))
    return -EFAULT;

  /* cmd.b is attacker-controlled and could be zero */
  cmd.result = cmd.a % cmd.b; /* { dg-warning "use of attacker-controlled value 'cmd.b' as divisor without checking for zero" } */

  if (copy_to_user (uptr, &cmd, sizeof(cmd)))
    return -EFAULT;
  return 0;
}

int taint_mod_by_zero_compound(void __user *uptr)
{
  struct cmd_s32_binop cmd;
  if (copy_from_user(&cmd, uptr, sizeof(cmd)))
    return -EFAULT;

  /*
   * cmd.b is attacker-controlled and could be -1, hence
   * the divisor could be zero
   */
  cmd.result = cmd.a % (cmd.b + 1); /* { dg-warning "use of attacker-controlled value 'cmd.b \\+ 1' as divisor without checking for zero" } */

  if (copy_to_user (uptr, &cmd, sizeof(cmd)))
    return -EFAULT;
  return 0;
}

/* TODO: etc.  */