llvm / llvm/llvm-project

[BOLT][Gadget scanner] CFG is constructed when it should not in relocation mode

Open
#178,232 1 comment 0 reactions 0 assignees View on GitHub
BOLT
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

Various tests under `bolt/test/binary-analysis/AArch64/` use the same pattern to inhibit CFG reconstruction in `*_nocfg` test cases:

```asm
adr xN, 1f
br xN
1:
; ... actual test case ...
```

Adding a recommended `-Wl,--emit-relocs` option to the `RUN: %clang ...` line breaks the tests, as CFG is now formally reconstructed for these functions (but `br xN` is still annotated with an `# UNKNOWN CONTROL FLOW` comment, that is why I say "formally").

For a function to be affected, it does not necessarily have to contain relocation, but relocations have to be emitted for any function in the binary.

## How to reproduce

Compile the following source:

```asm
.text

.globl func
.type func,@function
func:
adr x1, 1f
br x1
1:
ret x0
.size func, .-func

.globl other_func
.type other_func,@function
other_func:
adr x0, sym
ret
.size other_func, .-other_func
```

without `-Wl,--emit-relocs`:

```
clang -target aarch64-linux-gnu -march=armv8.3-a -fuse-ld=lld \
-Wl,--unresolved-symbols=ignore-all -nostdlib \
nocfg-test.s -o nocfg-test
```

As expected, a report for non-protected `ret x0` is generated. Note that it does not mention `..., basic block , ...` in the first line of the report:

```
$ ./bin/llvm-bolt-binary-analysis --scanners=pauth ./nocfg-test
BOLT-INFO: shared object or position-independent executable detected
BOLT-INFO: Target architecture: aarch64
BOLT-INFO: BOLT version: 3de4d32a7228519312a844bcd48a34124b1a718b
BOLT-INFO: first alloc address is 0x0
BOLT-INFO: creating new program header table at address 0x200000, offset 0x200000
BOLT-WARNING: non-relocation mode for AArch64 is not fully supported

GS-PAUTH: non-protected ret found in function func, at address 102b8
The instruction is 000102b8: ret x0 # Offset: 8
The 0 instructions that write to the affected registers after any authentication are:
```

Disassembled function dumped with `-no-threads -debug-only=bolt-pauth-scanner`

`func` has `State: disassembled`, `IsSimple: 0` and `BB Count: 0`.

```
Binary Function "func" {
Number : 1
State : disassembled
Address : 0x102b0
Size : 0xc
MaxSize : 0xc
Offset : 0x2b0
Section : .text
Orc Section : .local.text.func
LSDA : 0x0
IsSimple : 0
IsMultiEntry: 1
IsSplit : 0
BB Count : 0
Secondary Entry Points : __ENTRY_func@0x102b8
}
.LBB00:
00000000: adr x1, __ENTRY_func@0x102b8
00000004: br x1 # UNKNOWN CONTROL FLOW # Offset: 4
__ENTRY_func@0x102b8 (Entry Point):
.Ltmp0:
00000008: ret x0 # Offset: 8
DWARF CFI Instructions:

End of Function "func"

# ...

Binary Function "other_func" {
Number : 2
State : CFG constructed
Address : 0x102bc
Size : 0x8
MaxSize : 0x8
Offset : 0x2bc
Section : .text
Orc Section : .local.text.other_func
LSDA : 0x0
IsSimple : 1
IsMultiEntry: 0
IsSplit : 0
BB Count : 1
Hash : 3cab5d975d7c2f39
BB Layout : .LBB01
}
.LBB01 (2 instructions, align : 1)
Entry Point
00000000: adr x0, other_func
00000004: ret

DWARF CFI Instructions:

End of Function "other_func"
```

Then, recompile `nocfg-test` binary with `-Wl,--emit-relocs` option. The output of gadget scanner is now

```
$ ./bin/llvm-bolt-binary-analysis --scanners=pauth ./nocfg-test
BOLT-INFO: shared object or position-independent executable detected
BOLT-INFO: Target architecture: aarch64
BOLT-INFO: BOLT version: 3de4d32a7228519312a844bcd48a34124b1a718b
BOLT-INFO: first alloc address is 0x0
BOLT-INFO: creating new program header table at address 0x200000, offset 0x200000
BOLT-INFO: enabling relocation mode

GS-PAUTH: non-protected ret found in function func, basic block .Ltmp0, at address 102b8
The instruction is 000102b8: ret x0
The 0 instructions that write to the affected registers after any authentication are:
```

CFG information is formally available now, which can be seen by the basic block name being mentioned in the report.

Disassembled function dumped with `-no-threads -debug-only=bolt-pauth-scanner`

`func` has `State: CFG constructed`, `IsSimple: 0` and `BB Count: 2`.

```
Binary Function "func" {
Number : 1
State : CFG constructed
Address : 0x102b0
Size : 0xc
MaxSize : 0xc
Offset : 0x2b0
Section : .text
Orc Section : .local.text.func
LSDA : 0x0
IsSimple : 0
IsMultiEntry: 1
IsSplit : 0
BB Count : 2
Hash : 592111a3fb9ca883
Secondary Entry Points : __ENTRY_func@0x102b8
BB Layout : .LBB00, .Ltmp0
}
.LBB00 (2 instructions, align : 1)
Entry Point
00000000: adr x1, __ENTRY_func@0x102b8
00000004: br x1 # UNKNOWN CONTROL FLOW

.Ltmp0 (1 instructions, align : 1)
Secondary Entry Point: __ENTRY_func@0x102b8
00000008: ret x0

DWARF CFI Instructions:

End of Function "func"

# ...

Binary Function "other_func" {
Number : 2
State : CFG constructed
Address : 0x102bc
Size : 0x8
MaxSize : 0x8
Offset : 0x2bc
Section : .text
Orc Section : .local.text.other_func
LSDA : 0x0
IsSimple : 1
IsMultiEntry: 0
IsSplit : 0
BB Count : 1
Hash : 3cab5d975d7c2f39
BB Layout : .LBB01
}
.LBB01 (2 instructions, align : 1)
Entry Point
00000000: adr x0, other_func
00000004: ret

DWARF CFI Instructions:

End of Function "other_func"
```

Removing `other_func` eliminates the only emitted relocation from `nocfg-test` binary, resulting in restoring the original behavior of treating `func` as not having a valid CFG (whether `-Wl,--emit-relocs` is passed or not).

Disassembled function dumped with `-no-threads -debug-only=bolt-pauth-scanner`

```
Binary Function "func" {
Number : 1
State : disassembled
Address : 0x102b0
Size : 0xc
MaxSize : 0xc
Offset : 0x2b0
Section : .text
Orc Section : .local.text.func
LSDA : 0x0
IsSimple : 0
IsMultiEntry: 1
IsSplit : 0
BB Count : 0
Secondary Entry Points : __ENTRY_func@0x102b8
}
.LBB00:
00000000: adr x1, __ENTRY_func@0x102b8
00000004: br x1 # UNKNOWN CONTROL FLOW # Offset: 4
__ENTRY_func@0x102b8 (Entry Point):
.Ltmp0:
00000008: ret x0 # Offset: 8
DWARF CFI Instructions:

End of Function "func"
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.