Other modules extern
functions can currently be redefined
#47449
Labels
C-bug
Category: This is a bug.
I-crash
Issue: The compiler crashes (SIGSEGV, SIGABRT, etc). Use I-ICE instead when the compiler panics.
T-compiler
Relevant to the compiler team, which will review and decide on the PR/issue.
Currently it is possible to redefine functions that are defined as
extern
in another module. This affects many internal functions to rustc (the compiler) as well as the built Rust application.The most bold issue is currently this is safe in stable, produces no warnings or errors, and causes a crash of the built program:
This crash can be observed directly on the Rust playground https://play.rust-lang.org/?gist=c914a0d307eff3b7d4bb2b90b264970e&version=stable
The issue at heart is being able to redefine
extern
functions from another module. For example a simple application like this is allowed:Further this issue also affects
rustc
itself, in that it can invalidate certain internal compiler state and cause memory corruption and a crash ofrustc
.Building this will cause
rustc
to crash due to an out of bounds write due to type confusion around the type of__CxxFrameHandler3
. This issue can cause some pretty catastrophic corruption resulting inrustc
jumping to arbitrary code as seen here: https://gist.github.com/gamozolabs/d966adc2e13310a8ddb65285e5936681 (sorry, don't have symbols to this official build). Due to this being memory corruption, it might not always trigger a crash. Turning on page heap or address sanitizer makes it always crash, but without these it's 'random'.Here's stack traces at each stage of this crash, and the call site of the allocation that is being written out of bounds to:
https://gist.github.com/gamozolabs/2fc773c092a37ce3b160e946b6d475a3
This would be an assert if LLVM assertions are turned on and it is related to #38641 .
Further this also can be caused on non-MSVC targets by doing it as such:
Further it seems LLVM errors can be caused by defining LLVM intrinsics such as:
Output:
However if you try this with a made up LLVM intrinsic name, it yells at you for trying to define LLVM intrinsics:
Output:
At this point I've stopped looking for more examples of what this impacts as it's just too many to bother writing up. Almost all of my testing was done on x86_64 Windows as a host with nightly Rust, however I have cross checked most things on Linux or the Rust playground.
Further while almost all of these examples use
#[export_name]
or#[no_mangle]
, this issue also can occur if you have anextern
that is named the same as your mangled Rust function. A bit niche, but this issue is not with just these attributes.One worry with fixing this is that it would break a lot of
#![no_std]
projects that implementpanic_fmt
,memcpy
, etc as they are defined asextern
in Rust. I think to make this work we would have to enforce that the type signature of theextern
matches the type signature of the function you are implementing. If you declareextern { pub unsafe extern "C" fn memcpy(...) }
then the reimplementation must match that including theunsafe
. Which at that point this is no longer unsound. Or it might be able to be made that any naming collisions with anextern {}
must beunsafe
. Haven't thought through all the edge cases of that.-B
The text was updated successfully, but these errors were encountered: