oss-sec mailing list archives
Re: Telnetd Vulnerability Report
From: Justin Swartz <justin.swartz () risingedge co za>
Date: Sun, 8 Mar 2026 09:34:22 +0200
On Sun, 08 Mar 2026 06:05:45 +0200, Justin Swartz wrote:
I'll submit a third version of this patch set later.
Based on the feedback provided, the third version of the patch set [1]: - Leaves the inherited environment intact. - Implements a default whitelist and whitelisted variable value sanitization. - Places the strings of the allowed environment variables array into the .rodata section. - Eliminates duplicated setenv/unsetenv logic in "telnetd/state.c". - Discards the --accept-env feature [3], as an inetutils maintainer [2] is working on an implementation to extend the allowed environment using Gnulib instead. Find the patch included below. Regards, Justin --- [1] https://lists.gnu.org/archive/html/bug-inetutils/2026-03/msg00020.html [2] https://lists.gnu.org/archive/html/bug-inetutils/2026-03/msg00017.html [3] https://lists.gnu.org/archive/html/bug-inetutils/2026-03/msg00018.html
From 1b9dc91cfd3c730317aa3bb6ec58ff1beb5dcc15 Mon Sep 17 00:00:00 2001
From: Justin Swartz <justin.swartz () risingedge co za> Date: Sun, 8 Mar 2026 06:55:23 +0200 Subject: [PATCH v3 1/1] telnetd: replace environment blacklist with a whitelist. The previous method of scrubbing environment variables, scrub_env(), and targeted calls to unsetenv() were insufficient to protect against glibc-based injection attacks, such as the recently reported CVE-1999-0073 regression. To fix this issue, the approach suggested by Simon Josefsson in <https://lists.gnu.org/archive/html/bug-inetutils/2026-02/msg00002.html> has been taken to replace the reactive blacklist with a fairly strict default whitelist of the following allowed environment variables: USER LOGNAME TERM LANG LC_* And as suggested by Solar Designer, all whitelisted variables will be subject to sanitization, and the inherited environment will be left intact. Any negotiated variable will be dropped if its value contains a path separator ('/'), or an explicit reference to the current working directory (".") or its parent (".."). * telnetd/utility.c (allowed_env_vars): New whitelist array. (is_env_var_allowed): New function. (set_env_var_if_allowed): New helper function. (getterminaltype): Apply final whitelist validation to terminaltype. (terminaltypeok): Validate terminal type against the whitelist. * telnetd/state.c (suboption): Filter NEW_ENVIRON during parsing using set_env_var_if_allowed(). * telnetd/pty.c (start_login): Remove the obsolete scrubbing logic. * telnetd/telnetd.h: Add prototypes for new functions. --- telnetd/pty.c | 32 ------------------ telnetd/state.c | 10 ++---- telnetd/telnetd.h | 3 ++ telnetd/utility.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 88 insertions(+), 40 deletions(-) diff --git a/telnetd/pty.c b/telnetd/pty.c index f3518049..4bf407ad 100644 --- a/telnetd/pty.c +++ b/telnetd/pty.c @@ -83,29 +83,6 @@ startslave (char *host, int autologin, char *autoname) return master; } -/* - * scrub_env() - * - * Remove a few things from the environment that - * don't need to be there. - * - * Security fix included in telnet-95.10.23.NE of David Borman <deb () cray com>. - */ -static void -scrub_env (void) -{ - char **cpp, **cpp2; - - for (cpp2 = cpp = environ; *cpp; cpp++) - { - if (strncmp (*cpp, "LD_", 3) - && strncmp (*cpp, "_RLD_", 5) - && strncmp (*cpp, "LIBPATH=", 8) && strncmp (*cpp, "IFS=", 4)) - *cpp2++ = *cpp; - } - *cpp2 = 0; -} - void start_login (char *host, int autologin, char *name) { @@ -117,8 +94,6 @@ start_login (char *host, int autologin, char *name) (void) autologin; (void) name; - scrub_env (); - /* Set the environment variable "LINEMODE" to indicate our linemode */ if (lmodetype == REAL_LINEMODE) setenv ("LINEMODE", "real", 1); @@ -130,13 +105,6 @@ start_login (char *host, int autologin, char *name) fatal (net, "can't expand login command line"); argcv_get (cmd, "", &argc, &argv); - /* util-linux's "login" introduced an authentication bypass method - * via environment variable "CREDENTIALS_DIRECTORY" in version 2.40. - * Clear it from the environment before executing "login" to prevent - * abuse via Telnet. - */ - unsetenv ("CREDENTIALS_DIRECTORY"); - execv (argv[0], argv); syslog (LOG_ERR, "%s: %m\n", cmd); fatalperror (net, cmd); diff --git a/telnetd/state.c b/telnetd/state.c index a9a51e00..ab6bfb11 100644 --- a/telnetd/state.c +++ b/telnetd/state.c @@ -1495,10 +1495,7 @@ suboption (void) case NEW_ENV_VAR: case ENV_USERVAR: *cp = '\0'; - if (valp) - setenv (varp, valp, 1); - else - unsetenv (varp); + set_env_var_if_allowed (varp, valp); cp = varp = (char *) subpointer; valp = 0; break; @@ -1514,10 +1511,7 @@ suboption (void) } } *cp = '\0'; - if (valp) - setenv (varp, valp, 1); - else - unsetenv (varp); + set_env_var_if_allowed (varp, valp); break; } /* end of case TELOPT_NEW_ENVIRON */ #if defined AUTHENTICATION diff --git a/telnetd/telnetd.h b/telnetd/telnetd.h index df31a819..8b14d9dd 100644 --- a/telnetd/telnetd.h +++ b/telnetd/telnetd.h @@ -316,6 +316,9 @@ extern void tty_setsofttab (int); extern void tty_tspeed (int); extern char *expand_line (const char *fmt); +extern int is_env_var_allowed (const char *var, const char *val); +extern void set_env_var_if_allowed (const char *var, const char *val); + /* FIXME */ extern void _termstat (void); diff --git a/telnetd/utility.c b/telnetd/utility.c index 2fe6730c..085065ea 100644 --- a/telnetd/utility.c +++ b/telnetd/utility.c @@ -17,6 +17,16 @@ along with this program. If not, see `http://www.gnu.org/licenses/'. */ #include <config.h> +#include <fnmatch.h> +#include <string.h> + +#ifdef HAVE_PATHS_H +# include <paths.h> +#else +# ifndef _PATH_DEFPATH +# define _PATH_DEFPATH "/usr/bin:/bin" +# endif +#endif #define TELOPTS #define TELCMDS @@ -65,6 +75,66 @@ static int pcc; extern int not42; +/* A default whitelist for environment variables. */ +static const char * const allowed_env_vars[] = { + "USER", + "LOGNAME", + "TERM", + "LANG", + "LC_*", + NULL +}; + +int +is_env_var_allowed (const char *var, const char *val) +{ + const char * const *p; + int allowed = 0; + + for (p = allowed_env_vars; *p; p++) + { + if (fnmatch (*p, var, FNM_NOESCAPE) == 0) + { + allowed = 1; + break; + } + } + + if (!allowed) + return 0; + + if (val != NULL) + { + if (strchr (val, '/') != NULL) + return 0; + + if (strcmp (val, "..") == 0) + return 0; + + if (strcmp (val, ".") == 0) + return 0; + } + + return 1; +} + +void +set_env_var_if_allowed (const char *var, const char *val) +{ + if (is_env_var_allowed (var, val)) + { + if (val) + { + if (*val != 0) + setenv (var, val, 1); + } + else + { + unsetenv (var); + } + } +} + static int readstream (int p, char *ibuf, int bufsize) { @@ -863,6 +933,16 @@ getterminaltype (char *uname, size_t len) } free (first); free (last); + + /* Does TERM appear to be illogical? */ + if (terminaltype) + { + if (!is_env_var_allowed ("TERM", terminaltype)) + { + free (terminaltype); + terminaltype = NULL; + } + } } return retval; } @@ -876,6 +956,9 @@ getterminaltype (char *uname, size_t len) int terminaltypeok (char *s) { + if (!is_env_var_allowed ("TERM", s)) + return 0; + #ifdef HAVE_TGETENT char buf[2048]; --
Current thread:
- Re: Telnetd Vulnerability Report Justin Swartz (Feb 23)
- Re: Telnetd Vulnerability Report Solar Designer (Feb 23)
- Re: Telnetd Vulnerability Report Solar Designer (Feb 23)
- Re: Telnetd Vulnerability Report Justin Swartz (Mar 07)
- Re: Telnetd Vulnerability Report Solar Designer (Mar 07)
- Re: Telnetd Vulnerability Report Justin Swartz (Mar 07)
- Re: Telnetd Vulnerability Report Justin Swartz (Mar 07)
- Re: Telnetd Vulnerability Report Solar Designer (Mar 08)
- Re: Telnetd Vulnerability Report Justin Swartz (Mar 08)
- Re: Telnetd Vulnerability Report Solar Designer (Mar 08)
- Re: Telnetd Vulnerability Report Solar Designer (Feb 23)
- Re: Telnetd Vulnerability Report Solar Designer (Feb 23)
- Re: Re: Telnetd Vulnerability Report Pat Gunn (Mar 07)
- CVE-2026-28372: Telnetd Vulnerability Report Guillem Jover (Feb 27)
- Re: CVE-2026-28372: Telnetd Vulnerability Report Solar Designer (Mar 06)
- Re: CVE-2026-28372: Telnetd Vulnerability Report Guillem Jover (Mar 06)
- Re: CVE-2026-28372: Telnetd Vulnerability Report Salvatore Bonaccorso (Mar 07)
- Re: CVE-2026-28372: Telnetd Vulnerability Report Guillem Jover (Mar 07)
