From: Roy Marples Date: Fri, 26 Sep 2014 20:07:07 +0000 (+0000) Subject: Sanitise the following characters using svis(3) with VIS_CTYLE and VIS_OCTAL: X-Git-Tag: v6.4.6~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4f2199843d8e5937389b7d867669c3a14615a9b5;p=thirdparty%2Fdhcpcd.git Sanitise the following characters using svis(3) with VIS_CTYLE and VIS_OCTAL: | ^ & ; < > ( ) $ ` \ " ' This allows a non buggy unvis(1) to decode it 100% and stays compatible with how dhcpcd used to handle encoding on most platforms. For systems that supply svis(3) there is a code reduction, for systems that do not, a slight code increase. This change mitigates systems affected by bash CVE-2014-6271 and CVE-2014-7169. --- diff --git a/compat/vis.c b/compat/vis.c new file mode 100644 index 00000000..8bdd0baa --- /dev/null +++ b/compat/vis.c @@ -0,0 +1,160 @@ +/* $NetBSD: vis.c,v 1.44 2011/03/12 19:52:48 christos Exp $ */ + +/*- + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/*- + * Copyright (c) 1999, 2005 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * HEAVILY trimmed down for use only in dhcpcd. + * Please use the source in NetBSD for a fuller working copy. + */ + +#include +#include +#include +#include +#include + +#include "vis.h" + +#undef BELL +#define BELL '\a' + +#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7') +#define iswhite(c) (c == ' ' || c == '\t' || c == '\n') + +/* + * This is do_vis, the central code of vis. + * dst: Pointer to the destination buffer + * c: Character to encode + * flag: Flag word + * nextc: The character following 'c' + * extra: Pointer to the list of extra characters to be + * backslash-protected. + */ +char * +svis(char *dst, int c, int flag, int nextc, const char *extra) +{ + int isextra; + + isextra = strchr(extra, c) != NULL; + if (!isextra && isascii(c) && (isgraph(c) || iswhite(c))) { + *dst++ = (char)c; + return dst; + } + if (flag & VIS_CSTYLE) { + switch (c) { + case '\n': + *dst++ = '\\'; *dst++ = 'n'; + return dst; + case '\r': + *dst++ = '\\'; *dst++ = 'r'; + return dst; + case '\b': + *dst++ = '\\'; *dst++ = 'b'; + return dst; + case BELL: + *dst++ = '\\'; *dst++ = 'a'; + return dst; + case '\v': + *dst++ = '\\'; *dst++ = 'v'; + return dst; + case '\t': + *dst++ = '\\'; *dst++ = 't'; + return dst; + case '\f': + *dst++ = '\\'; *dst++ = 'f'; + return dst; + case ' ': + *dst++ = '\\'; *dst++ = 's'; + return dst; + case '\0': + *dst++ = '\\'; *dst++ = '0'; + if (isoctal(nextc)) { + *dst++ = '0'; + *dst++ = '0'; + } + return dst; + case '$': /* vis(1) - l */ + break; + default: + if (isgraph(c)) { + *dst++ = '\\'; *dst++ = (char)c; + return dst; + } + } + } + + *dst++ = '\\'; + if (isextra || ((c & 0177) == ' ') || (flag & VIS_OCTAL)) { + *dst++ = (((unsigned char)c >> 6) & 03) + '0'; + *dst++ = (((unsigned char)c >> 3) & 07) + '0'; + *dst++ = ( (unsigned char)c & 07) + '0'; + } else { + if (c & 0200) { + c &= 0177; *dst++ = 'M'; + } + + if (iscntrl(c)) { + *dst++ = '^'; + if (c == 0177) + *dst++ = '?'; + else + *dst++ = (char)c + '@'; + } else { + *dst++ = '-'; *dst++ = (char)c; + } + } + return dst; +} diff --git a/compat/vis.h b/compat/vis.h new file mode 100644 index 00000000..25c55b52 --- /dev/null +++ b/compat/vis.h @@ -0,0 +1,9 @@ +#ifndef VIS_H +#define VIS_H + +#define VIS_OCTAL 0x0001 /* use octal \ddd format */ +#define VIS_CSTYLE 0x0002 /* use \[nrft0..] where appropiate */ + +char *svis(char *dst, int c, int flag, int nextc, const char *meta); + +#endif diff --git a/configure b/configure index 294f49a0..b169337d 100755 --- a/configure +++ b/configure @@ -71,6 +71,7 @@ for x do --without-md5) MD5=no;; --without-sha2) SHA2=no;; --without-sha256) SHA2=no;; + --without-vis) VIS=no;; --without-dev) DEV=no;; --without-udev) UDEV=no;; --serviceexists) SERVICEEXISTS=$var;; @@ -627,6 +628,31 @@ if [ "$STRLCPY" = no ]; then echo "#include \"compat/strlcpy.h\"" >>$CONFIG_H fi +if [ -z "$VIS" ]; then + printf "Testing for vis ... " + cat <_vis.c +#include +int main(void) { + char s[10]; + svis(s, 1, 2, 3, s); + return 0; +} +EOF + if $XCC _vis.c -o _vis 2>&3; then + VIS=yes + else + VIS=no + fi + echo "$VIS" + rm -f _svis.c _svis +fi +if [ "$VIS" = no ]; then + echo "COMPAT_SRCS+= compat/vis.c" >>$CONFIG_MK + echo "#include \"compat/vis.h\"" >>$CONFIG_H +else + echo "#define HAVE_VIS_H" >>$CONFIG_H +fi + if [ -z "$DPRINTF" ]; then printf "Testing for dprintf ... " cat <_dprintf.c diff --git a/dhcp-common.c b/dhcp-common.c index 09354064..1e0d1003 100644 --- a/dhcp-common.c +++ b/dhcp-common.c @@ -36,6 +36,11 @@ #include #include "config.h" + +#ifdef HAVE_VIS_H +#include +#endif + #include "common.h" #include "dhcp-common.h" #include "dhcp.h" @@ -291,14 +296,28 @@ decode_rfc3397(char *out, size_t len, const uint8_t *p, size_t pl) return (ssize_t)count; } +/* + * Escape these characters to avoid any nastiness passing to a POSIX shell. + * See IEEE Std 1003.1, 2004 Shell Command Language, 2.2 Quoting + * space is not escaped. + */ +#define ESCAPE_CHARS "|&;<>()$`\\\"'\t\n" + +/* + * Prints a chunk of data to a string. + * Escapes some characters defnined above to try and avoid any loopholes + * in the shell we're passing to. + * Any non visible characters are escaped as an octal number. + */ ssize_t print_string(char *s, size_t len, const uint8_t *data, size_t dl) { uint8_t c; const uint8_t *e, *p; - ssize_t bytes = 0; - ssize_t r; + size_t bytes; + char v[5], *vp, *ve; + bytes = 0; e = data + dl; while (data < e) { c = *data++; @@ -310,51 +329,25 @@ print_string(char *s, size_t len, const uint8_t *data, size_t dl) if (p == e) break; } - if (!isascii(c) || !isprint(c)) { - if (s) { - if (len < 5) { - errno = ENOBUFS; - return -1; - } - r = snprintf(s, len, "\\%03o", c); - len -= (size_t)r; - bytes += r; - s += r; - } else - bytes += 4; - continue; - } - switch (c) { - case '"': /* FALLTHROUGH */ - case '\'': /* FALLTHROUGH */ - case '$': /* FALLTHROUGH */ - case '`': /* FALLTHROUGH */ - case '\\': /* FALLTHROUGH */ - case '|': /* FALLTHROUGH */ - case '&': - if (s) { - if (len < 3) { - errno = ENOBUFS; - return -1; - } - *s++ = '\\'; - len--; - } - bytes++; - break; + ve = svis(v, c, VIS_CSTYLE | VIS_OCTAL, + data <= e ? *data : 0, ESCAPE_CHARS); + if (len < (size_t)(ve - v) + 1) { + errno = ENOBUFS; + return -1; } + bytes += (size_t)(ve - v); if (s) { - *s++ = (char)c; - len--; + vp = v; + while (vp != ve) + *s++ = *vp++; } - bytes++; } /* NULL */ if (s) *s = '\0'; bytes++; - return bytes; + return (ssize_t)bytes; } #define ADDRSZ 4 diff --git a/dhcpcd.8.in b/dhcpcd.8.in index 7a155ff1..215c73e4 100644 --- a/dhcpcd.8.in +++ b/dhcpcd.8.in @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd September 15, 2014 +.Dd September 26, 2014 .Dt DHCPCD 8 .Os .Sh NAME @@ -203,6 +203,17 @@ See for details on how these scripts work. .Nm currently ignores the exit code of the script. +.Pp +.Nm +sanitises each variable passed from the DHCP/RA message by encoding non +printable characters in escaped octal and escaping the following characters: +.D1 | \*[Am] \&; \*[Lt] \*[Gt] \&( \&) $ ` \e \*q ' \ +\*[Lt]tab\*[Gt] \*[Lt]newline\*[Gt] +.Pp +It is possible to reverse this encoding by passing the variable to +.Xr unvis 1 , +like so: +.D1 printf \*q%s\*q \*qvariable_name\*q | unvis .Ss Fine tuning You can fine-tune the behaviour of .Nm @@ -631,6 +642,23 @@ to rebind, reconfigure or exit need to include the same restrictive flags so that .Nm knows which process to signal. +.Pp +.Nm +sanitises variables using the +.Xr svis 3 +function with the +.Dv VIS_CTYPE +and +.Dv VIS_OCTAL +flags which your libc may provide, +or it's own compatible one if not. +Some +.Xr unvis 1 +implementations may not decode either correctly, depending on how they +handle VIS_CTYPE in both +.Xr vis 3 +and +.Xr unvis 3 . .Sh FILES .Bl -ohang .It Pa @SYSCONFDIR@/dhcpcd.conf