aboutsummaryrefslogtreecommitdiff
path: root/clang/test/CodeGen/cfi-salt.c
blob: 7ba1e2fc14daa3185693e70fc1e5d9d3597dd622 (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
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -fsanitize=kcfi -DORIG_ATTR_SYN -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -fsanitize=kcfi -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -fsanitize=kcfi -fpatchable-function-entry-offset=3 -DORIG_ATTR_SYN -o - %s | FileCheck %s --check-prefixes=CHECK,OFFSET
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -fsanitize=kcfi -fpatchable-function-entry-offset=3 -o - %s | FileCheck %s --check-prefixes=CHECK,OFFSET

// Note that the interleving of functions, which normally would be in sequence,
// is due to the fact that Clang outputs them in a non-sequential order.

#if !__has_feature(kcfi)
#error Missing kcfi?
#endif

#ifdef ORIG_ATTR_SYN
#define __cfi_salt       __attribute__((cfi_salt("pepper")))
#define __cfi_salt_empty __attribute__((cfi_salt("")))
#else
#define __cfi_salt       [[clang::cfi_salt("pepper")]]
#define __cfi_salt_empty [[clang::cfi_salt("")]]
#endif

typedef int (*fn_t)(void);
typedef int (* __cfi_salt fn_salt_t)(void);
typedef int (* __cfi_salt_empty fn_salt_empty_t)(void);

typedef unsigned int (*ufn_t)(void);
typedef unsigned int (* __cfi_salt ufn_salt_t)(void);

/// Must emit __kcfi_typeid symbols for address-taken function declarations
// CHECK: module asm ".weak __kcfi_typeid_[[F4:[a-zA-Z0-9_]+]]"
// CHECK: module asm ".set __kcfi_typeid_[[F4]], [[#%d,LOW_SODIUM_HASH:]]"
// CHECK: module asm ".weak __kcfi_typeid_[[F4_SALT:[a-zA-Z0-9_]+]]"
// CHECK: module asm ".set __kcfi_typeid_[[F4_SALT]], [[#%d,ASM_SALTY_HASH:]]"

/// Must not __kcfi_typeid symbols for non-address-taken declarations
// CHECK-NOT: module asm ".weak __kcfi_typeid_f6"

int f1(void);
int f1_salt(void) __cfi_salt;

unsigned int f2(void);
unsigned int f2_salt(void) __cfi_salt;

static int f3(void);
static int f3_salt(void) __cfi_salt;

extern int f4(void);
extern int f4_salt(void) __cfi_salt;

static int f5(void);
static int f5_salt(void) __cfi_salt;

extern int f6(void);
extern int f6_salt(void) __cfi_salt;

int f8(void);
int f8_salt_empty(void) __cfi_salt_empty;

struct cfi_struct {
  fn_t __cfi_salt fptr;
  fn_salt_t td_fptr;
  fn_salt_empty_t td_empty_fptr;
};

int f7_salt(struct cfi_struct *ptr);
int f7_typedef_salt(struct cfi_struct *ptr);

// CHECK-LABEL: @__call
// CHECK:         call{{.*}} i32
// CHECK-NOT:     "kcfi"
// CHECK-SAME:    ()
__attribute__((__no_sanitize__("kcfi")))
int __call(fn_t f) {
  return f();
}

// CHECK-LABEL: @call
// CHECK:         call{{.*}} i32 %{{.}}(){{.*}} [ "kcfi"(i32 [[#LOW_SODIUM_HASH]]) ]
// CHECK-LABEL: @call_salt
// CHECK:         call{{.*}} i32 %{{.}}(){{.*}} [ "kcfi"(i32 [[#%d,SALTY_HASH:]]) ]
// CHECK-LABEL: @call_salt_ty
// CHECK:         call{{.*}} i32 %{{.}}(){{.*}} [ "kcfi"(i32 [[#SALTY_HASH]]) ]
int call(fn_t f) { return f(); }
int call_salt(fn_t __cfi_salt f) { return f(); }
int call_salt_ty(fn_salt_t f) { return f(); }
int call_salt_empty_ty(fn_salt_empty_t f) { return f(); }

// CHECK-LABEL: @ucall
// CHECK:         call{{.*}} i32 %{{.}}(){{.*}} [ "kcfi"(i32 [[#%d,LOW_SODIUM_UHASH:]]) ]
// CHECK-LABEL: @ucall_salt
// CHECK:         call{{.*}} i32 %{{.}}(){{.*}} [ "kcfi"(i32 [[#%d,SALTY_UHASH:]]) ]
// CHECK-LABEL: @ucall_salt_ty
// CHECK:         call{{.*}} i32 %{{.}}(){{.*}} [ "kcfi"(i32 [[#SALTY_UHASH]]) ]
unsigned int ucall(ufn_t f) { return f(); }
unsigned int ucall_salt(ufn_t __cfi_salt f) { return f(); }
unsigned int ucall_salt_ty(ufn_salt_t f) { return f(); }

int test1(struct cfi_struct *ptr) {
  return call(f1) +
         call_salt(f1_salt) +
         call_salt_ty(f1_salt) +

         __call((fn_t)f2) +
         __call((fn_t)f2_salt) +

         ucall(f2) +
         ucall_salt(f2_salt) +
         ucall_salt_ty(f2_salt) +

         call(f3) +
         call_salt(f3_salt) +
         call_salt_ty(f3_salt) +

         call(f4) +
         call_salt(f4_salt) +
         call_salt_ty(f4_salt) +

         f5() +
         f5_salt() +

         f6() +
         f6_salt() +

         f7_salt(ptr) +
         f7_typedef_salt(ptr) +

         f8() +
         f8_salt_empty();
}

// CHECK-LABEL: define dso_local{{.*}} i32 @f1(){{.*}} !kcfi_type
// CHECK-SAME:  ![[#LOW_SODIUM_TYPE:]]
// CHECK-LABEL: define dso_local{{.*}} i32 @f1_salt(){{.*}} !kcfi_type
// CHECK-SAME:  ![[#SALTY_TYPE:]]
int f1(void) { return 0; }
int f1_salt(void) __cfi_salt { return 0; }

// CHECK-LABEL: define dso_local{{.*}} i32 @f2(){{.*}} !kcfi_type
// CHECK-SAME:  ![[#LOW_SODIUM_UTYPE:]]
// CHECK: define dso_local{{.*}} i32 @f2_salt(){{.*}} !kcfi_type
// CHECK-SAME:  ![[#SALTY_UTYPE:]]
unsigned int f2(void) { return 2; }
unsigned int f2_salt(void) __cfi_salt { return 2; }

// CHECK-LABEL: define internal{{.*}} i32 @f3(){{.*}} !kcfi_type
// CHECK-SAME:  ![[#LOW_SODIUM_TYPE]]
// CHECK-LABEL: define internal{{.*}} i32 @f3_salt(){{.*}} !kcfi_type
// CHECK-SAME:  ![[#SALTY_TYPE]]
static int f3(void) { return 1; }
static int f3_salt(void) __cfi_salt { return 1; }

// CHECK: declare !kcfi_type ![[#LOW_SODIUM_TYPE]]{{.*}} i32 @[[F4]]()
// CHECK: declare !kcfi_type ![[#SALTY_TYPE]]{{.*}} i32 @[[F4_SALT]]()

/// Must not emit !kcfi_type for non-address-taken local functions
// CHECK-LABEL: define internal{{.*}} i32 @f5()
// CHECK-NOT:   !kcfi_type
// CHECK-SAME:  {
// CHECK-LABEL: define internal{{.*}} i32 @f5_salt()
// CHECK-NOT:   !kcfi_type
// CHECK-SAME:  {
static int f5(void) { return 2; }
static int f5_salt(void) __cfi_salt { return 2; }

// CHECK: declare !kcfi_type ![[#LOW_SODIUM_TYPE]]{{.*}} i32 @f6()
// CHECK: declare !kcfi_type ![[#SALTY_TYPE]]{{.*}} i32 @f6_salt()

// CHECK-LABEL: @f7_salt
// CHECK:         call{{.*}} i32 %{{.*}}() [ "kcfi"(i32 [[#SALTY_HASH]]) ]
// CHECK-LABEL: @f7_typedef_salt
// CHECK:         call{{.*}} i32 %{{.*}}() [ "kcfi"(i32 [[#SALTY_HASH]]) ]
int f7_salt(struct cfi_struct *ptr) { return ptr->fptr(); }
int f7_typedef_salt(struct cfi_struct *ptr) { return ptr->td_fptr(); }

// CHECK-LABEL: define dso_local{{.*}} i32 @f8(){{.*}} !kcfi_type
// CHECK-SAME:  ![[#LOW_SODIUM_TYPE:]]
// CHECK-LABEL: define dso_local{{.*}} i32 @f8_salt_empty(){{.*}} !kcfi_type
// CHECK-SAME:  ![[#LOW_SODIUM_TYPE:]]
int f8(void) { return 0; }
int f8_salt_empty(void) __cfi_salt_empty { return 0; }

// CHECK:  ![[#]] = !{i32 4, !"kcfi", i32 1}
// OFFSET: ![[#]] = !{i32 4, !"kcfi-offset", i32 3}
//
// CHECK:  ![[#LOW_SODIUM_TYPE]] = !{i32 [[#LOW_SODIUM_HASH]]}
// CHECK:  ![[#SALTY_TYPE]] = !{i32 [[#SALTY_HASH]]}
//
// CHECK:  ![[#LOW_SODIUM_UTYPE]] = !{i32 [[#LOW_SODIUM_UHASH]]}
// CHECK:  ![[#SALTY_UTYPE]] = !{i32 [[#SALTY_UHASH]]}