Update exploit mitigations documentation · rust-lang/rust@7c385f5 (original) (raw)

`@@ -43,7 +43,8 @@ understood within a given context.

`

43

43

`This section documents the exploit mitigations applicable to the Rust compiler

`

44

44

`when building programs for the Linux operating system on the AMD64 architecture

`

45

45

`and equivalent.<a href="#fn:1"

`

46

``

`-

class="footnote">1

`

``

46

`+

class="footnote">1 All examples in this section were built using

`

``

47

`+

nightly builds of the Rust compiler on Debian testing.

`

47

48

``

48

49

`The Rust Programming Language currently has no specification. The Rust compiler

`

49

50

`(i.e., rustc) is the language reference implementation. All references to “the

`

`@@ -102,7 +103,10 @@ and unsigned integer computations that cannot be represented in their type,

`

102

103

`resulting in an overflow or wraparound.

`

103

104

``

104

105

`The Rust compiler supports integer overflow checks, and enables it when debug

`

105

``

`-

assertions are enabled since version 1.1.0 (2015-06-25)[14]–[20].

`

``

106

`+

assertions are enabled since version 1.0.0 (2015-05-15)[14]–[17], but support

`

``

107

`+

for it was not completed until version 1.1.0 (2015-06-25)[16]. An option to

`

``

108

`+

control integer overflow checks was later stabilized in version 1.17.0

`

``

109

`+

(2017-04-27)[18]–[20].

`

106

110

``

107

111

