Skip to content

target_feature_11 allows bypassing safety checks through Fn* traits #72012

Closed
@hanna-kruppe

Description

@hanna-kruppe
Contributor

(Moved from #69098 (comment) with an added PoC.)

The following program (playground) demonstrates how current implementation of target_feature_11 allows using a target_feature from safe code without ensuring it's actually available:

#![feature(target_feature_11)]

#[target_feature(enable="avx")]
fn use_avx() {
    println!("Hello from AVX")
}

fn call_it(f: impl FnOnce()) {
    f();
}

fn main() {
    call_it(use_avx);
}

This is unsound because it allows executing (e.g.) AVX instructions on CPUs that do not implement them, which is UB. It only works because "safe fns with target_features" are erroneously considered to implement the FnOnce/FnMut/Fn traits.

Activity

added
I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness
C-bugCategory: This is a bug.
requires-nightlyThis issue requires a nightly compiler in some way.
on May 8, 2020
petrochenkov

petrochenkov commented on May 8, 2020

@petrochenkov
Contributor

Proposed resolution: #69098 (comment).

It would probably be better to add the unsafe to #[target_feature] functions implicitly during lowering to HIR.
Implicit unsafe is already added to functions in extern blocks in the same way.

That would make the unsafety checker the only place (besides AST lowering) where they would be treated specially. Like, "yes, the function is unsafe, but we know that it's safe to call in this specific context, so the unsafe block can be omitted".

The special coercion checks would no longer be necessary in that case.

added
T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
and removed on May 8, 2020
petrochenkov

petrochenkov commented on May 8, 2020

@petrochenkov
Contributor

Or perhaps the RFC should be revised to still require writing unsafe fn and only unsafety checker need to be enhanced to allow calling unsafe functions without unsafe blocks in the situations known to be safe.

That would be even less magic, which is good, IMO.
The ergonomic regression would be minor because unsafe would still be not required at call sites.

nikomatsakis

nikomatsakis commented on May 8, 2020

@nikomatsakis
Contributor

Good catch. Another option is that referencing, not calling, a target-feature function is unsafe, but I guess that is a bit inconsistent given that this already compiles (playground):

#[target_feature(enable="avx")]
unsafe fn use_avx() {
    println!("Hello from AVX")
}

fn call_it(f: impl FnOnce()) {
    f();
}

fn main() {
    let x = use_avx;
}

In other words, accessing a safe target feature 1.1 function would be unsafe (unless the target feature is in scope), not just calling it.

I think that this is what I would expect somehow, but I would expect it to apply uniformly to both safe and unsafe target feature functions (and that's not an option).

Or perhaps the RFC should be revised to still require writing unsafe fn and only unsafety checker need to be enhanced to allow calling unsafe functions without unsafe blocks in the situations known to be safe.

The downside of this approach is that we don't know why the function was declared unsafe, not really -- was it only because of the target feature? Or were there additional requirements that would have made it unsafe?

hanna-kruppe

hanna-kruppe commented on May 8, 2020

@hanna-kruppe
ContributorAuthor

The downside of this approach is that we don't know why the function was declared unsafe, not really -- was it only because of the target feature? Or were there additional requirements that would have made it unsafe?

For example, a whole bunch of core::arch::* functions take raw pointers and use them to access memory, so they need to be unsafe even if the respective target feature is enabled in the calling context.

petrochenkov

petrochenkov commented on May 8, 2020

@petrochenkov
Contributor

The downside of this approach is that we don't know why the function was declared unsafe, not really -- was it only because of the target feature? Or were there additional requirements that would have made it unsafe?

Ah, right, that's a good argument.
The "unsafety checker enhancement" should only affect unsafe functions that are made unsafe through #[target_feature], but not other means (explicit unsafe or extern block).

added
I-prioritizeIssue: Indicates that prioritization has been requested for this issue.
on Jun 9, 2020
removed
I-prioritizeIssue: Indicates that prioritization has been requested for this issue.
on Jun 9, 2020

19 remaining items

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-target-featureArea: Enabling/disabling target features like AVX, Neon, etc.C-bugCategory: This is a bug.F-target_feature_11target feature 1.1 RFCI-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-langRelevant to the language teamrequires-nightlyThis issue requires a nightly compiler in some way.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      Participants

      @nikomatsakis@calebzulawski@jonas-schievink@hanna-kruppe@petrochenkov

      Issue actions

        target_feature_11 allows bypassing safety checks through Fn* traits · Issue #72012 · rust-lang/rust