]> granicus.if.org Git - sudo/commitdiff
Sanity check the TZ environment variable by special casing it in
authorTodd C. Miller <Todd.Miller@courtesan.com>
Fri, 6 Feb 2015 18:01:05 +0000 (11:01 -0700)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Fri, 6 Feb 2015 18:01:05 +0000 (11:01 -0700)
env_check.  The --with-tzdir configure option can be used to
specify the zoneinfo directory if configure doesn't find it.

INSTALL
NEWS
configure
configure.ac
doc/sudoers.cat
doc/sudoers.man.in
doc/sudoers.mdoc.in
m4/sudo.m4
pathnames.h.in
plugins/sudoers/env.c

diff --git a/INSTALL b/INSTALL
index e19b08e1fabd2e85b80f63306b1de6063e17fb0b..a13fdd504b96c25d6695ac8c3b27f96b984c299e 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -145,6 +145,16 @@ Directory and file names:
            /var/db, /var/lib, /var/adm, /usr/adm
        This directory should not be cleared when the system boots.
 
+  --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.
+
 Compilation options:
   --disable-hardening
        Disable the use of compiler/linker exploit mitigation options
diff --git a/NEWS b/NEWS
index 2e74a9533c4faf4429a336550a81de0232bd8b28..19633a83518c8c731afea442b51e0af62c5c7176 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -69,6 +69,9 @@ What's new in Sudo 1.8.12
  * Fixed two potential crashes when sudo is run with very low
    resource limits.
 
+ * The TZ environment variable is now checked for safety instead
+   of simply being copied to the environment of the command.
+
 What's new in Sudo 1.8.11p2
 
  * Fixed a bug where dynamic shared objects loaded from a plugin
index 5ac327f818afdc0a98c6c03697292ad2b2549c7e..d3666f6676a91b507e2d55e730b098540eb2f8f4 100755 (executable)
--- a/configure
+++ b/configure
@@ -889,6 +889,7 @@ with_timedir
 with_rundir
 with_vardir
 with_iologdir
+with_tzdir
 with_sendmail
 with_sudoers_mode
 with_sudoers_uid
@@ -1686,6 +1687,7 @@ Optional Packages:
   --with-rundir=DIR       path to the sudo time stamp parent dir
   --with-vardir=DIR       path to the sudo var dir
   --with-iologdir=DIR     directory to store sudo I/O log files in
+  --with-tzdir=DIR        path to the time zone data directory
   --with-sendmail         set path to sendmail
   --without-sendmail      do not send mail at all
   --with-sudoers-mode     mode of sudoers file (defaults to 0440)
@@ -4828,6 +4830,16 @@ fi
 
 
 
+# Check whether --with-tzdir was given.
+if test "${with_tzdir+set}" = set; then :
+  withval=$with_tzdir; case $with_tzdir in
+    yes)       as_fn_error $? "\"must give --with-tzdir an argument.\"" "$LINENO" 5
+               ;;
+esac
+fi
+
+
+
 # Check whether --with-sendmail was given.
 if test "${with_sendmail+set}" = set; then :
   withval=$with_sendmail; case $with_sendmail in
@@ -23367,6 +23379,27 @@ EOF
     { $as_echo "$as_me:${as_lineno-$LINENO}: result: $iolog_dir" >&5
 $as_echo "$iolog_dir" >&6; }
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking time zone data directory" >&5
+$as_echo_n "checking time zone data directory... " >&6; }
+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
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $tzdir" >&5
+$as_echo "$tzdir" >&6; }
+if test "${tzdir}" != "no"; then
+    cat >>confdefs.h <<EOF
+#define _PATH_ZONEINFO "$tzdir"
+EOF
+
+fi
+
 
 
 ac_c_werror_flag=yes