```` ```compile_fail


`108`

`112`

`fn main() {

`

`@@ -120,7 +124,7 @@ $ cargo run

`

`120`

`124`

`thread 'main' panicked at 'attempt to add with overflow', src/main.rs:3:23

`

`121`

`125`

`` note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.

``

`122`

`126`

```` ```

123

``

`-

Fig. 3. Build and execution of hello-rust-integer with debug assertions

`

``

127

`+

Fig. 3. Build and execution of hello-rust-integer with debug assertions

`

124

128

`enabled.

`

125

129

``

126

130

```` ```text


`@@ -130,7 +134,7 @@ $ cargo run --release

`

`130`

`134`

``  Running `target/release/hello-rust-integer`

``

`131`

`135`

`u: 0

`

`132`

`136`

```` ```

133

``

`-

Fig. 4. Build and execution of hello-rust-integer with debug assertions

`

``

137

`+

Fig. 4. Build and execution of hello-rust-integer with debug assertions

`

134

138

`disabled.

`

135

139

``

136

140

`Integer overflow checks are enabled when debug assertions are enabled (see Fig.

`

`@@ -156,7 +160,7 @@ Non-executable memory regions increase the difficulty of exploitation by

`

156

160

`limiting the memory regions that can be used to execute arbitrary code. Most

`

157

161

`modern processors provide support for the operating system to mark memory

`

158

162

`regions as non executable, but it was previously emulated by software, such as

`

159

``

`-

in grsecurity/PaX's PAGEEXEC

`

``

163

`+

in grsecurity/PaX’s PAGEEXEC

`

160

164

`and SEGMEXEC, on processors

`

161

165

`that did not provide support for it. This is also known as “No Execute (NX)

`

162

166

`Bit”, “Execute Disable (XD) Bit”, “Execute Never (XN) Bit”, and others.

`

`@@ -171,7 +175,7 @@ $ readelf -l target/release/hello-rust | grep -A 1 GNU_STACK

`

171

175

` GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000

`

172

176

` 0x0000000000000000 0x0000000000000000 RW 0x10

`

173

177

```` ```


`174`

``

`-

Fig. 5. Checking if non-executable memory regions are enabled for a given

`

``

`178`

`+

Fig. 5. Checking if non-executable memory regions are enabled for a given

`

`175`

`179`

`binary.

`

`176`

`180`

``

`177`

`181`

`` The presence of an element of type `PT_GNU_STACK` in the program header table

``

`@@ -199,30 +203,33 @@ when attempting to read from the guard page/region. This is also referred to as

`

`199`

`203`

`The Rust compiler supports stack clashing protection via stack probing, and

`

`200`

`204`

`enables it by default since version 1.20.0 (2017-08-31)[26]–[29].

`

`201`

`205`

``

`202`

``

`-

![Screenshot of IDA Pro listing cross references to __rust_probestack in hello-rust.](images/image1.png "Cross references to __rust_probestack in hello-rust.")

`

`203`

``

`` -

Fig. 6. IDA Pro listing cross references to `__rust_probestack` in hello-rust.

``

`204`

``

`-`

`205`

`206`

```` ```rust

206

``

`-

fn hello() {

`

207

``

`-

println!("Hello, world!");

`

``

207

`+

fn main() {

`

``

208

`+

let v: [u8; 16384] = [1; 16384];

`

``

209

`+

let first = &v[0];

`

``

210

`+

println!("The first element is: {first}");

`

208

211

`}

`

``

212


```

``

213

`+

Fig. 6. hello-rust-stack-probe-1 program.

`

209

214

``

``

215

`+

Screenshot of IDA Pro listing the "unrolled loop" stack probe variant in modified hello-rust.

`

``

216

`+

Fig. 7. The "unrolled loop" stack probe variant in modified hello-rust.

`

``

217

+

``

218


```rust

210

219

`fn main() {

`

211

``

`-

let _: [u64; 1024] = [0; 1024];

`

212

``

`-

hello();

`

``

220

`+

let v: [u8; 65536] = [1; 65536];

`

``

221

`+

let first = &v[0];

`

``

222

`+

println!("The first element is: {first}");

`

213

223

`}

`

214

224

```` ```


`215`

``

`-

Fig 7. Modified hello-rust.

`

``

`225`

`+

Fig. 8. hello-rust-stack-probe-2 program.

`

`216`

`226`

``

`217`

``

`-

![Screenshot of IDA Pro listing cross references to __rust_probestack in modified hello-rust.](images/image2.png "Cross references to __rust_probestack in modified hello-rust.")

`

`218`

``

`` -

Fig. 8. IDA Pro listing cross references to `__rust_probestack` in modified

``

`219`

``

`-

hello-rust.

`

``

`227`

`+

![Screenshot of IDA Pro listing the "standard loop" stack probe variant in modified hello-rust.](images/image2.png "The \"standard loop\" stack probe variant in modified hello-rust.")

`

``

`228`

`+

Fig. 9. The "standard loop" stack probe variant in modified hello-rust.

`

`220`

`229`

``

`221`

``

`-

To check if stack clashing protection is enabled for a given binary, search for

`

`222`

``

`` -

cross references to `__rust_probestack`. The `__rust_probestack` is called in

``

`223`

``

`-

the prologue of functions whose stack size is larger than a page size (see Fig.

`

`224`

``

`-

6), and can be forced for illustration purposes by modifying the hello-rust

`

`225`

``

`-

example as seen in Fig. 7 and Fig. 8.

`

``

`230`

`+

To check if stack clashing protection is enabled for a given binary, look for

`

``

`231`

`+

any of the two stack probe variants in the prologue of functions whose stack

`

``

`232`

`+

size is larger than a page size (see Figs. 6–9).

`

`226`

`233`

``

`227`

`234`

``

`228`

`235`

`### Read-only relocations and immediate binding

`

`@@ -272,7 +279,7 @@ section indicates immediate binding is not enabled for a given binary.

`

`272`

`279`

`` The presence of both an element of type `PT_GNU_RELRO` in the program header

``

`273`

`280`

`` table and of an element with the `DT_BIND_NOW` tag and the `DF_BIND_NOW` flag

``

`274`

`281`

`in the dynamic section indicates full RELRO is enabled for a given binary (see

`

`275`

``

`-

Fig. 9 and Fig. 10).

`

``

`282`

`+

Figs. 9–10).

