Module Name:src
Committed By: riz
Date: Thu Apr 7 17:33:17 UTC 2011
Modified Files:
src/dist/dhcp/client [netbsd-4-0]: dhclient.c
Log Message:
Pull up following revision(s) (requested by christos in ticket #1427):
dist/dhcp/client/dhclient.c: revision 1.21
CVE-2011-0997 dhclient: insufficient sanitization of certain DHCP
response values. Apply patch by hand from the 3.1-ESV-R1 release.
To generate a diff of this commit:
cvs rdiff -u -r1.18.12.1 -r1.18.12.2 src/dist/dhcp/client/dhclient.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/dist/dhcp/client/dhclient.c
diff -u src/dist/dhcp/client/dhclient.c:1.18.12.1 src/dist/dhcp/client/dhclient.c:1.18.12.2
--- src/dist/dhcp/client/dhclient.c:1.18.12.1 Tue Jul 14 19:57:00 2009
+++ src/dist/dhcp/client/dhclient.c Thu Apr 7 17:33:17 2011
@@ -32,7 +32,7 @@
#ifndef lint
static char ocopyright[] =
-"$Id: dhclient.c,v 1.18.12.1 2009/07/14 19:57:00 snj Exp $ Copyright (c) 2004-2005 Internet Systems Consortium. All rights reserved.\n";
+"$Id: dhclient.c,v 1.18.12.2 2011/04/07 17:33:17 riz Exp $ Copyright (c) 2004-2005 Internet Systems Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
@@ -79,6 +79,11 @@
static void usage PROTO ((void));
static void limit_interval PROTO((struct client_state *));
+static int check_domain_name(const char *ptr, size_t len, int dots);
+static int check_domain_name_list(const char *ptr, size_t len, int dots);
+static int check_option_values(struct universe *universe, unsigned int opt,
+ const char *ptr, size_t len);
+
void do_release(struct client_state *);
#if !defined (SMALL)
@@ -2476,12 +2481,23 @@
char name [256];
if (dhcp_option_ev_name (name, sizeof name,
oc -> option)) {
-client_envadd (es -> client, es -> prefix,
- name, "%s",
- (pretty_print_option
- (oc -> option,
- data.data, data.len,
- 0, 0)));
+const char *value;
+value = pretty_print_option(oc->option,
+ data.data,
+ data.len, 0, 0);
+size_t length = strlen(value);
+
+if (check_option_values(oc->option->universe,
+ oc->option->code,
+ value, length) == 0) {
+ client_envadd(es->client, es->prefix,
+ name, "%s", value);
+} else {
+ log_error("suspect value in %s "
+ "option - discarded",
+ name);
+}
+
data_string_forget (&data, MDL);
}
}
@@ -2554,13 +2570,31 @@
data_string_forget (&data, MDL);
}
- if (lease -> filename)
- client_envadd (client,
- prefix, "filename", "%s", lease -> filename);
- if (lease -> server_name)
- client_envadd (client, prefix, "server_name",
- "%s", lease -> server_name);
+ if (lease->filename) {
+ if (check_option_values(NULL, DHO_ROOT_PATH,
+ lease->filename,
+ strlen(lease->filename)) == 0) {
+ client_envadd(client, prefix, "filename",
+ "%s", lease->filename);
+ } else {
+ log_error("suspect value in %s "
+ "option - discarded",
+ lease->filename);
+ }
+ }
+ if (lease->server_name) {
+ if (check_option_values(NULL, DHO_HOST_NAME,
+ lease->server_name,
+ strlen(lease->server_name)) == 0 ) {
+ client_envadd (client, prefix, "server_name",
+ "%s", lease->server_name);
+ } else {
+ log_error("suspect value in %s "
+ "option - discarded",
+ lease->server_name);
+ }
+ }
for (i = 0; i < lease -> options -> universe_count; i++) {
option_space_foreach ((struct packet *)0, (struct lease *)0,
client, (struct option_state *)0,
@@ -3185,3 +3219,115 @@
#endif
return rcode;
}
+
+/*
+ * The following routines are used to check that certain
+ * strings are reasonable before we pass them to the scripts.
+ * This avoids some problems with scripts treating the strings
+ * as commands - see ticket 23722
+ * The domain checking code should be done as part of assembling
+ * the string but we are doing it here for now due to time
+ * constraints.
+ */
+
+static int check_domain_name(const char *ptr, size_t len, int dots)
+{
+ const char *p;
+
+ /* not empty or complete length not over 255 characters */
+ if ((len == 0) || (len > 256))
+ return(-1);
+
+ /* consists of [[:alnum:]-]+ labels separated by [.] */
+ /* a [_] is against RFC but seems to be "widely used"... */
+ for (p=ptr; (*p != 0) && (len-- > 0); p++) {
+ if ((*p == '-') || (*p == '_')) {
+ /* not allowed at begin or end of a label */
+ if (((p - ptr) == 0) || (len == 0) || (p[1] == '.'))
+return(-1);
+ } else if (*p == '.') {
+ /* each label has to be 1-63 characters;
+ we allow [.] at the end ('foo.bar.') */
+ size_t d = p - ptr;
+ if ((d <= 0) || (d >= 64))
+return(-1);
+ ptr = p + 1; /* jump to the next label*/
+ if ((dots > 0) && (len > 0))
+dots--;
+ } else if (isalnum((unsigned char)*p) == 0) {
+ /* al