Skip to content

Unsound lifetime bound in Remote::get_refspec #1286

Description

@kimjy0126

Remote::get_refspec returns a RefSpec with lifetime 'repo, not the same lifetime as &self. This allows Refspec to outlive Remote (self).

git2-rs/src/remote.rs

Lines 301 to 306 in a00922b

pub fn get_refspec(&self, i: usize) -> Option<Refspec<'repo>> {
unsafe {
let ptr = raw::git_remote_get_refspec(&*self.raw, i as libc::size_t);
Binding::from_raw_opt(ptr)
}
}

Reproduction

#[forbid(unsafe_code)]

use git2::Repository;

fn main() {
    let repo = Repository::init("temp_dir").unwrap();
    repo.remote("origin", "https://aaa.com/bbb.git").unwrap();
    
    let refspec = {
        let remote = repo.find_remote("origin").unwrap();
        remote.get_refspec(0)
    };
    // remote goes out of scope
    // but refspec's lifetime is not bounded to remote    
    
    // removing temp_dir, not necessary to trigger UAF
    let _ = std::fs::remove_dir_all("temp_dir");
    
    // triggers UAF
    let _ = refspec.unwrap().str();
}

You can get ASan UAF report by running following command. git2 latest release version (0.21.0) and latest commit in main branch (a00922b) print the same ASan report.

CFLAGS=-fsanitize=address RUSTFLAGS="-Zsanitizer=address" cargo +nightly run --target x86_64-unknown-linux-gnu

I reported this issue to security team first, and they said it's ok to make this issue publicly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions