From fa6c2a8840cbc8d7622e46ce12ba15ecc0fb51b7 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Thu, 23 Jul 2026 10:51:25 -0500 Subject: [PATCH] Fix authorization path handling The username is received from the remote end and thus untrusted. Make sure it doesn't have any characters that can cause it to escape the directory it is supposed to be in when constructing a path. Reported-by: TristanInSec Signed-off-by: Corey Minyard Upstream: https://github.com/cminyard/ser2net/commit/fa6c2a8840cbc8d7622e46ce12ba15ecc0fb51b7 Signed-off-by: Mattia Narducci --- auth.c | 42 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/auth.c b/auth.c index 95c80b4..53c3186 100644 --- a/auth.c +++ b/auth.c @@ -185,6 +185,40 @@ handle_auth_begin(struct gensio *net, const char *authdir, const char *pamauth, return GE_NOTSUP; } +/* + * Construct a secure authorization path. + * + * filename must be at least MAX_PATH. + * + * "username" is untrusted, the rest of the data is trusted. + */ +static bool +construct_auth_path(char *filename, const char *authdir, const char *username, + const char *format, ...) +{ + size_t baselen; + va_list ap; + + /* + * '/', '.', and '\' are all parts of things that can modify the base + * path. Don't allow them in usernames. + */ + if (strchr(username, '.') || strchr(username, '/') + || strchr(username, '\\')) + return false; + + /* Get a good base path ending in / */ + baselen = snprintf(filename, PATH_MAX, "%s/%s/", + authdir, username); + + /* Now append the rest of the path. */ + va_start(ap, format); + vsnprintf(filename + baselen, PATH_MAX - baselen, format, ap); + va_end(ap); + + return true; +} + static int handle_precert(struct gensio *net, const char *authdir) { @@ -228,8 +262,8 @@ handle_precert(struct gensio *net, const char *authdir) } } - snprintf(filename, sizeof(filename), "%s/%s/allowed_certs/", - authdir, s); + if (!construct_auth_path(filename, authdir, s, "allowed_certs/")) + return GE_AUTHREJECT; err = gensio_control(net, 0, false, GENSIO_CONTROL_CERT_AUTH, filename, &len); if (err && err != GE_CERTNOTFOUND) { @@ -258,8 +292,8 @@ handle_password(struct gensio *net, const char *authdir, const char *password) return GE_AUTHREJECT; } - snprintf(filename, sizeof(filename), "%s/%s/password", - authdir, username); + if (!construct_auth_path(filename, authdir, username, "password")) + return GE_AUTHREJECT; pwfile = fopen(filename, "r"); if (!pwfile) { syslog(LOG_ERR, "Can't open password file %s: %s", filename, -- 2.55.0