Fix nested runtime panic during SSH key authentication
Dependency security audit / rustsec (push) Successful in 23s
Dependency security audit / rustsec (push) Successful in 23s
This commit is contained in:
1 parent
aec3f237a9
commit
71a4f289cf
2 files changed
+36
-14
No files matched your search
@@ -755,8 +755,21 @@ fn non_fast_forward_and_cancellation_fail_without_blind_replay() {
|
|||||||
local.add_remote("origin", remote.url()).expect("remote");
|
local.add_remote("origin", remote.url()).expect("remote");
|
||||||
let control = GitOperationControl::default();
|
let control = GitOperationControl::default();
|
||||||
let cancel = control.clone();
|
let cancel = control.clone();
|
||||||
|
let observed = server.observed.clone();
|
||||||
let cancellation = thread::spawn(move || {
|
let cancellation = thread::spawn(move || {
|
||||||
thread::sleep(Duration::from_millis(100));
|
let deadline = std::time::Instant::now() + Duration::from_secs(5);
|
||||||
|
while observed
|
||||||
|
.lock()
|
||||||
|
.expect("observed")
|
||||||
|
.receive_requests
|
||||||
|
.is_empty()
|
||||||
|
{
|
||||||
|
assert!(
|
||||||
|
std::time::Instant::now() < deadline,
|
||||||
|
"push request not received"
|
||||||
|
);
|
||||||
|
thread::sleep(Duration::from_millis(1));
|
||||||
|
}
|
||||||
cancel.cancel();
|
cancel.cancel();
|
||||||
});
|
});
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
|
|||||||
+22
-13
@@ -162,13 +162,11 @@ impl SshSession {
|
|||||||
control.report(GitProgressPhase::Authenticating)?;
|
control.report(GitProgressPhase::Authenticating)?;
|
||||||
let user = connection.user.as_deref().unwrap_or("git");
|
let user = connection.user.as_deref().unwrap_or("git");
|
||||||
let authenticated = match &connection.identity {
|
let authenticated = match &connection.identity {
|
||||||
SshIdentitySource::KeyFile(path) => runtime.block_on(authenticate_key_file(
|
SshIdentitySource::KeyFile(path) => {
|
||||||
&mut handle,
|
// Synchronous secret stores may drive their own runtime.
|
||||||
user,
|
let key = load_identity(path, passphrases)?;
|
||||||
path,
|
runtime.block_on(authenticate_key_file(&mut handle, user, key, control))?
|
||||||
passphrases,
|
}
|
||||||
control,
|
|
||||||
))?,
|
|
||||||
SshIdentitySource::Agent {
|
SshIdentitySource::Agent {
|
||||||
fingerprint,
|
fingerprint,
|
||||||
socket,
|
socket,
|
||||||
@@ -770,13 +768,10 @@ impl client::Handler for HostVerifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn authenticate_key_file(
|
fn load_identity(
|
||||||
handle: &mut client::Handle<HostVerifier>,
|
|
||||||
user: &str,
|
|
||||||
path: &Path,
|
path: &Path,
|
||||||
passphrases: &dyn SshPassphraseProvider,
|
passphrases: &dyn SshPassphraseProvider,
|
||||||
control: &GitOperationControl,
|
) -> Result<PrivateKey, GitError> {
|
||||||
) -> Result<bool, GitError> {
|
|
||||||
let metadata = fs::symlink_metadata(path).map_err(|_| GitError::SshIdentityMissing {
|
let metadata = fs::symlink_metadata(path).map_err(|_| GitError::SshIdentityMissing {
|
||||||
path: path.to_owned(),
|
path: path.to_owned(),
|
||||||
})?;
|
})?;
|
||||||
@@ -802,6 +797,15 @@ async fn authenticate_key_file(
|
|||||||
fingerprint: fingerprint.clone(),
|
fingerprint: fingerprint.clone(),
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
|
Ok(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn authenticate_key_file(
|
||||||
|
handle: &mut client::Handle<HostVerifier>,
|
||||||
|
user: &str,
|
||||||
|
key: PrivateKey,
|
||||||
|
control: &GitOperationControl,
|
||||||
|
) -> Result<bool, GitError> {
|
||||||
let hash = rsa_hash(handle, key.public_key(), control).await?;
|
let hash = rsa_hash(handle, key.public_key(), control).await?;
|
||||||
let result = controlled(
|
let result = controlled(
|
||||||
handle.authenticate_publickey(user, PrivateKeyWithHashAlg::new(Arc::new(key), hash)),
|
handle.authenticate_publickey(user, PrivateKeyWithHashAlg::new(Arc::new(key), hash)),
|
||||||
@@ -1230,7 +1234,12 @@ mod tests {
|
|||||||
&self,
|
&self,
|
||||||
fingerprint: &SshFingerprint,
|
fingerprint: &SshFingerprint,
|
||||||
) -> Result<SecretBytes, GitError> {
|
) -> Result<SecretBytes, GitError> {
|
||||||
self.0
|
// Model a synchronous secret store that drives its own async backend.
|
||||||
|
static RUNTIME: std::sync::OnceLock<tokio::runtime::Runtime> =
|
||||||
|
std::sync::OnceLock::new();
|
||||||
|
RUNTIME
|
||||||
|
.get_or_init(|| tokio::runtime::Runtime::new().expect("secret store runtime"))
|
||||||
|
.block_on(async { self.0 })
|
||||||
.map(|value| SecretBytes::new(value.to_vec()))
|
.map(|value| SecretBytes::new(value.to_vec()))
|
||||||
.ok_or_else(|| GitError::SshKeyPassphraseUnavailable {
|
.ok_or_else(|| GitError::SshKeyPassphraseUnavailable {
|
||||||
fingerprint: fingerprint.clone(),
|
fingerprint: fingerprint.clone(),
|
||||||
|
|||||||
Reference in new issue
Block a user