-
Notifications
You must be signed in to change notification settings - Fork 14.8k
[Clang][attr] Add 'cfi_salt' attribute #141846
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 26 commits
bfdf16c
04d2c0b
94d10c5
bbce666
e36bc7c
b0c8a2e
9e164e5
eef5f43
46d0edd
f4a54d9
e9aaaf5
0b13d3a
cec156a
44950cc
514523b
f74c5ea
527297f
2df94a9
66cb83b
516aa05
1b1d3ab
6d00a7e
2e9022d
7f2de1c
44c179d
029ee8e
06e43bd
132995f
cd975ea
abe3bde
c2dba02
95698c2
09a446a
ae91164
9bd2c95
9700cac
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3643,6 +3643,95 @@ make the function's CFI jump table canonical. See :ref:`the CFI documentation | |
}]; | ||
} | ||
|
||
def CFISaltDocs : Documentation { | ||
let Category = DocCatFunction; | ||
let Heading = "cfi_salt"; | ||
let Label = "langext-cfi_salt"; | ||
let Content = [{ | ||
The ``cfi_salt`` attribute allows you to add a salt value to Control Flow | ||
Integrity (CFI) type hashes to help distinguish between functions with the | ||
same type signature. This attribute can be applied to function declarations, | ||
function definitions, and function pointer typedefs. | ||
|
||
**Syntax:** | ||
|
||
* GNU-style: ``__attribute__((cfi_salt("<salt_string>")))`` | ||
* C++11-style: ``[[clang::cfi_salt("<salt_string>")]]`` | ||
|
||
**Usage:** | ||
|
||
The attribute takes a single string literal argument that serves as the salt. | ||
Functions or function types with different salt values will have different CFI | ||
hashes, even if they have identical type signatures. | ||
|
||
**Motivation:** | ||
|
||
In large codebases like the Linux kernel, there are often hundreds of functions | ||
with identical type signatures that are called indirectly: | ||
|
||
.. code-block:: | ||
|
||
1662 functions with void (*)(void) | ||
1179 functions with int (*)(void) | ||
... | ||
|
||
By salting the CFI hashes, you can make CFI more robust by ensuring that | ||
functions intended for different purposes have distinct CFI identities. | ||
|
||
**Type Compatibility:** | ||
|
||
* Functions with different salt values are considered to have incompatible types | ||
* Function pointers with different salt values cannot be assigned to each other | ||
* All declarations of the same function must use the same salt value | ||
|
||
**Example:** | ||
|
||
.. code-block:: c | ||
|
||
// Header file - define convenience macros | ||
#define __cfi_salt(s) __attribute__((cfi_salt(s))) | ||
|
||
// Typedef for regular function pointers | ||
typedef int (*fptr_t)(void); | ||
|
||
// Typedef for salted function pointers | ||
typedef int (*fptr_salted_t)(void) __cfi_salt("pepper"); | ||
|
||
struct widget_ops { | ||
fptr_t init; // Regular CFI | ||
fptr_salted_t exec; // Salted CFI | ||
fptr_t cleanup; // Regular CFI | ||
}; | ||
|
||
// Function implementations | ||
static int widget_init(void) { return 0; } | ||
static int widget_exec(void) __cfi_salt("pepper") { return 1; } | ||
static int widget_cleanup(void) { return 0; } | ||
|
||
static struct widget_ops ops = { | ||
.init = widget_init, // OK - compatible types | ||
.exec = widget_exec, // OK - both use "pepper" salt | ||
.cleanup = widget_cleanup // OK - compatible types | ||
}; | ||
|
||
// Using C++11 attribute syntax | ||
void secure_callback(void) [[clang::cfi_salt("secure")]]; | ||
|
||
// This would cause a compilation error: | ||
// fptr_t bad_ptr = widget_exec; // Error: incompatible types | ||
|
||
**Notes:** | ||
|
||
* The salt string can contain any characters, including spaces and quotes | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Embedded nulls? (If so, we should have a test case for that situation.) Also, do we need to say anything about the text encoding? (Any other weird things we need to be aware of @cor3ntin?) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unicode, wide-characters, an excessive amount of characters (think "War and Peace"), etc. I'm thinking of backing off of this claim and simply say non-null ASCII characters, unless we need can support those easily (we're using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think non-null ASCII characters would be good; we can basically claim it is a bucket of non-zero bytes more than a textual string, really. Or, maybe the salt should be a 64-bit numeric value? e.g., |
||
* This attribute only applies to function types; using it on non-function | ||
types will generate a warning | ||
* All declarations and definitions of the same function must use identical | ||
salt values | ||
* The attribute affects type compatibility during compilation and CFI hash | ||
generation during code generation | ||
}]; | ||
} | ||
|
||
def DocCatTypeSafety : DocumentationCategory<"Type Safety Checking"> { | ||
let Content = [{ | ||
Clang supports additional attributes to enable checking type safety properties | ||
|
Uh oh!
There was an error while loading. Please reload this page.