[X86] Enhance kCFI type IDs with a 3-bit arity indicator. by scottconstable · Pull Request #117121 · llvm/llvm-project (original) (raw)

Conversation

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters

[ Show hidden characters]({{ revealButtonHref }})

scottconstable

@llvmbot llvmbot added clang

Clang issues not falling into any other category

clang:codegen

IR generation bugs: mangling, exceptions, etc.

labels

Nov 21, 2024

sirmc

scottconstable

scottconstable

@scottconstable

@scottconstable

phoebewang pushed a commit that referenced this pull request

Feb 6, 2025

@scottconstable

Kernel Control Flow Integrity (kCFI) is a feature that hardens indirect calls by comparing a 32-bit hash of the function pointer's type against a hash of the target function's type. If the hashes do not match, the kernel may panic (or log the hash check failure, depending on the kernel's configuration). These hashes are computed at compile time by applying the xxHash64 algorithm to each mangled canonical function (or function pointer) type, then truncating the result to 32 bits. This hash is written into each indirect-callable function header by encoding it as the 32-bit immediate operand to a MOVri instruction, e.g.:

__cfi_foo:
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    movl	$199571451, %eax                # hash of foo's type = 0xBE537FB
foo:
        ...

This PR extends x86-based kCFI with a 3-bit arity indicator encoded in the MOVri instruction's register (reg) field as follows:

Arity Indicator Description Encoding in reg field
0 0 parameters EAX
1 1 parameter in RDI ECX
2 2 parameters in RDI and RSI EDX
3 3 parameters in RDI, RSI, and RDX EBX
4 4 parameters in RDI, RSI, RDX, and RCX ESP
5 5 parameters in RDI, RSI, RDX, RCX, and R8 EBP
6 6 parameters in RDI, RSI, RDX, RCX, R8, and R9 ESI
7 At least one parameter may be passed on the stack EDI

For example, if foo takes 3 register arguments and no stack arguments then the MOVri instruction in its kCFI header would instead be written as:

    movl	$199571451, %ebx                # hash of foo's type = 0xBE537FB

This PR will benefit other CFI approaches that build on kCFI, such as FineIBT. For example, this proposed enhancement to FineIBT must be able to infer (at kernel init time) which registers are live at an indirect call target: https://lkml.org/lkml/2024/9/27/982. If the arity bits are available in the kCFI function header, then this information is trivial to infer.

Note that there is another existing PR proposal that includes the 3-bit arity within the existing 32-bit immediate field, which introduces different security properties: #117121.

github-actions bot pushed a commit to arm/arm-toolchain that referenced this pull request

Feb 6, 2025

@scottconstable @github-actions

Kernel Control Flow Integrity (kCFI) is a feature that hardens indirect calls by comparing a 32-bit hash of the function pointer's type against a hash of the target function's type. If the hashes do not match, the kernel may panic (or log the hash check failure, depending on the kernel's configuration). These hashes are computed at compile time by applying the xxHash64 algorithm to each mangled canonical function (or function pointer) type, then truncating the result to 32 bits. This hash is written into each indirect-callable function header by encoding it as the 32-bit immediate operand to a MOVri instruction, e.g.:

__cfi_foo:
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    movl	$199571451, %eax                # hash of foo's type = 0xBE537FB
foo:
        ...

This PR extends x86-based kCFI with a 3-bit arity indicator encoded in the MOVri instruction's register (reg) field as follows:

Arity Indicator Description Encoding in reg field
0 0 parameters EAX
1 1 parameter in RDI ECX
2 2 parameters in RDI and RSI EDX
3 3 parameters in RDI, RSI, and RDX EBX
4 4 parameters in RDI, RSI, RDX, and RCX ESP
5 5 parameters in RDI, RSI, RDX, RCX, and R8 EBP
6 6 parameters in RDI, RSI, RDX, RCX, R8, and R9 ESI
7 At least one parameter may be passed on the stack EDI

For example, if foo takes 3 register arguments and no stack arguments then the MOVri instruction in its kCFI header would instead be written as:

    movl	$199571451, %ebx                # hash of foo's type = 0xBE537FB

This PR will benefit other CFI approaches that build on kCFI, such as FineIBT. For example, this proposed enhancement to FineIBT must be able to infer (at kernel init time) which registers are live at an indirect call target: https://lkml.org/lkml/2024/9/27/982. If the arity bits are available in the kCFI function header, then this information is trivial to infer.

Note that there is another existing PR proposal that includes the 3-bit arity within the existing 32-bit immediate field, which introduces different security properties: llvm/llvm-project#117121.

Icohedron pushed a commit to Icohedron/llvm-project that referenced this pull request

Feb 11, 2025

@scottconstable @Icohedron

Kernel Control Flow Integrity (kCFI) is a feature that hardens indirect calls by comparing a 32-bit hash of the function pointer's type against a hash of the target function's type. If the hashes do not match, the kernel may panic (or log the hash check failure, depending on the kernel's configuration). These hashes are computed at compile time by applying the xxHash64 algorithm to each mangled canonical function (or function pointer) type, then truncating the result to 32 bits. This hash is written into each indirect-callable function header by encoding it as the 32-bit immediate operand to a MOVri instruction, e.g.:

__cfi_foo:
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    movl	$199571451, %eax                # hash of foo's type = 0xBE537FB
foo:
        ...

This PR extends x86-based kCFI with a 3-bit arity indicator encoded in the MOVri instruction's register (reg) field as follows:

Arity Indicator Description Encoding in reg field
0 0 parameters EAX
1 1 parameter in RDI ECX
2 2 parameters in RDI and RSI EDX
3 3 parameters in RDI, RSI, and RDX EBX
4 4 parameters in RDI, RSI, RDX, and RCX ESP
5 5 parameters in RDI, RSI, RDX, RCX, and R8 EBP
6 6 parameters in RDI, RSI, RDX, RCX, R8, and R9 ESI
7 At least one parameter may be passed on the stack EDI

For example, if foo takes 3 register arguments and no stack arguments then the MOVri instruction in its kCFI header would instead be written as:

    movl	$199571451, %ebx                # hash of foo's type = 0xBE537FB

This PR will benefit other CFI approaches that build on kCFI, such as FineIBT. For example, this proposed enhancement to FineIBT must be able to infer (at kernel init time) which registers are live at an indirect call target: https://lkml.org/lkml/2024/9/27/982. If the arity bits are available in the kCFI function header, then this information is trivial to infer.

Note that there is another existing PR proposal that includes the 3-bit arity within the existing 32-bit immediate field, which introduces different security properties: llvm#117121.

rcvalle added a commit to rcvalle/rust that referenced this pull request

Mar 11, 2025

@rcvalle

rcvalle added a commit to rcvalle/rust that referenced this pull request

Mar 11, 2025

@rcvalle

rcvalle added a commit to rcvalle/rust that referenced this pull request

Mar 11, 2025

@rcvalle