`

`276`

`283`

``

`277`

`284`

`` <small id="fn:4">4\. And the `DF_1_NOW` flag for some link editors. <a

``

`278`

`285`

`href="#fnref:4" class="reversefootnote" role="doc-backlink">↩</a></small>

`

`@@ -321,7 +328,7 @@ $ cargo run

`

`321`

`328`

`free(): invalid next size (normal)

`

`322`

`329`

`Aborted

`

`323`

`330`

```` ```

324

``

`-

Fig. 12. Build and execution of hello-rust-heap with debug assertions enabled.

`

``

331

`+

Fig. 12. Build and execution of hello-rust-heap with debug assertions enabled.

`

325

332

``

326

333

```` ```text


`327`

`334`

`$ cargo run --release

`

`@@ -331,10 +338,10 @@ $ cargo run --release

`

`331`

`338`

`free(): invalid next size (normal)

`

`332`

`339`

`Aborted

`

`333`

`340`

```` ```

334

``

`-

Fig. 13. Build and execution of hello-rust-heap with debug assertions disabled.

`

``

341

`+

Fig. 13. Build and execution of hello-rust-heap with debug assertions disabled.

`

335

342

``

336

``

`-

Heap corruption checks are being performed when using the default allocator

`

337

``

`-

(i.e., the GNU Allocator) as seen in Fig. 12 and Fig. 13.

`

``

343

`+

Heap corruption checks are performed when using the default allocator (i.e.,

`

``

344

`+

the GNU Allocator) (see Figs. 12–13).

`

338

345

``

339

346

`5. Linux's standard C library default allocator is the GNU

`

340

347

`Allocator, which is derived from ptmalloc (pthreads malloc) by Wolfram Gloger,

`

`@@ -350,15 +357,13 @@ instruction pointer, and checking if this value has changed when returning from

`

350

357

`a function. This is also known as “Stack Protector” or “Stack Smashing

`

351

358

`Protector (SSP)”.

`

352

359

``

353

``

`-

The Rust compiler supports stack smashing protection on nightly builds[42].

`

``

360

`+

The Rust compiler supports stack smashing protection on nightly builds[40].

`

354

361

``

355

362

`Screenshot of IDA Pro listing cross references to __stack_chk_fail in hello-rust.

`

356

363

`` Fig. 14. IDA Pro listing cross references to __stack_chk_fail in hello-rust.

``

357

364

``

358

365

`To check if stack smashing protection is enabled for a given binary, search for

`

359

``

`` -

cross references to __stack_chk_fail. The presence of these cross-references

``

360

``

`` -

in Rust-compiled code (e.g., hello_rust::main) indicates that the stack

``

361

``

`-

smashing protection is enabled (see Fig. 14).

`

``

366

`` +

cross references to __stack_chk_fail (see Fig. 14).

``

362

367

``

363

368

``

364

369

`### Forward-edge control flow protection

`

`@@ -380,17 +385,14 @@ commercially available [grsecurity/PaX Reuse Attack Protector

`

380

385

`(RAP)](https://grsecurity.net/rap_faq).

`

381

386

``

382

387

`The Rust compiler supports forward-edge control flow protection on nightly

`

383

``

`-

builds[40]-[41] <a href="#fn:6"

`

``

388

`+

builds[41]-[42] <a href="#fn:6"

`

384

389

`class="footnote">6.

`

385

390

``

386

391

```` ```text


`387`

``

`-

$ readelf -s -W target/debug/rust-cfi | grep "\.cfi"

`

`388`

``

`-

12: 0000000000005170 46 FUNC LOCAL DEFAULT 14 _RNvCsjaOHoaNjor6_8rust_cfi7add_one.cfi

`

`389`

``

`-

