mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-02-28 07:13:54 +09:00
CVE-2026-0965 config: Do not attempt to read non-regular and too large configuration files
Changes also the reading of known_hosts to use the new helper function Signed-off-by: Jakub Jelen <jjelen@redhat.com> Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
This commit is contained in:
@@ -217,7 +217,7 @@ local_parse_file(ssh_bind bind,
|
||||
return;
|
||||
}
|
||||
|
||||
f = fopen(filename, "r");
|
||||
f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
|
||||
if (f == NULL) {
|
||||
SSH_LOG(SSH_LOG_RARE, "Cannot find file %s to load",
|
||||
filename);
|
||||
@@ -655,7 +655,7 @@ int ssh_bind_config_parse_file(ssh_bind bind, const char *filename)
|
||||
* option to be redefined later by another file. */
|
||||
uint8_t seen[BIND_CFG_MAX] = {0};
|
||||
|
||||
f = fopen(filename, "r");
|
||||
f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
|
||||
if (f == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -256,10 +256,9 @@ local_parse_file(ssh_session session,
|
||||
return;
|
||||
}
|
||||
|
||||
f = fopen(filename, "r");
|
||||
f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
|
||||
if (f == NULL) {
|
||||
SSH_LOG(SSH_LOG_RARE, "Cannot find file %s to load",
|
||||
filename);
|
||||
/* The underlying function logs the reasons */
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1708,8 +1707,9 @@ int ssh_config_parse_file(ssh_session session, const char *filename)
|
||||
int rv;
|
||||
bool global = 0;
|
||||
|
||||
fp = fopen(filename, "r");
|
||||
fp = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
|
||||
if (fp == NULL) {
|
||||
/* The underlying function logs the reasons */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -526,9 +526,9 @@ static int ssh_retrieve_dhgroup(char *moduli_file,
|
||||
}
|
||||
|
||||
if (moduli_file != NULL)
|
||||
moduli = fopen(moduli_file, "r");
|
||||
moduli = ssh_strict_fopen(moduli_file, SSH_MAX_CONFIG_FILE_SIZE);
|
||||
else
|
||||
moduli = fopen(MODULI_FILE, "r");
|
||||
moduli = ssh_strict_fopen(MODULI_FILE, SSH_MAX_CONFIG_FILE_SIZE);
|
||||
|
||||
if (moduli == NULL) {
|
||||
char err_msg[SSH_ERRNO_MSG_MAX] = {0};
|
||||
|
||||
@@ -83,7 +83,7 @@ static struct ssh_tokens_st *ssh_get_knownhost_line(FILE **file,
|
||||
struct ssh_tokens_st *tokens = NULL;
|
||||
|
||||
if (*file == NULL) {
|
||||
*file = fopen(filename,"r");
|
||||
*file = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
|
||||
if (*file == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -243,7 +243,7 @@ static int ssh_known_hosts_read_entries(const char *match,
|
||||
FILE *fp = NULL;
|
||||
int rc;
|
||||
|
||||
fp = fopen(filename, "r");
|
||||
fp = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
|
||||
if (fp == NULL) {
|
||||
char err_msg[SSH_ERRNO_MSG_MAX] = {0};
|
||||
SSH_LOG(SSH_LOG_TRACE, "Failed to open the known_hosts file '%s': %s",
|
||||
|
||||
74
src/misc.c
74
src/misc.c
@@ -37,6 +37,7 @@
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -2416,4 +2417,77 @@ ssh_libssh_proxy_jumps(void)
|
||||
return !(t != NULL && t[0] == '1');
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Safely open a file containing some configuration.
|
||||
*
|
||||
* Runs checks if the file can be used as some configuration file (is regular
|
||||
* file and is not too large). If so, returns the opened file (for reading).
|
||||
* Otherwise logs error and returns `NULL`.
|
||||
*
|
||||
* @param filename The path to the file to open.
|
||||
* @param max_file_size Maximum file size that is accepted.
|
||||
*
|
||||
* @returns the opened file or `NULL` on error.
|
||||
*/
|
||||
FILE *ssh_strict_fopen(const char *filename, size_t max_file_size)
|
||||
{
|
||||
FILE *f = NULL;
|
||||
struct stat sb;
|
||||
char err_msg[SSH_ERRNO_MSG_MAX] = {0};
|
||||
int r, fd;
|
||||
|
||||
/* open first to avoid TOCTOU */
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
SSH_LOG(SSH_LOG_RARE,
|
||||
"Failed to open a file %s for reading: %s",
|
||||
filename,
|
||||
ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Check the file is sensible for a configuration file */
|
||||
r = fstat(fd, &sb);
|
||||
if (r != 0) {
|
||||
SSH_LOG(SSH_LOG_RARE,
|
||||
"Failed to stat %s: %s",
|
||||
filename,
|
||||
ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
if ((sb.st_mode & S_IFMT) != S_IFREG) {
|
||||
SSH_LOG(SSH_LOG_RARE,
|
||||
"The file %s is not a regular file: skipping",
|
||||
filename);
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((size_t)sb.st_size > max_file_size) {
|
||||
SSH_LOG(SSH_LOG_RARE,
|
||||
"The file %s is too large (%jd MB > %zu MB): skipping",
|
||||
filename,
|
||||
(intmax_t)sb.st_size / 1024 / 1024,
|
||||
max_file_size / 1024 / 1024);
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
f = fdopen(fd, "r");
|
||||
if (f == NULL) {
|
||||
SSH_LOG(SSH_LOG_RARE,
|
||||
"Failed to open a file %s for reading: %s",
|
||||
filename,
|
||||
ssh_strerror(r, err_msg, SSH_ERRNO_MSG_MAX));
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* the flcose() will close also the underlying fd */
|
||||
return f;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
@@ -2008,11 +2008,16 @@ int ssh_options_parse_config(ssh_session session, const char *filename)
|
||||
goto out;
|
||||
}
|
||||
if (filename == NULL) {
|
||||
if ((fp = fopen(GLOBAL_CLIENT_CONFIG, "r")) != NULL) {
|
||||
fp = ssh_strict_fopen(GLOBAL_CLIENT_CONFIG, SSH_MAX_CONFIG_FILE_SIZE);
|
||||
if (fp != NULL) {
|
||||
filename = GLOBAL_CLIENT_CONFIG;
|
||||
#ifdef USR_GLOBAL_CLIENT_CONFIG
|
||||
} else if ((fp = fopen(USR_GLOBAL_CLIENT_CONFIG, "r")) != NULL) {
|
||||
filename = USR_GLOBAL_CLIENT_CONFIG;
|
||||
} else {
|
||||
fp = ssh_strict_fopen(USR_GLOBAL_CLIENT_CONFIG,
|
||||
SSH_MAX_CONFIG_FILE_SIZE);
|
||||
if (fp != NULL) {
|
||||
filename = USR_GLOBAL_CLIENT_CONFIG;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user