aboutsummaryrefslogtreecommitdiff
path: root/gcc/asan.h
blob: 9efd33f9b86babbc10c4553c31b86950a313a242 (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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
/* AddressSanitizer, a fast memory error detector.
   Copyright (C) 2011-2020 Free Software Foundation, Inc.
   Contributed by Kostya Serebryany <kcc@google.com>

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.

GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */

#ifndef TREE_ASAN
#define TREE_ASAN

extern void asan_function_start (void);
extern void asan_finish_file (void);
extern rtx_insn *asan_emit_stack_protection (rtx, rtx, unsigned int,
					     HOST_WIDE_INT *, tree *, int);
extern rtx_insn *asan_emit_allocas_unpoison (rtx, rtx, rtx_insn *);
extern bool asan_protect_global (tree, bool ignore_decl_rtl_set_p = false);
extern void initialize_sanitizer_builtins (void);
extern tree asan_dynamic_init_call (bool);
extern bool asan_expand_check_ifn (gimple_stmt_iterator *, bool);
extern bool asan_expand_mark_ifn (gimple_stmt_iterator *);
extern bool asan_expand_poison_ifn (gimple_stmt_iterator *, bool *,
				    hash_map<tree, tree> &);

extern gimple_stmt_iterator create_cond_insert_point
     (gimple_stmt_iterator *, bool, bool, bool, basic_block *, basic_block *);

/* Alias set for accessing the shadow memory.  */
extern alias_set_type asan_shadow_set;

/* Hash set of labels that are either used in a goto, or their address
   has been taken.  */
extern hash_set <tree> *asan_used_labels;

/* Shadow memory is found at
   (address >> ASAN_SHADOW_SHIFT) + asan_shadow_offset ().  */
#define ASAN_SHADOW_SHIFT	3
#define ASAN_SHADOW_GRANULARITY (1UL << ASAN_SHADOW_SHIFT)

/* Red zone size, stack and global variables are padded by ASAN_RED_ZONE_SIZE
   up to 2 * ASAN_RED_ZONE_SIZE - 1 bytes.  */
#define ASAN_RED_ZONE_SIZE	32

/* Stack variable use more compact red zones.  The size includes also
   size of variable itself.  */

#define ASAN_MIN_RED_ZONE_SIZE	16

/* Shadow memory values for stack protection.  Left is below protected vars,
   the first pointer in stack corresponding to that offset contains
   ASAN_STACK_FRAME_MAGIC word, the second pointer to a string describing
   the frame.  Middle is for padding in between variables, right is
   above the last protected variable and partial immediately after variables
   up to ASAN_RED_ZONE_SIZE alignment.  */
#define ASAN_STACK_MAGIC_LEFT		  0xf1
#define ASAN_STACK_MAGIC_MIDDLE		  0xf2
#define ASAN_STACK_MAGIC_RIGHT		  0xf3
#define ASAN_STACK_MAGIC_USE_AFTER_RET	  0xf5
#define ASAN_STACK_MAGIC_USE_AFTER_SCOPE  0xf8

#define ASAN_STACK_FRAME_MAGIC		0x41b58ab3
#define ASAN_STACK_RETIRED_MAGIC	0x45e0360e

#define ASAN_USE_AFTER_SCOPE_ATTRIBUTE	"use after scope memory"

/* Various flags for Asan builtins.  */
enum asan_check_flags
{
  ASAN_CHECK_STORE = 1 << 0,
  ASAN_CHECK_SCALAR_ACCESS = 1 << 1,
  ASAN_CHECK_NON_ZERO_LEN = 1 << 2,
  ASAN_CHECK_LAST = 1 << 3
};

/* Flags for Asan check builtins.  */
#define IFN_ASAN_MARK_FLAGS DEF(POISON), DEF(UNPOISON)

enum asan_mark_flags
{
#define DEF(X) ASAN_MARK_##X
  IFN_ASAN_MARK_FLAGS
#undef DEF
};

/* Return true if STMT is ASAN_MARK with FLAG as first argument.  */
extern bool asan_mark_p (gimple *stmt, enum asan_mark_flags flag);

/* Return the size of padding needed to insert after a protected
   decl of SIZE.  */

static inline unsigned int
asan_red_zone_size (unsigned int size)
{
  unsigned int c = size & (ASAN_RED_ZONE_SIZE - 1);
  return c ? 2 * ASAN_RED_ZONE_SIZE - c : ASAN_RED_ZONE_SIZE;
}

/* Return how much a stack variable occupis on a stack
   including a space for red zone.  */

static inline unsigned HOST_WIDE_INT
asan_var_and_redzone_size (unsigned HOST_WIDE_INT size)
{
  if (size <= 4)
    return 16;
  else if (size <= 16)
    return 32;
  else if (size <= 128)
    return size + 32;
  else if (size <= 512)
    return size + 64;
  else if (size <= 4096)
    return size + 128;
  else
    return size + 256;
}

extern bool set_asan_shadow_offset (const char *);

extern void set_sanitized_sections (const char *);

extern bool asan_sanitize_stack_p (void);

extern bool asan_sanitize_allocas_p (void);

extern hash_set<tree> *asan_handled_variables;

/* Return TRUE if builtin with given FCODE will be intercepted by
   libasan.  */

static inline bool
asan_intercepted_p (enum built_in_function fcode)
{
  return fcode == BUILT_IN_INDEX
	 || fcode == BUILT_IN_MEMCHR
	 || fcode == BUILT_IN_MEMCMP
	 || fcode == BUILT_IN_MEMCPY
	 || fcode == BUILT_IN_MEMMOVE
	 || fcode == BUILT_IN_MEMSET
	 || fcode == BUILT_IN_STRCASECMP
	 || fcode == BUILT_IN_STRCAT
	 || fcode == BUILT_IN_STRCHR
	 || fcode == BUILT_IN_STRCMP
	 || fcode == BUILT_IN_STRCPY
	 || fcode == BUILT_IN_STRDUP
	 || fcode == BUILT_IN_STRLEN
	 || fcode == BUILT_IN_STRNCASECMP
	 || fcode == BUILT_IN_STRNCAT
	 || fcode == BUILT_IN_STRNCMP
	 || fcode == BUILT_IN_STRCSPN
	 || fcode == BUILT_IN_STRPBRK
	 || fcode == BUILT_IN_STRSPN
	 || fcode == BUILT_IN_STRSTR
	 || fcode == BUILT_IN_STRNCPY;
}

/* Return TRUE if we should instrument for use-after-scope sanity checking.  */

static inline bool
asan_sanitize_use_after_scope (void)
{
  return (flag_sanitize_address_use_after_scope && asan_sanitize_stack_p ());
}

/* Return true if DECL should be guarded on the stack.  */

static inline bool
asan_protect_stack_decl (tree decl)
{
  return DECL_P (decl)
    && (!DECL_ARTIFICIAL (decl)
	|| (asan_sanitize_use_after_scope () && TREE_ADDRESSABLE (decl)));
}

/* Return true when flag_sanitize & FLAG is non-zero.  If FN is non-null,
   remove all flags mentioned in "no_sanitize" of DECL_ATTRIBUTES.  */

static inline bool
sanitize_flags_p (unsigned int flag, const_tree fn = current_function_decl)
{
  unsigned int result_flags = flag_sanitize & flag;
  if (result_flags == 0)
    return false;

  if (fn != NULL_TREE)
    {
      tree value = lookup_attribute ("no_sanitize", DECL_ATTRIBUTES (fn));
      if (value)
	result_flags &= ~tree_to_uhwi (TREE_VALUE (value));
    }

  return result_flags;
}

#endif /* TREE_ASAN */