Skip to content

Commit f56ad39

Browse files
committed
fix: Prevent usernames with leading - from being passed to SSH
This detects ambiguous usernames in dangerous cases where they would be passed to external commands to form SSH connections, if they would be misinterpreted as option arguments. This change is analogous to b06a0dd, hardening `gix-transport` and applications that use it against options smuggled in URLs, but for the non-mandatory username portion of a URL, rather than the host and path portions that were covered there. For example, commands like these no longer pass `-F...` options to `ssh`: gix clone 'ssh://[email protected]/abc' gix clone -- '[email protected]:abc/def' Instead, they refuse to run `ssh`, producing the error: Error: Username '-Fconfigfile' could be mistaken for a command-line argument
1 parent 5428609 commit f56ad39

File tree

2 files changed

+17
-3
lines changed

2 files changed

+17
-3
lines changed

gix-transport/src/client/blocking_io/ssh/program_kind.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,12 @@ impl ProgramKind {
6060
}
6161
}
6262
};
63-
let host_as_ssh_arg = match url.user() {
63+
let host_maybe_with_user_as_ssh_arg = match url.user() {
6464
Some(user) => {
65+
// FIXME: See the fixme comment on Url::user_argument_safe() about its return type.
66+
if url.user_argument_safe() != Some(user) {
67+
return Err(ssh::invocation::Error::AmbiguousUserName { user: user.into() });
68+
}
6569
let host = url.host().expect("present in ssh urls");
6670
format!("{user}@{host}")
6771
}
@@ -75,8 +79,11 @@ impl ProgramKind {
7579
}
7680
};
7781

78-
// Try to force ssh to yield english messages (for parsing later)
79-
Ok(prepare.arg(host_as_ssh_arg).env("LANG", "C").env("LC_ALL", "C"))
82+
// Try to force ssh to yield English messages (for parsing later).
83+
Ok(prepare
84+
.arg(host_maybe_with_user_as_ssh_arg)
85+
.env("LANG", "C")
86+
.env("LC_ALL", "C"))
8087
}
8188

8289
/// Note that the caller has to assure that the ssh program is launched in English by setting the locale.

gix-url/src/lib.rs

+7
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,13 @@ impl Url {
180180
///
181181
/// Use this method if the user or a portion of the URL that begins with it will be passed to a command-line application.
182182
pub fn user_argument_safe(&self) -> Option<&str> {
183+
// FIXME: A return value of None from this method, or host_argument_safe(), is ambiguous: the user (or host) is
184+
// either present but unsafe, or absent. Furthermore, in practice the value is usually needed even if unsafe,
185+
// in order to report it in an error message. In gix-transport, the ambiguity makes it easy to write a new bug
186+
// while using this interface for user_argument_safe(). In contrast, in host_argument_safe(), the ambiguity is
187+
// much less of a problem, because the host is expected to be present. Yet the host() method must still be
188+
// called when handling the None case, to include it in the error. If possible, both methods should be replaced
189+
// by methods with a richer return type (a new enum). If not, the ambiguity should be prominently documented.
183190
self.user().filter(|user| !looks_like_argument(user.as_bytes()))
184191
}
185192

0 commit comments

Comments
 (0)