| // 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]]} |