Skip to content

Conversation

@taiki-e
Copy link
Member

@taiki-e taiki-e commented Jan 23, 2026

Potential fix for rust-lang/rust#151486.

TODO:

  • Does this approach work in naked_asm?
  • How to test this on CI? Both linux and macos runner by GitHub doesn't seem to support BTI.

@taiki-e taiki-e changed the title Use BTI c in aarch64_outline_atomic.rs WIP: Use BTI c in aarch64_outline_atomic.rs Jan 23, 2026
@tgross35
Copy link
Contributor

Thanks for jumping on this

How to test this on CI? Both linux and macos runner by GitHub doesn't seem to support BTI.

@rust-lang/project-exploit-mitigations any chance you have some testing ideas?

Does BTI work in qemu-user by chance?

@zmodem
Copy link

zmodem commented Jan 26, 2026

grep'ing compiler-builtins, I don't see any mention of bti at all. Maybe instead of adding hint #34 to each function manually, there should be some general facility which adds BTI landingpads to manually generated functions when the feature is enabled.

@taiki-e
Copy link
Member Author

taiki-e commented Jan 26, 2026

For normal Rust functions, the BTI c should be inserted by the compiler as needed. For global assemblies, the BTI c should be explicitly written within the assembly as needed.

However, it is unclear whose responsibility it should be for naked functions (what we use for outline_atomic). At least currently, the naked function does nothing, but -Z branch-protection is unstable so we can change its behavior.
cc @Amanieu @folkertdev

Comment on lines +416 to +423
#[cfg(all(branch_protection = "bti", branch_protection = "pac-ret"))]
".word 3",
#[cfg(all(not(branch_protection = "bti"), branch_protection = "pac-ret"))]
".word 2",
#[cfg(all(branch_protection = "bti", not(branch_protection = "pac-ret")))]
".word 1",
#[cfg(all(not(branch_protection = "bti"), not(branch_protection = "pac-ret")))]
".word 0",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think cfg_select would be nicer here

Suggested change
#[cfg(all(branch_protection = "bti", branch_protection = "pac-ret"))]
".word 3",
#[cfg(all(not(branch_protection = "bti"), branch_protection = "pac-ret"))]
".word 2",
#[cfg(all(branch_protection = "bti", not(branch_protection = "pac-ret")))]
".word 1",
#[cfg(all(not(branch_protection = "bti"), not(branch_protection = "pac-ret")))]
".word 0",
cfg_select! (
all(branch_protection = "bti", branch_protection = "pac-ret") => ".word 3",
branch_protection = "pac-ret" => ".word 2",
branch_protection = "bti" => ".word 1",
_ => ".word 0",
),

@folkertdev
Copy link
Contributor

I'm not that familiar with how this works, but generally the aim is to make naked functions "just work". So I'd say naked functions should support the flag.

@zmodem
Copy link

zmodem commented Jan 26, 2026

There was some discussion about naked functions vs. bti on the llvm side: llvm/llvm-project#56369 but it didn't conclude. I'm not actually sure what the current behavior is.

@folkertdev
Copy link
Contributor

Rust naked functions are entirely distinct from LLVM naked functions. We lower them to a block of global assembly + an extern block defining the rust symbol ourselves. So, we are free to make our own decisions here. So far, this flag was not considered, but it seems like we should.

@Amanieu
Copy link
Member

Amanieu commented Jan 26, 2026

I would actually prefer not having a BTI automatically inserted at the start of naked functions. The main purpose of naked functions is to support custom calling conventions which cannot be otherwise supported by the Rust compiler. In those cases we don't want to mess with what the user is intending for these functions to contain.

@folkertdev
Copy link
Contributor

Ah, I misunderstood: this actually adds instructions. Then I agree that we should not add that. And then -Z branch-protection should provide a way (via cfg maybe?) for the program to know what mode it's being compiled in.

@Amanieu
Copy link
Member

Amanieu commented Jan 28, 2026

Is there any reason these functions need to be naked at all? They don't use a custom calling convention and could just be implemented using plain asm!. This would avoid any issues related to branch protection.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants