Synopsis: dhclient vulnerability
NetBSD versions: NetBSD 1.4, 1.4.1, and 1.4.2
Thanks to: Todd Fries, Itojun, Ted Lemon
Reported in NetBSD Security Advisory: SA2000-008

--- usr.sbin/dhcp/common/options.c.orig 1999/03/30 03:10:46     1.1.1.9
+++ usr.sbin/dhcp/common/options.c      2000/06/28 18:47:02     1.1.1.9.2.1
@@ -47,6 +47,7 @@

#define DHCP_OPTION_DATA
#include "dhcpd.h"
+#include <ctype.h>

/* Parse all available options out of the specified packet. */

@@ -439,7 +440,7 @@
       int numhunk = -1;
       int numelem = 0;
       char fmtbuf [32];
-       int i, j;
+       int i, j, k;
       char *op = optbuf;
       unsigned char *dp = data;
       struct in_addr foo;
@@ -471,11 +472,21 @@
                       numhunk = 0;
                       break;
                     case 'X':
-                       fmtbuf [i] = 'x';
+                       for (k = 0; k < len; k++) {
+                               if (!isascii (data [k]) ||
+                                   !isprint (data [k]))
+                                       break;
+                       }
+                       if (k == len) {
+                               fmtbuf [i] = 't';
+                               numhunk = -2;
+                       } else {
+                               fmtbuf [i] = 'x';
+                               hunksize++;
+                               comma = ':';
+                               numhunk = 0;
+                       }
                       fmtbuf [i + 1] = 0;
-                       hunksize++;
-                       numhunk = 0;
-                       comma = ':';
                       break;
                     case 't':
                       fmtbuf [i] = 't';
@@ -539,8 +550,22 @@
                             case 't':
                               if (emit_quotes)
                                       *op++ = '"';
-                               strcpy (op, (char *)dp);
-                               op += strlen ((char *)dp);
+                               for (; dp < data + len; dp++) {
+                                       if (!isascii (*dp) ||
+                                           !isprint (*dp)) {
+                                               sprintf (op, "\\%03o",
+                                                        *dp);
+                                               op += 4;
+                                       } else if (*dp == '"' ||
+                                                  *dp == '\'' ||
+                                                  *dp == '$' ||
+                                                  *dp == '`' ||
+                                                  *dp == '\\') {
+                                               *op++ = '\\';
+                                               *op++ = *dp;
+                                       } else
+                                               *op++ = *dp;
+                               }
                               if (emit_quotes)
                                       *op++ = '"';
                               *op = 0;