index 6dd791564f5dec4cb9139d1b4fe2e2c516b7b183..48e263b27c3526a606929fed634264d7c8f1364f 100644 (file)
@@ -828,6 +828,12 @@ AC_ARG_WITH(iologdir, [AS_HELP_STRING([--with-iologdir=DIR], [directory to store
            ;;
 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
@@ -3757,6 +3763,7 @@ SUDO_LOGFILE
 SUDO_RUNDIR
 SUDO_VARDIR
 SUDO_IO_LOGDIR
+SUDO_TZDIR
 
 dnl
 dnl Turn warnings into errors.
index 8261801a3665f71727250f338d90ec44b1571e05..6021e6f55d57f541cff52771a28626d1d8d00911 100644 (file)
@@ -1662,19 +1662,35 @@ S\bSU\bUD\bDO\bOE\bER\bRS\bS O\bOP\bPT\bTI\bIO\bON\bNS\bS
      L\bLi\bis\bst\bts\bs t\bth\bha\bat\bt c\bca\ban\bn b\bbe\be u\bus\bse\bed\bd i\bin\bn a\ba b\bbo\boo\bol\ble\bea\ban\bn c\bco\bon\bnt\bte\bex\bxt\bt:
 
      env_check         Environment variables to be removed from the user's
-                       environment if the variable's value contains `%' or `/'
+                       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 s\bsu\bud\bdo\bo
-                       is run by root with the -\b-V\bV option.
+                       programs.  The TZ variable is considerd unsafe if any
+                       of the following are true:
+
+                       +\b+\bo\bo   It consists of a fully-qualified path name that
+                           does not match the location of the _\bz_\bo_\bn_\be_\bi_\bn_\bf_\bo
+                           directory.
+
+                       +\b+\bo\bo   It contains a _\b._\b. path element.
+
+                       +\b+\bo\bo   It contains white space or non-printable
+                           characters.
+
+                       +\b+\bo\bo   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 s\bsu\bud\bdo\bo is run by
+                       root with the -\b-V\bV option.
 
      env_delete        Environment variables to be removed from the user's
                        environment when the _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt option is not in effect.
@@ -2363,4 +2379,4 @@ D\bDI\bIS\bSC\bCL\bLA\bAI\bIM\bME\bER\bR
      file distributed with s\bsu\bud\bdo\bo or http://www.sudo.ws/license.html for
      complete details.
 
-Sudo 1.8.12                    January 21, 2015                    Sudo 1.8.12
+Sudo 1.8.12                    February 6, 2015                    Sudo 1.8.12
index dca9897a109d221d9ae543a3619097d968728dd8..8f0b39b90546a12840cbbac561fdbde4152ce01f 100644 (file)
@@ -21,7 +21,7 @@
 .\" Agency (DARPA) and Air Force Research Laboratory, Air Force
 .\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
 .\"
-.TH "SUDOERS" "5" "January 21, 2015" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
+.TH "SUDOERS" "5" "February 6, 2015" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
 .nh
 .if n .ad l
 .SH "NAME"
@@ -3415,13 +3415,44 @@ The default value is
 .TP 18n
 env_check
 Environment variables to be removed from the user's environment if
-the variable's value contains
+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 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
@@ -3443,6 +3474,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
index 41b74c2dccc5c0c1278b34ce6a66df30594c9468..ad16019458b4eabe9d888d3476a284d0815f14ac 100644 (file)
@@ -19,7 +19,7 @@
 .\" Agency (DARPA) and Air Force Research Laboratory, Air Force
 .\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
 .\"
-.Dd January 21, 2015
+.Dd February 6, 2015
 .Dt SUDOERS @mansectform@
 .Os Sudo @PACKAGE_VERSION@
 .Sh NAME
@@ -3171,13 +3171,38 @@ 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 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
index 9087155fac91ef60d86badea2fbe43ab0060ae62..3111b7225c4f8acd2242710e94587e691282950f 100644 (file)
@@ -1,6 +1,6 @@
 dnl Local m4 macros for autoconf (used by sudo)
 dnl
-dnl Copyright (c) 1994-1996, 1998-2005, 2007-2014
+dnl Copyright (c) 1994-1996, 1998-2005, 2007-2015
 dnl    Todd C. Miller <Todd.Miller@courtesan.com>
 dnl
 dnl XXX - should cache values in all cases!!!
@@ -82,6 +82,26 @@ else
 fi
 ])dnl
 
+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 Parent directory for time stamp dir.
 dnl
index e831eee65a33b37e68158fda04a238bfa9248dbe..003f4f40ad7d15acfa83cde375147a102a613db1 100644 (file)
 # undef        _PATH_NETSVC_CONF
 #endif /* _PATH_NETSVC_CONF */
 
+#ifndef _PATH_ZONEINFO
+# undef        _PATH_ZONEINFO
+#endif /* _PATH_ZONEINFO */
+
 /* On AIX, _PATH_BSHELL in paths.h is /usr/bin/bsh but we want /usr/bin/sh */
 #ifndef _PATH_SUDO_BSHELL
 # if defined(_AIX) && defined(HAVE_PATHS_H)
index 00046143588f7d382bf5fcc64be4700ac4ccff84..d2f844f3e7848d16974100fc9b26ebb7eeaf42ea 100644 (file)
@@ -187,6 +187,7 @@ static const char *initial_checkenv_table[] = {
     "LC_*",
     "LINGUAS",
     "TERM",
+    "TZ",
     NULL
 };
 
@@ -202,7 +203,6 @@ static const char *initial_keepenv_table[] = {
     "PATH",
     "PS1",
     "PS2",
-    "TZ",
     "XAUTHORITY",
     "XAUTHORIZATION",
     NULL
@@ -587,6 +587,54 @@ matches_env_delete(const char *var)
     debug_return_bool(matches_env_list(var, &def_env_delete, &full_match));
 }
 
+/*
+ * 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, SUDOERS_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
@@ -600,9 +648,14 @@ matches_env_check(const char *var, bool *full_match)
 
     /* Skip anything listed in env_check that includes '/' or '%'. */
     if (matches_env_list(var, &def_env_check, full_match)) {
-       const char *val = strchr(var, '=');
-       if (val != NULL)
-           keepit = !strpbrk(++val, "/%");
+       if (strncmp(var, "TZ=", 3) == 0) {
+           /* Special case for TZ */
+           keepit = tz_is_sane(var + 3);
+       } else {
+           const char *val = strchr(var, '=');
+           if (val != NULL)
+               keepit = !strpbrk(++val, "/%");
+       }
     }
     debug_return_bool(keepit);
 }