diff -up sudo-1.8.6p7/aclocal.m4.CVE-2014-9680 sudo-1.8.6p7/aclocal.m4 --- sudo-1.8.6p7/aclocal.m4.CVE-2014-9680 2013-02-25 20:42:44.000000000 +0100 +++ sudo-1.8.6p7/aclocal.m4 2015-07-05 13:44:11.610596042 +0200 @@ -156,6 +156,25 @@ AC_DEFUN([SUDO_IO_LOGDIR], [ AC_MSG_RESULT($iolog_dir) ])dnl +dnl Detect time zone file directory, if any. +dnl +AC_DEFUN([SUDO_TZDIR], [AC_MSG_CHECKING(time zone data directory) +tzdir="$with_tzdir" +if test -z "$tzdir"; then + tzdir=no + for d in /usr/share /usr/share/lib /usr/lib /etc; do + if test -d "$d/zoneinfo"; then + tzdir="$d/zoneinfo" + break + fi + done +fi +AC_MSG_RESULT([$tzdir]) +if test "${tzdir}" != "no"; then + SUDO_DEFINE_UNQUOTED(_PATH_ZONEINFO, "$tzdir") +fi +])dnl + dnl dnl check for working fnmatch(3) dnl diff -up sudo-1.8.6p7/configure.in.CVE-2014-9680 sudo-1.8.6p7/configure.in --- sudo-1.8.6p7/configure.in.CVE-2014-9680 2015-07-05 13:44:11.598596222 +0200 +++ sudo-1.8.6p7/configure.in 2015-07-05 13:44:11.610596042 +0200 @@ -776,6 +776,12 @@ AC_ARG_WITH(iologdir, [AS_HELP_STRING([- ;; esac]) +AC_ARG_WITH(tzdir, [AS_HELP_STRING([--with-tzdir=DIR], [path to the time zone data directory])], +[case $with_tzdir in + yes) AC_MSG_ERROR(["must give --with-tzdir an argument."]) + ;; +esac]) + AC_ARG_WITH(sendmail, [AS_HELP_STRING([--with-sendmail], [set path to sendmail]) AS_HELP_STRING([--without-sendmail], [do not send mail at all])], [case $with_sendmail in @@ -3250,6 +3256,7 @@ fi SUDO_LOGFILE SUDO_TIMEDIR SUDO_IO_LOGDIR +SUDO_TZDIR dnl dnl Turn warnings into errors. diff -up sudo-1.8.6p7/doc/sudoers.cat.CVE-2014-9680 sudo-1.8.6p7/doc/sudoers.cat --- sudo-1.8.6p7/doc/sudoers.cat.CVE-2014-9680 2015-07-05 13:44:11.586596402 +0200 +++ sudo-1.8.6p7/doc/sudoers.cat 2015-07-05 13:44:11.610596042 +0200 @@ -1421,20 +1421,36 @@ SSUUDDOOEERRSS OOPPTTIIOONN LLiissttss tthhaatt ccaann bbee uusseedd iinn aa bboooolleeaann ccoonntteexxtt: - env_check Environment variables to be removed from the user's - environment if the variable's value contains `%' or `/' + env_check Environment variables to be removed from the user's + environment if unless they are considered ``safe''. + For all variables except TZ, ``safe'' means that the + variable's value does not contain any `%' or `/' characters. This can be used to guard against printf- style format vulnerabilities in poorly-written - programs. The argument may be a double-quoted, space- - separated list or a single value without double-quotes. - The list can be replaced, added to, deleted from, or - disabled by using the =, +=, -=, and ! operators - respectively. Regardless of whether the env_reset - option is enabled or disabled, variables specified by - env_check will be preserved in the environment if they - pass the aforementioned check. The default list of - environment variables to check is displayed when ssuuddoo - is run by root with the --VV option. + programs. The TZ variable is considerd unsafe if any + of the following are true: + + ++oo It consists of a fully-qualified path name, + optionally prefixed with a colon (`:'), that does + not match the location of the _z_o_n_e_i_n_f_o directory. + + ++oo It contains a _._. path element. + + ++oo It contains white space or non-printable + characters. + + ++oo It is longer than the value of PATH_MAX. + + The argument may be a double-quoted, space-separated + list or a single value without double-quotes. The list + can be replaced, added to, deleted from, or disabled by + using the =, +=, -=, and ! operators respectively. + Regardless of whether the env_reset option is enabled + or disabled, variables specified by env_check will be + preserved in the environment if they pass the + aforementioned check. The default list of environment + variables to check is displayed when ssuuddoo is run by + root with the --VV option. env_delete Environment variables to be removed from the user's environment when the _e_n_v___r_e_s_e_t option is not in effect. diff -up sudo-1.8.6p7/doc/sudoers.man.in.CVE-2014-9680 sudo-1.8.6p7/doc/sudoers.man.in --- sudo-1.8.6p7/doc/sudoers.man.in.CVE-2014-9680 2015-07-05 13:44:11.586596402 +0200 +++ sudo-1.8.6p7/doc/sudoers.man.in 2015-07-05 13:44:11.611596027 +0200 @@ -3002,14 +3002,47 @@ The default value is \fBLists that can be used in a boolean context\fR: .TP 18n env_check -Environment variables to be removed from the user's environment if -the variable's value contains -`%' + Environment variables to be removed from the user's environment if +unless they are considered +\(lqsafe\(rq. +For all variables except +\fRTZ\fR, +\(lqsafe\(rq +means that the variable's value does not contain any +\(oq%\(cq or -`/' +\(oq/\(cq characters. This can be used to guard against printf-style format vulnerabilities in poorly-written programs. +The +\fRTZ\fR +variable is considerd unsafe if any of the following are true: +.PP +.RS 18n +.PD 0 +.TP 4n +\fB\(bu\fR +It consists of a fully-qualified path name, +optionally prefixed with a colon +(\(oq:\&\(cq), +that does not match the location of the +\fIzoneinfo\fR +directory. +.PD +.TP 4n +\fB\(bu\fR +It contains a +\fI..\fR +path element. +.TP 4n +\fB\(bu\fR +It contains white space or non-printable characters. +.TP 4n +\fB\(bu\fR +It is longer than the value of +\fRPATH_MAX\fR. +.PP The argument may be a double-quoted, space-separated list or a single value without double-quotes. The list can be replaced, added to, deleted from, or disabled by using @@ -3031,6 +3064,7 @@ is run by root with the \fB\-V\fR option. +.RE .TP 18n env_delete Environment variables to be removed from the user's environment when the diff -up sudo-1.8.6p7/doc/sudoers.mdoc.in.CVE-2014-9680 sudo-1.8.6p7/doc/sudoers.mdoc.in --- sudo-1.8.6p7/doc/sudoers.mdoc.in.CVE-2014-9680 2015-07-05 13:44:11.586596402 +0200 +++ sudo-1.8.6p7/doc/sudoers.mdoc.in 2015-07-05 13:44:11.611596027 +0200 @@ -2791,13 +2791,40 @@ The default value is .Bl -tag -width 16n .It env_check Environment variables to be removed from the user's environment if -the variable's value contains +unless they are considered +.Dq safe . +For all variables except +.Li TZ , +.Dq safe +means that the variable's value does not contain any .Ql % or .Ql / characters. This can be used to guard against printf-style format vulnerabilities in poorly-written programs. +The +.Li TZ +variable is considerd unsafe if any of the following are true: +.Bl -bullet +.It +It consists of a fully-qualified path name, +optionally prefixed with a colon +.Pq Ql :\& , +that does not match the location of the +.Pa zoneinfo +directory. +.It +It contains a +.Pa .. +path element. +.It +It contains white space or non-printable characters. +.It +It is longer than the value of +.Li PATH_MAX . +.El +.Pp The argument may be a double-quoted, space-separated list or a single value without double-quotes. The list can be replaced, added to, deleted from, or disabled by using diff -up sudo-1.8.6p7/INSTALL.CVE-2014-9680 sudo-1.8.6p7/INSTALL --- sudo-1.8.6p7/INSTALL.CVE-2014-9680 2013-02-25 20:42:43.000000000 +0100 +++ sudo-1.8.6p7/INSTALL 2015-07-05 13:44:11.611596027 +0200 @@ -461,6 +461,16 @@ The following options are also configura Override the default location of the sudo timestamp directory and use "path" instead. + --with-tzdir=DIR + Set the directory to the system's time zone data files. This + is only used when sanitizing the TZ environment variable to + allow for fully-qualified paths in TZ. + By default, configure will look for an existing "zoneinfo" + directory in the following locations: + /usr/share /usr/share/lib /usr/lib /etc + If no zoneinfo directory is found, the TZ variable may not + contain a fully-qualified path. + --with-sendmail=PATH Override configure's guess as to the location of sendmail. diff -up sudo-1.8.6p7/pathnames.h.in.CVE-2014-9680 sudo-1.8.6p7/pathnames.h.in --- sudo-1.8.6p7/pathnames.h.in.CVE-2014-9680 2012-09-18 15:56:28.000000000 +0200 +++ sudo-1.8.6p7/pathnames.h.in 2015-07-05 13:44:11.612596011 +0200 @@ -168,3 +168,7 @@ #ifndef _PATH_NETSVC_CONF #undef _PATH_NETSVC_CONF #endif /* _PATH_NETSVC_CONF */ + +#ifndef _PATH_ZONEINFO +# undef _PATH_ZONEINFO +#endif /* _PATH_ZONEINFO */ diff -up sudo-1.8.6p7/plugins/sudoers/env.c.CVE-2014-9680 sudo-1.8.6p7/plugins/sudoers/env.c --- sudo-1.8.6p7/plugins/sudoers/env.c.CVE-2014-9680 2013-02-25 20:42:44.000000000 +0100 +++ sudo-1.8.6p7/plugins/sudoers/env.c 2015-07-05 13:44:11.612596011 +0200 @@ -198,6 +198,7 @@ static const char *initial_checkenv_tabl "LC_*", "LINGUAS", "TERM", + "TZ", NULL }; @@ -213,7 +214,6 @@ static const char *initial_keepenv_table "PATH", "PS1", "PS2", - "TZ", "XAUTHORITY", "XAUTHORIZATION", NULL @@ -584,6 +584,54 @@ matches_env_delete(const char *var) } /* + * Sanity-check the TZ environment variable. + * On many systems it is possible to set this to a pathname. + */ +static bool +tz_is_sane(const char *tzval) +{ + const char *cp; + char lastch; + debug_decl(tz_is_sane, SUDO_DEBUG_ENV) + + /* tzcode treats a value beginning with a ':' as a path. */ + if (tzval[0] == ':') + tzval++; + + /* Reject fully-qualified TZ that doesn't being with the zoneinfo dir. */ + if (tzval[0] == '/') { +#ifdef _PATH_ZONEINFO + if (strncmp(tzval, _PATH_ZONEINFO, sizeof(_PATH_ZONEINFO) - 1) != 0 || + tzval[sizeof(_PATH_ZONEINFO) - 1] != '/') + debug_return_bool(false); +#else + /* Assume the worst. */ + debug_return_bool(false); +#endif + } + + /* + * Make sure TZ only contains printable non-space characters + * and does not contain a '..' path element. + */ + lastch = '/'; + for (cp = tzval; *cp != '\0'; cp++) { + if (isspace((unsigned char)*cp) || !isprint((unsigned char)*cp)) + debug_return_bool(false); + if (lastch == '/' && cp[0] == '.' && cp[1] == '.' && + (cp[2] == '/' || cp[2] == '\0')) + debug_return_bool(false); + lastch = *cp; + } + + /* Reject extra long TZ values (even if not a path). */ + if ((size_t)(cp - tzval) >= PATH_MAX) + debug_return_bool(false); + + debug_return_bool(true); +} + +/* * Apply the env_check list. * Returns true if the variable is allowed, false if denied * or -1 if no match. @@ -607,8 +655,13 @@ matches_env_check(const char *var) iswild = false; if (strncmp(cur->value, var, len) == 0 && (iswild || var[len] == '=')) { + if (strncmp(var, "TZ=", 3) == 0 ) { + /* Sperial case for TZ */ + keepit = tz_is_sane(var + 3); + } else { keepit = !strpbrk(var, "/%"); - break; + } + break; } } debug_return_bool(keepit);