Skip to content

SGX's std::env::args function is not thread-safe #64304

Closed

Description

@sugar700

The args method is defined as follows.

pub fn args() -> Args {
    let args = unsafe { (ARGS.load(Ordering::Relaxed) as *const ArgsStore).as_ref() };
    if let Some(args) = args {
        Args(args.iter())
    } else {
        Args([].iter())
    }
}

Clean-up function is defined as follows;

pub unsafe fn cleanup() {
    let args = ARGS.swap(0, Ordering::Relaxed);
    if args != 0 {
        drop(Box::<ArgsStore>::from_raw(args as _))
    }
}

It is possible for another thread to use std::env::args() while the main thread quits, and access already freed memory - assuming the following sequence of events.

// Secondary thread
let args = unsafe { (ARGS.load(Ordering::Relaxed) as *const ArgsStore).as_ref() };
// Main thread
{
    let args = ARGS.swap(0, Ordering::Relaxed);
    if args != 0 {
        drop(Box::<ArgsStore>::from_raw(args as _))
    }
}
// Secondary thread
if let Some(args) = args {
    Args(args.iter())
}

This issue has been assigned to @Goirad via this comment.

Activity

  1. added
    I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness
    T-libs-api[DEPRECATED; DO NOT USE]
    on Sep 10, 2019
  2. jonas-schievink commented on Dec 10, 2019

    @jonas-schievink
    Contributor

    cc @jethrogb

    (do we want an O-fortanix-sgx label?)

  3. jethrogb commented on Dec 10, 2019

    @jethrogb
    Contributor

    I suppose we could just turn cleanup into a NOP. How do other platforms handle this?

  4. Goirad commented on Feb 5, 2020

    @Goirad
    Contributor

    @rustbot claim

  5. self-assigned this
    on Feb 5, 2020
  6. Goirad commented on Feb 7, 2020

    @Goirad
    Contributor

    Looking at other implementations, the only times when this is not a NOP is for hermit vxcode and unix on non-apple variants. In all these cases the code is:

    pub unsafe fn cleanup() {
        let _guard = LOCK.lock();
        ARGC = 0;
        ARGV = ptr::null();
    }
    

    I am inclined to just change it to a NOP. What was the motivation for the existing logic?

  7. jethrogb commented on Feb 10, 2020

    @jethrogb
    Contributor

    What was the motivation for the existing logic?

    Implement the required function cleanup without knowing exactly what needs to happen.

    Having done some git archeology, it looks to me like the cleanup function exists solely for certain platforms where the arguments may be stored on the stack of the main thread. If the main thread exits, that stack may no longer be available so other threads may not reference it.

    I think turning it into a nop for SGX is probably fine.

  8. added a commit that references this issue on Feb 13, 2020
    2501a10
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.I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessT-libs-api[DEPRECATED; DO NOT USE]

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions