Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/bin/cargo/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ pub fn main(gctx: &mut GlobalContext) -> CliResult {
global_args,
Some(&exec),
)?;
super::init_git(gctx);
super::init_git();

exec.exec(gctx, subcommand_args)?;
}
Expand Down
38 changes: 1 addition & 37 deletions src/bin/cargo/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
use cargo::core::features;
use cargo::util::network::http::http_handle;
use cargo::util::network::http::needs_custom_http_transport;
use cargo::util::{self, CargoResult, closest_msg, command_prelude};
use cargo_util::{ProcessBuilder, ProcessError};
use cargo_util_schemas::manifest::StringOrVec;
Expand Down Expand Up @@ -370,7 +368,7 @@ fn search_directories(gctx: &GlobalContext) -> Vec<PathBuf> {

/// Initialize libgit2.
#[tracing::instrument(skip_all)]
fn init_git(gctx: &GlobalContext) {
fn init_git() {
// Disabling the owner validation in git can, in theory, lead to code execution
// vulnerabilities. However, libgit2 does not launch executables, which is the foundation of
// the original security issue. Meanwhile, issues with refusing to load git repos in
Expand All @@ -392,38 +390,4 @@ fn init_git(gctx: &GlobalContext) {
git2::opts::set_verify_owner_validation(false)
.expect("set_verify_owner_validation should never fail");
}

init_git_transports(gctx);
}

/// Configure libgit2 to use libcurl if necessary.
///
/// If the user has a non-default network configuration, then libgit2 will be
/// configured to use libcurl instead of the built-in networking support so
/// that those configuration settings can be used.
#[tracing::instrument(skip_all)]
fn init_git_transports(gctx: &GlobalContext) {
match needs_custom_http_transport(gctx) {
Ok(true) => {}
_ => return,
}

let handle = match http_handle(gctx) {
Ok(handle) => handle,
Err(..) => return,
};

// The unsafety of the registration function derives from two aspects:
//
// 1. This call must be synchronized with all other registration calls as
// well as construction of new transports.
// 2. The argument is leaked.
//
// We're clear on point (1) because this is only called at the start of this
// binary (we know what the state of the world looks like) and we're mostly
// clear on point (2) because we'd only free it after everything is done
// anyway
unsafe {
git2_curl::register(handle);
}
}
14 changes: 10 additions & 4 deletions src/cargo/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,16 @@
//! - <https://doc.rust-lang.org/nightly/nightly-rustc/cargo>: targeted at cargo contributors
//! - Updated on each update of the `cargo` submodule in `rust-lang/rust`
//!
//! > This library is maintained by the Cargo team, primarily for use by Cargo
//! > and not intended for external use (except as a transitive dependency). This
//! > crate may make major changes to its APIs. See [The Cargo Book:
//! > External tools] for more on this topic.
//! <div class="warning">
//!
//! This library is maintained by the Cargo team, primarily for use by Cargo
//! and not intended for external use.
//! This crate may make major changes to its APIs or assumptions about how it is invoked (e.g.
//! when it is safe to call [git2::transport::register]).
//!
//! See [The Cargo Book: External tools] for alternatives to using this library.
//!
//! </div>
//!
//! ## Overview
//!
Expand Down
47 changes: 47 additions & 0 deletions src/cargo/sources/git/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ use crate::sources::git::source::GitSource;
use crate::sources::source::Source as _;
use crate::util::HumanBytes;
use crate::util::errors::{CargoResult, GitCliError};
use crate::util::network::http::http_handle;
use crate::util::network::http::needs_custom_http_transport;
use crate::util::{GlobalContext, IntoUrl, MetricsCounter, Progress, network};

use anyhow::{Context as _, anyhow};
Expand All @@ -23,6 +25,7 @@ use std::borrow::Cow;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::str;
use std::sync::Once;
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::{Duration, Instant};

Expand Down Expand Up @@ -1308,6 +1311,24 @@ fn fetch_with_libgit2(
) -> CargoResult<()> {
debug!(target: "git-fetch", backend = "libgit2");

static INIT: Once = Once::new();
INIT.call_once(|| {
// SAFETY:
//
// The unsafety of the registration function derives from two aspects:
//
// 1. This call must be synchronized with all other registration calls as
// well as construction of new transports.
// 2. The argument is leaked.
//
// We're clear on point (1) because this is the only `register` call we make in the
// cargo-binary and cargo-library is not officially supported and it is under a lock.
// Technically, `git2_curl` also has a lock but that isn't part of their API guarantees.
//
// We're mostly clear on point (2) because we'd only free it after everything is done anyway
unsafe { init_git_transports(gctx) };
});

let git_config = git2::Config::open_default()?;
with_fetch_options(&git_config, remote_url, gctx, &mut |mut opts| {
if tags {
Expand Down Expand Up @@ -1356,6 +1377,32 @@ fn fetch_with_libgit2(
})
}

/// Configure libgit2 to use libcurl if necessary.
///
/// If the user has a non-default network configuration, then libgit2 will be
/// configured to use libcurl instead of the built-in networking support so
/// that those configuration settings can be used.
///
/// # Safety
///
/// See [git2_curl::register]
#[tracing::instrument(skip_all)]
unsafe fn init_git_transports(gctx: &GlobalContext) {
match needs_custom_http_transport(gctx) {
Ok(true) => {}
_ => return,
}

let handle = match http_handle(gctx) {
Ok(handle) => handle,
Err(..) => return,
};

unsafe {
git2_curl::register(handle);
}
}

/// Attempts to `git gc` a repository.
///
/// Cargo has a bunch of long-lived git repositories in its global cache and
Expand Down