15: 00000000000051a0 16 FUNC LOCAL DEFAULT 14 _RNvCsjaOHoaNjor6_8rust_cfi7add_two.cfi

`

`390`

``

`-

17: 0000000000005270 396 FUNC LOCAL DEFAULT 14 _RNvCsjaOHoaNjor6_8rust_cfi4main.cfi

`

`391`

``

`-

...

`

``

`392`

`+

$ readelf -s -W target/release/hello-rust | grep "\.cfi"

`

``

`393`

`+

5: 0000000000006480 657 FUNC LOCAL DEFAULT 15 _ZN10hello_rust4main17h4e359f1dcd627c83E.cfi

`

`392`

`394`

```` ```

393

``

`-

Fig. 15. Checking if LLVM CFI is enabled for a given binary[41].

`

``

395

`+

Fig. 15. Checking if LLVM CFI is enabled for a given binary.

`

394

396

``

395

397

`` The presence of symbols suffixed with ".cfi" or the __cfi_init symbol (and

``

396

398

`` references to __cfi_check) indicates that LLVM CFI (i.e., forward-edge

``

`@@ -429,21 +431,21 @@ Newer processors provide hardware assistance for backward-edge control flow

`

429

431

`protection, such as ARM Pointer Authentication, and Intel Shadow Stack as part

`

430

432

`of Intel CET.

`

431

433

``

432

``

`-

The Rust compiler supports shadow stack for aarch64 only <sup id="fnref:7"

`

433

``

`-

role="doc-noteref">7 on nightly Rust

`

434

``

`-

compilers [43]-[44]. Safe stack is available on nightly Rust compilers

`

435

``

`-

[45]-[46].

`

``

434

`+

The Rust compiler supports shadow stack for the AArch64 architecture<sup

`

``

435

`+

id="fnref:7" role="doc-noteref">7on

`

``

436

`+

nightly builds[43]-[44], and also supports safe stack on nightly

`

``

437

`+

builds[45]-[46].

`

436

438

``

437

439

```` ```text


`438`

`440`

`$ readelf -s target/release/hello-rust | grep __safestack_init

`

`439`

``

`-

1177: 00000000000057b0 444 FUNC GLOBAL DEFAULT  9 __safestack_init

`

``

`441`

`+

678: 0000000000008c80 426 FUNC GLOBAL DEFAULT 15 __safestack_init

`

`440`

`442`

```` ```

441

443

`Fig. 16. Checking if LLVM SafeStack is enabled for a given binary.

`

442

444

``

443

445

`` The presence of the __safestack_init symbol indicates that LLVM SafeStack is

``

444

``

`-

enabled for a given binary (see Fig. 16). Conversely, the absence of the

`

445

``

`` -

__safestack_init symbol indicates that LLVM SafeStack is not enabled for a

``

446

``

`-

given binary.

`

``

446

`` +

enabled for a given binary. Conversely, the absence of the __safestack_init

``

``

447

`+

symbol indicates that LLVM SafeStack is not enabled for a given binary (see

`

``

448

`+

Fig. 16).

`

447

449

``

448

450

`7. The shadow stack implementation for the AMD64 architecture

`

449

451

`and equivalent in LLVM was removed due to performance and security issues. <a

`

`` @@ -458,7 +460,7 @@ the PT_GNU_STACK program header indicates whether the stack should be

``

458

460

`executable, and the absence of this header indicates that the stack should be

`

459

461

`` executable. However, the Linux kernel currently sets the READ_IMPLIES_EXEC

``

460

462

`` personality upon loading any executable with the PT_GNU_STACK program header

``

461

``

`` -

and the PF_X flag set or with the absence of this header, resulting in not

``

``

463

`` +

and the PF_X flag set or with the absence of this header, resulting in not

``

462

464

`only the stack, but also all readable virtual memory mappings being executable.

`

463

465

``

464

466

`An attempt to fix this [was made in

`

`` @@ -560,19 +562,19 @@ to READ_IMPLIES_EXEC).

``

560

562

`25. A. Clark. “Explicitly disable stack execution on linux and bsd #30859.”

`

561

563

` GitHub. https://github.com/rust-lang/rust/pull/30859.

`

562

564

``

563

``

`-

  1. “Replace stack overflow checking with stack probes #16012.” GitHub.

`

``

565

`+

  1. Zoxc. “Replace stack overflow checking with stack probes #16012.” GitHub.

`

564

566

`https://github.com/rust-lang/rust/issues/16012.

`

565

567

``

566

``

`-

  1. B. Striegel. “Extend stack probe support to non-tier-1 platforms, and

`

567

``

`-

clarify policy for mitigating LLVM-dependent unsafety #43241.” GitHub.

`

568

``

`-

https://github.com/rust-lang/rust/issues/43241.

`

569

``

-

570

``

`-

  1. A. Crichton. “rustc: Implement stack probes for x86 #42816.” GitHub.

`

``

568

`+

  1. A. Crichton. “rustc: Implement stack probes for x86 #42816.” GitHub.

`

571

569

`https://github.com/rust-lang/rust/pull/42816.

`

572

570

``

573

``

`-

  1. A. Crichton. “Add __rust_probestack intrinsic #175.” GitHub.

`

``

571

`+

  1. A. Crichton. “Add __rust_probestack intrinsic #175.” GitHub.

`

574

572

`https://github.com/rust-lang/compiler-builtins/pull/175.

`

575

573

``

``

574

`+

  1. S. Guelton, S. Ledru, J. Stone. “Bringing Stack Clash Protection to Clang /

`

``

575

`+

X86 — the Open Source Way.” The LLVM Project Blog.

`

``

576

`+

https://blog.llvm.org/posts/2021-01-05-stack-clash-protection/.

`

``

577

+

576

578

`30. B. Anderson. “Consider applying -Wl,-z,relro or -Wl,-z,relro,-z,now by

`

577

579

` default #29877.” GitHub. https://github.com/rust-lang/rust/issues/29877.

`

578

580

``

`` @@ -605,16 +607,16 @@ to READ_IMPLIES_EXEC).

``

605

607

`39. A. Crichton. “Remove the alloc_jemalloc crate #55238.” GitHub.

`

606

608

`https://github.com/rust-lang/rust/pull/55238.

`

607

609

``

608

``

`-

  1. R. de C Valle. “Tracking Issue for LLVM Control Flow Integrity (CFI) Support

`

``

610

`+

  1. bbjornse. “Add codegen option for using LLVM stack smash protection #84197.”

`

``

611

`+

GitHub. https://github.com/rust-lang/rust/pull/84197

`

``

612

+

``

613

`+

  1. R. de C. Valle. “Tracking Issue for LLVM Control Flow Integrity (CFI) Support

`

609

614

` for Rust #89653.” GitHub. https://github.com/rust-lang/rust/issues/89653.

`

610

615

``

611

``

`-

  1. “ControlFlowIntegrity.” The Rust Unstable Book.

`

``

616

`+

  1. “ControlFlowIntegrity.” The Rust Unstable Book.

`

612

617

`https://doc.rust-lang.org/unstable-book/compiler-flags/sanitizer.html#controlflowintegrity.

`

613

618

``

614

``

`-

  1. bbjornse. “add codegen option for using LLVM stack smash protection #84197.”

`

615

``

`-

GitHub. https://github.com/rust-lang/rust/pull/84197

`

616

``

-

617

``

`-

  1. ivanloz. “Add support for LLVM ShadowCallStack. #98208.” GitHub.

`

``

619

`+

  1. I. Lozano. “Add support for LLVM ShadowCallStack #98208.” GitHub.

`

618

620

`https://github.com/rust-lang/rust/pull/98208.

`

619

621

``

620

622

`44. “ShadowCallStack.” The Rust Unstable Book.

`