1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380
|
Description: CVE-2014-9680: unsafe handling of TZ environment variable
The TZ environment variable was passed through unchecked. Most libc
tzset() implementations support passing an absolute pathname in the time
zone to point to an arbitrary, user-controlled file. This may be used
to exploit bugs in the C library's TZ parser or open files the user
would not otherwise have access to. Arbitrary file access via TZ could
also be used in a denial of service attack by reading from a file or
fifo that will block.
Origin: backport, http://www.sudo.ws/repos/sudo/rev/650ac6938b59,
http://www.sudo.ws/repos/sudo/rev/ac1467f71ac0
Bug-Debian: https://bugs.debian.org/772707
Forwarded: not-needed
Author: Todd C. Miller <Todd.Miller@courtesan.com>
Author: Salvatore Bonaccorso <carnil@debian.org>
Last-Update: 2015-02-18
Applied-Upstream: 1.8.12
--- a/configure
+++ b/configure
@@ -882,6 +882,7 @@ with_timedir
with_rundir
with_vardir
with_iologdir
+with_tzdir
with_sendmail
with_sudoers_mode
with_sudoers_uid
@@ -1670,6 +1671,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)
@@ -4773,6 +4775,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
@@ -21483,6 +21495,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
--- a/configure.ac
+++ b/configure.ac
@@ -816,6 +816,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
@@ -3446,6 +3452,7 @@ SUDO_LOGFILE
SUDO_RUNDIR
SUDO_VARDIR
SUDO_IO_LOGDIR
+SUDO_TZDIR
dnl
dnl Turn warnings into errors.
--- a/doc/sudoers.cat
+++ b/doc/sudoers.cat
@@ -1628,19 +1628,35 @@ 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 `/'
+ environment 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 considered unsafe if any
+ of the following are true:
+
+ ++oo It consists of a fully-qualified path name 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.
--- a/doc/sudoers.man.in
+++ b/doc/sudoers.man.in
@@ -3336,14 +3336,45 @@ 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
+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 considered 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
@@ -3365,6 +3396,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
--- a/doc/sudoers.mdoc.in
+++ b/doc/sudoers.mdoc.in
@@ -3095,14 +3095,39 @@ The default value is
.Sy Lists that can be used in a boolean context :
.Bl -tag -width 16n
.It 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
+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 considered 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
--- a/m4/sudo.m4
+++ b/m4/sudo.m4
@@ -119,6 +119,26 @@ 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
AC_DEFUN([SUDO_RUNDIR], [AC_MSG_CHECKING(for sudo run dir location)
--- a/pathnames.h.in
+++ b/pathnames.h.in
@@ -178,3 +178,7 @@
#ifndef _PATH_NETSVC_CONF
#undef _PATH_NETSVC_CONF
#endif /* _PATH_NETSVC_CONF */
+
+#ifndef _PATH_ZONEINFO
+# undef _PATH_ZONEINFO
+#endif /* _PATH_ZONEINFO */
--- a/plugins/sudoers/env.c
+++ b/plugins/sudoers/env.c
@@ -197,6 +197,7 @@ static const char *initial_checkenv_tabl
"LC_*",
"LINGUAS",
"TERM",
+ "TZ",
NULL
};
@@ -212,7 +213,6 @@ static const char *initial_keepenv_table
"PATH",
"PS1",
"PS2",
- "TZ",
"XAUTHORITY",
"XAUTHORIZATION",
NULL
@@ -576,6 +576,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.
@@ -599,7 +647,12 @@ matches_env_check(const char *var)
iswild = false;
if (strncmp(cur->value, var, len) == 0 &&
(iswild || var[len] == '=')) {
- keepit = !strpbrk(var, "/%");
+ if (strncmp(var, "TZ=", 3) == 0) {
+ /* Special case for TZ */
+ keepit = tz_is_sane(var + 3);
+ } else {
+ keepit = !strpbrk(var, "/%");
+ }
break;
}
}
|