Skip to content

CFI: SIGILL reached via trait objects #106547

@maurer

Description

@maurer
Contributor

I tried this code:

struct T;
trait TT {
    fn foo(&self);
}

impl TT for T {
    fn foo(&self) {
        println!("foo");
    }
}

fn main() {
    let x = T;
    let y = &x as &dyn TT;
    y.foo();
}

I expected to see this happen: "foo" should be printed and the program should exit, as in

mmaurer@curtana:~/printer$ cargo run
   Compiling printer v0.1.0 (/usr/local/google/home/mmaurer/printer)
    Finished dev [unoptimized + debuginfo] target(s) in 0.29s
     Running `target/debug/printer`
foo
mmaurer@curtana:~/printer$

Instead, this happened: "Illegal instruction" is printed as the program has received a SIGILL

mmaurer@curtana:~/printer$ RUSTFLAGS="-Zsanitizer=cfi -C lto -Cembed-bitcode=yes" cargo run
   Compiling printer v0.1.0 (/usr/local/google/home/mmaurer/printer)
    Finished dev [unoptimized + debuginfo] target(s) in 2.51s
     Running `target/debug/printer`
Illegal instruction
mmaurer@curtana:~/printer$ echo $?
132
mmaurer@curtana:~/printer$ 

Meta

rustc --version --verbose:

rustc 1.68.0-nightly (388538fc9 2023-01-05)
binary: rustc
commit-hash: 388538fc963e07a94e3fc3ac8948627fd2d28d29
commit-date: 2023-01-05
host: x86_64-unknown-linux-gnu
release: 1.68.0-nightly
LLVM version: 15.0.6

Activity

maurer

maurer commented on Jan 6, 2023

@maurer
ContributorAuthor
maurer

maurer commented on Jan 6, 2023

@maurer
ContributorAuthor

@rustbot claim

Ran into this while trying to enable KCFI for Linux, and found that the same bug exists in a much more simple environment with the arguably-more-stable CFI support. I'll be debugging this later today or early next week, but wanted to post this since I know the problem exists.

maurer

maurer commented on Jan 11, 2023

@maurer
ContributorAuthor

The core of the problem here is that the type data for T::Foo correctly wants to receive a &T, not a &dyn TT. The thunk generated at the &dyn TT based call checks T::Foo expecting &dyn TT to be legal.

clang typechecks their vtables rather than their functions for this, which I think makes sense - it doesn't require us to thunk the function, and doesn't end up with a looser-than-true piece of metadata on each call.

I'll take a crack at that next.

7 remaining items

added a commit that references this issue on May 23, 2023
20b6e5a
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

C-bugCategory: This is a bug.PG-exploit-mitigationsProject group: Exploit mitigations

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

    Development

    Participants

    @maurer@rcvalle

    Issue actions

      CFI: SIGILL reached via trait objects · Issue #106547 · rust-lang/rust