From 6baf17f609d736946c865280a493041af8e83d17 Mon Sep 17 00:00:00 2001 From: t8y2 <1156263951@qq.com> Date: Mon, 24 Aug 2026 13:19:25 +0000 Subject: [PATCH] fix(ssh): trim Pageant username buffer padding Closes #7091 --- vendor/pageant/src/username.rs | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/vendor/pageant/src/username.rs b/vendor/pageant/src/username.rs index e957a92ce6..9e0c281b45 100644 --- a/vendor/pageant/src/username.rs +++ b/vendor/pageant/src/username.rs @@ -25,11 +25,20 @@ pub(crate) fn resolve_username( parse_username(local().map_err(UsernameLookupError::Api)?).map_err(|_| UsernameLookupError::Invalid) } -fn parse_username(buffer: Vec) -> Result { - let Some((&0, bytes)) = buffer.split_last() else { - return if buffer.is_empty() { Err(UsernameParseError::Empty) } else { Err(UsernameParseError::Invalid) }; - }; - let username = std::str::from_utf8(bytes).map_err(|_| UsernameParseError::Invalid)?; +fn parse_username(mut buffer: Vec) -> Result { + if buffer.is_empty() { + return Err(UsernameParseError::Empty); + } + if buffer.last() != Some(&0) { + return Err(UsernameParseError::Invalid); + } + while buffer.last() == Some(&0) { + buffer.pop(); + } + if buffer.contains(&0) { + return Err(UsernameParseError::Invalid); + } + let username = std::str::from_utf8(&buffer).map_err(|_| UsernameParseError::Invalid)?; let username = username.rsplit_once('\\').map_or(username, |(_, username)| username); let username = username.split_once('@').map_or(username, |(username, _)| username); if username.is_empty() { Err(UsernameParseError::Empty) } else { Ok(username.to_owned()) } @@ -57,6 +66,13 @@ mod tests { assert_eq!(parse_username(b"DOMAIN\\alice\0".to_vec()), Ok("alice".to_owned())); } + #[test] + fn accepts_only_trailing_username_buffer_padding() { + assert_eq!(parse_username(b"Shaan\0\0\0\0\0\0\0".to_vec()), Ok("Shaan".to_owned())); + assert_eq!(format_pipe_name("Shaan", "0123abcd"), "\\\\.\\pipe\\pageant.Shaan.0123abcd"); + assert_eq!(parse_username(b"alice\0unexpected\0".to_vec()), Err(UsernameParseError::Invalid)); + } + #[test] fn falls_back_when_principal_is_empty() { for principal in [Vec::new(), vec![0]] {