Resolves: RHEL-215674 Resolves: RHEL-215675 Resolves: RHEL-215676 Resolves: RHEL-215677 Resolves: RHEL-215678 Resolves: RHEL-215679 Resolves: RHEL-215680 Assisted-by: Ymir
256 lines
8.3 KiB
Diff
256 lines
8.3 KiB
Diff
From 18ca8c90663b800a21bdce39dab4e402b8ad4bc0 Mon Sep 17 00:00:00 2001
|
|
From: Norbert Pocs <norbertpocs0@gmail.com>
|
|
Date: Wed, 27 Dec 2023 20:32:18 +0100
|
|
Subject: [PATCH 1/3] misc: Add function to check username syntax
|
|
|
|
Malicious code can be injected using the username with metacharacters,
|
|
therefore the username must be validated before using it with any %u.
|
|
|
|
Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
|
|
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
|
|
---
|
|
include/libssh/misc.h | 1 +
|
|
src/misc.c | 32 ++++++++++++++++++++++++++++++++
|
|
tests/unittests/torture_misc.c | 34 ++++++++++++++++++++++++++++++++++
|
|
3 files changed, 67 insertions(+)
|
|
|
|
diff --git a/include/libssh/misc.h b/include/libssh/misc.h
|
|
index a5bee930..c8328722 100644
|
|
--- a/include/libssh/misc.h
|
|
+++ b/include/libssh/misc.h
|
|
@@ -98,5 +98,6 @@ int ssh_quote_file_name(const char *file_name, char *buf, size_t buf_len);
|
|
int ssh_newline_vis(const char *string, char *buf, size_t buf_len);
|
|
|
|
int ssh_check_hostname_syntax(const char *hostname);
|
|
+int ssh_check_username_syntax(const char *username);
|
|
|
|
#endif /* MISC_H_ */
|
|
diff --git a/src/misc.c b/src/misc.c
|
|
index 8bbb2587..23fad83d 100644
|
|
--- a/src/misc.c
|
|
+++ b/src/misc.c
|
|
@@ -1835,4 +1835,36 @@ int ssh_check_hostname_syntax(const char *hostname)
|
|
return SSH_OK;
|
|
}
|
|
|
|
+/**
|
|
+ * @brief Checks syntax of a username
|
|
+ *
|
|
+ * This check disallows metacharacters in the username
|
|
+ *
|
|
+ * @param username The username to be checked, has to be null terminated
|
|
+ *
|
|
+ * @return SSH_OK if the username passes syntax check
|
|
+ * SSH_ERROR otherwise or if username is NULL or empty string
|
|
+ */
|
|
+int ssh_check_username_syntax(const char *username)
|
|
+{
|
|
+ size_t username_len;
|
|
+
|
|
+ if (username == NULL || *username == '-') {
|
|
+ return SSH_ERROR;
|
|
+ }
|
|
+
|
|
+ username_len = strlen(username);
|
|
+ if (username_len == 0 || username[username_len - 1] == '\\' ||
|
|
+ strpbrk(username, "'`\";&<>|(){}") != NULL) {
|
|
+ return SSH_ERROR;
|
|
+ }
|
|
+ for (size_t i = 0; i < username_len; i++) {
|
|
+ if (isspace(username[i]) != 0 && username[i + 1] == '-') {
|
|
+ return SSH_ERROR;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return SSH_OK;
|
|
+}
|
|
+
|
|
/** @} */
|
|
diff --git a/tests/unittests/torture_misc.c b/tests/unittests/torture_misc.c
|
|
index f16b766e..3737ed27 100644
|
|
--- a/tests/unittests/torture_misc.c
|
|
+++ b/tests/unittests/torture_misc.c
|
|
@@ -735,6 +735,39 @@ static void torture_ssh_check_hostname_syntax(void **state)
|
|
assert_int_equal(rc, SSH_ERROR);
|
|
}
|
|
|
|
+static void torture_ssh_check_username_syntax(void **state) {
|
|
+ int rc;
|
|
+ (void)state;
|
|
+
|
|
+ rc = ssh_check_username_syntax("username");
|
|
+ assert_int_equal(rc, SSH_OK);
|
|
+ rc = ssh_check_username_syntax("Alice");
|
|
+ assert_int_equal(rc, SSH_OK);
|
|
+ rc = ssh_check_username_syntax("Alice and Bob");
|
|
+ assert_int_equal(rc, SSH_OK);
|
|
+ rc = ssh_check_username_syntax("n4me?");
|
|
+ assert_int_equal(rc, SSH_OK);
|
|
+
|
|
+ rc = ssh_check_username_syntax("alice&bob");
|
|
+ assert_int_equal(rc, SSH_ERROR);
|
|
+ rc = ssh_check_username_syntax("backslash\\");
|
|
+ assert_int_equal(rc, SSH_ERROR);
|
|
+ rc = ssh_check_username_syntax("&var|()us\"<ha`r{}'");
|
|
+ assert_int_equal(rc, SSH_ERROR);
|
|
+ rc = ssh_check_username_syntax(" -");
|
|
+ assert_int_equal(rc, SSH_ERROR);
|
|
+ rc = ssh_check_username_syntax("me and -");
|
|
+ assert_int_equal(rc, SSH_ERROR);
|
|
+ rc = ssh_check_username_syntax("los -santos");
|
|
+ assert_int_equal(rc, SSH_ERROR);
|
|
+ rc = ssh_check_username_syntax("- who?");
|
|
+ assert_int_equal(rc, SSH_ERROR);
|
|
+ rc = ssh_check_username_syntax(NULL);
|
|
+ assert_int_equal(rc, SSH_ERROR);
|
|
+ rc = ssh_check_username_syntax("");
|
|
+ assert_int_equal(rc, SSH_ERROR);
|
|
+}
|
|
+
|
|
static void torture_ssh_is_ipaddr(void **state) {
|
|
int rc;
|
|
char *interf = malloc(64);
|
|
@@ -796,6 +829,7 @@ int torture_run_tests(void) {
|
|
cmocka_unit_test(torture_ssh_mkdirs),
|
|
cmocka_unit_test(torture_ssh_quote_file_name),
|
|
cmocka_unit_test(torture_ssh_check_hostname_syntax),
|
|
+ cmocka_unit_test(torture_ssh_check_username_syntax),
|
|
cmocka_unit_test(torture_ssh_is_ipaddr),
|
|
};
|
|
|
|
|
|
From e02b26abd4b34aac065beb1860c54782055334ac Mon Sep 17 00:00:00 2001
|
|
From: Norbert Pocs <norbertpocs0@gmail.com>
|
|
Date: Thu, 28 Dec 2023 12:16:29 +0100
|
|
Subject: [PATCH 2/3] Check any input username for validity
|
|
|
|
Check possible inputs of username for malicious code.
|
|
|
|
Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
|
|
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
|
|
---
|
|
src/config_parser.c | 4 ++++
|
|
src/misc.c | 10 ++++++++--
|
|
src/options.c | 5 +++++
|
|
3 files changed, 17 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/src/config_parser.c b/src/config_parser.c
|
|
index 9e07a0b7..3c43b806 100644
|
|
--- a/src/config_parser.c
|
|
+++ b/src/config_parser.c
|
|
@@ -166,6 +166,10 @@ int ssh_config_parse_uri(const char *tok,
|
|
if (*username == NULL) {
|
|
goto error;
|
|
}
|
|
+ rc = ssh_check_username_syntax(*username);
|
|
+ if (rc != SSH_OK) {
|
|
+ goto error;
|
|
+ }
|
|
}
|
|
tok = endp + 1;
|
|
/* If there is second @ character, this does not look like our URI */
|
|
diff --git a/src/misc.c b/src/misc.c
|
|
index 23fad83d..c1c4dcfa 100644
|
|
--- a/src/misc.c
|
|
+++ b/src/misc.c
|
|
@@ -178,6 +178,7 @@ int gettimeofday(struct timeval *__p, void *__t) {
|
|
char *ssh_get_local_username(void) {
|
|
DWORD size = 0;
|
|
char *user;
|
|
+ int rc;
|
|
|
|
/* get the size */
|
|
GetUserName(NULL, &size);
|
|
@@ -188,7 +189,10 @@ char *ssh_get_local_username(void) {
|
|
}
|
|
|
|
if (GetUserName(user, &size)) {
|
|
- return user;
|
|
+ rc = ssh_check_username_syntax(user);
|
|
+ if (rc == SSH_OK) {
|
|
+ return user;
|
|
+ }
|
|
}
|
|
|
|
return NULL;
|
|
@@ -330,8 +334,10 @@ char *ssh_get_local_username(void)
|
|
}
|
|
|
|
name = strdup(pwd.pw_name);
|
|
+ rc = ssh_check_username_syntax(name);
|
|
|
|
- if (name == NULL) {
|
|
+ if (rc != SSH_OK) {
|
|
+ free(name);
|
|
return NULL;
|
|
}
|
|
|
|
diff --git a/src/options.c b/src/options.c
|
|
index 082c6cf4..f7eaab42 100644
|
|
--- a/src/options.c
|
|
+++ b/src/options.c
|
|
@@ -595,6 +595,11 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
|
|
ssh_set_error_oom(session);
|
|
return -1;
|
|
}
|
|
+ rc = ssh_check_username_syntax(session->opts.username);
|
|
+ if (rc != SSH_OK) {
|
|
+ ssh_set_error_invalid(session);
|
|
+ return -1;
|
|
+ }
|
|
}
|
|
break;
|
|
case SSH_OPTIONS_SSH_DIR:
|
|
|
|
From bf16e4df1809e1fa12aaff2fab6c43b31a108011 Mon Sep 17 00:00:00 2001
|
|
From: Jakub Jelen <jjelen@redhat.com>
|
|
Date: Thu, 2 Apr 2026 15:39:25 +0200
|
|
Subject: [PATCH 3/3] CVE-2026-59846 Block shell metacharacters from usernames
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
When an attacker could sneak the dollar sign or backslash into the username
|
|
expanded for example in proxy command, it can result in printing environment
|
|
variables that might contain secrets.
|
|
|
|
This is a fixup of CVE-2023-6004 which fixed this for hostnames, but these
|
|
two metacharacters were left out from the username filter.
|
|
|
|
This keeps the list in one place to simplify maintenance.
|
|
|
|
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
|
|
Reviewed-by: Pavol Žáčik <pzacik@redhat.com>
|
|
(cherry picked from commit 6309df220e3431deb41946f892f4bb5af8b59dba)
|
|
---
|
|
include/libssh/priv.h | 2 ++
|
|
src/misc.c | 2 +-
|
|
2 files changed, 3 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/include/libssh/priv.h b/include/libssh/priv.h
|
|
index 3e910860..dee941c4 100644
|
|
--- a/include/libssh/priv.h
|
|
+++ b/include/libssh/priv.h
|
|
@@ -218,6 +218,8 @@ int gettimeofday(struct timeval *__p, void *__t);
|
|
# define LIBSSH_MEM_PROTECTION
|
|
#endif
|
|
|
|
+#define SSH_DANGEROUS_SHELL_CHARS "'`\";&<>|(){}$\\,"
|
|
+
|
|
/* forward declarations */
|
|
struct ssh_common_struct;
|
|
struct ssh_kex_struct;
|
|
diff --git a/src/misc.c b/src/misc.c
|
|
index c1c4dcfa..11f799e1 100644
|
|
--- a/src/misc.c
|
|
+++ b/src/misc.c
|
|
@@ -1861,7 +1861,7 @@ int ssh_check_username_syntax(const char *username)
|
|
|
|
username_len = strlen(username);
|
|
if (username_len == 0 || username[username_len - 1] == '\\' ||
|
|
- strpbrk(username, "'`\";&<>|(){}") != NULL) {
|
|
+ strpbrk(username, SSH_DANGEROUS_SHELL_CHARS) != NULL) {
|
|
return SSH_ERROR;
|
|
}
|
|
for (size_t i = 0; i < username_len; i++) {
|