~ubuntu-branches/ubuntu/lucid/dhcp3/lucid-security

« back to all changes in this revision

Viewing changes to debian/patches/CVE-2011-0997.dpatch

  • Committer: Bazaar Package Importer
  • Author(s): Marc Deslauriers
  • Date: 2011-04-11 08:57:21 UTC
  • Revision ID: james.westby@ubuntu.com-20110411085721-5obw79petr0y045e
Tags: 3.1.3-2ubuntu3.1
* SECURITY UPDATE: arbitrary code execution via crafted hostname
  - debian/patches/CVE-2011-0997.dpatch: filter strings in
    client/dhclient.c, common/options.c.
  - CVE-2011-0997

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#! /bin/sh /usr/share/dpatch/dpatch-run
 
2
# Description: fix arbitrary code execution via crafted hostname
 
3
# Author: Marius Tomaschewski
 
4
# Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=621099
 
5
 
 
6
@DPATCH@
 
7
diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' dhcp3-3.1.3~/client/dhclient.c dhcp3-3.1.3/client/dhclient.c
 
8
--- dhcp3-3.1.3~/client/dhclient.c      2011-04-11 08:57:02.976060280 -0400
 
9
+++ dhcp3-3.1.3/client/dhclient.c       2011-04-11 08:57:16.536060277 -0400
 
10
@@ -77,6 +77,11 @@
 
11
 int quiet=0;
 
12
 int nowait=0;
 
13
 
 
14
+static int check_domain_name(const char *ptr, size_t len, int dots);
 
15
+static int check_domain_name_list(const char *ptr, size_t len, int dots);
 
16
+static int check_option_values(struct universe *universe, unsigned int opt,
 
17
+                              const char *ptr, size_t len);
 
18
+
 
19
 static void usage PROTO ((void));
 
20
 
 
21
 int main (argc, argv, envp)
 
22
@@ -2524,13 +2529,23 @@
 
23
                if (data.len) {
 
24
                        char name [256];
 
25
                        if (dhcp_option_ev_name (name, sizeof name,
 
26
-                                                oc -> option)) {
 
27
-                               client_envadd (es -> client, es -> prefix,
 
28
-                                              name, "%s",
 
29
-                                              (pretty_print_option
 
30
-                                               (oc -> option,
 
31
-                                                data.data, data.len,
 
32
-                                                0, 0)));
 
33
+                                                oc->option)) {
 
34
+                               const char *value;
 
35
+                               value = pretty_print_option(oc->option,
 
36
+                                                           data.data,
 
37
+                                                           data.len, 0, 0);
 
38
+                               size_t length = strlen(value);
 
39
+
 
40
+                               if (check_option_values(oc->option->universe,
 
41
+                                                       oc->option->code,
 
42
+                                                       value, length) == 0) {
 
43
+                                       client_envadd(es->client, es->prefix,
 
44
+                                                     name, "%s", value);
 
45
+                               } else {
 
46
+                                       log_error("suspect value in %s "
 
47
+                                                 "option - discarded",
 
48
+                                                 name);
 
49
+                               }
 
50
                                data_string_forget (&data, MDL);
 
51
                        }
 
52
                }
 
53
@@ -2610,12 +2625,32 @@
 
54
                data_string_forget (&data, MDL);
 
55
        }
 
56
 
 
57
-       if (lease -> filename)
 
58
-               client_envadd (client,
 
59
-                              prefix, "filename", "%s", lease -> filename);
 
60
-       if (lease -> server_name)
 
61
-               client_envadd (client, prefix, "server_name",
 
62
-                              "%s", lease -> server_name);
 
63
+       if (lease->filename) {
 
64
+               if (check_option_values(NULL, DHO_ROOT_PATH,
 
65
+                                       lease->filename,
 
66
+                                       strlen(lease->filename)) == 0) {
 
67
+                       client_envadd(client, prefix, "filename",
 
68
+                                     "%s", lease->filename);
 
69
+               } else {
 
70
+                       log_error("suspect value in %s "
 
71
+                                 "option - discarded",
 
72
+                                 "filename");
 
73
+               }
 
74
+       }
 
75
+
 
76
+       if (lease->server_name) {
 
77
+               if (check_option_values(NULL, DHO_HOST_NAME,
 
78
+                                       lease->server_name,
 
79
+                                       strlen(lease->server_name)) == 0 ) {
 
80
+                       client_envadd (client, prefix, "server_name",
 
81
+                                      "%s", lease->server_name);
 
82
+               } else {
 
83
+                       log_error("suspect value in %s "
 
84
+                                 "option - discarded",
 
85
+                                 "server_name");
 
86
+               }
 
87
+       }
 
88
+                               
 
89
 
 
90
        for (i = 0; i < lease -> options -> universe_count; i++) {
 
91
                option_space_foreach ((struct packet *)0, (struct lease *)0,
 
92
@@ -3239,3 +3274,112 @@
 
93
        data_string_forget (&ddns_dhcid, MDL);
 
94
        return rcode;
 
95
 }
 
96
+
 
97
+/*
 
98
+ * The following routines are used to check that certain
 
99
+ * strings are reasonable before we pass them to the scripts.
 
100
+ * This avoids some problems with scripts treating the strings
 
101
+ * as commands - see ticket 23722
 
102
+ * The domain checking code should be done as part of assembling
 
103
+ * the string but we are doing it here for now due to time
 
104
+ * constraints.
 
105
+ */
 
106
+
 
107
+static int check_domain_name(const char *ptr, size_t len, int dots)
 
108
+{
 
109
+       const char *p;
 
110
+
 
111
+       /* not empty or complete length not over 255 characters   */
 
112
+       if ((len == 0) || (len > 256))
 
113
+               return(-1);
 
114
+
 
115
+       /* consists of [[:alnum:]-]+ labels separated by [.]      */
 
116
+       /* a [_] is against RFC but seems to be "widely used"...  */
 
117
+       for (p=ptr; (*p != 0) && (len-- > 0); p++) {
 
118
+               if ((*p == '-') || (*p == '_')) {
 
119
+                       /* not allowed at begin or end of a label */
 
120
+                       if (((p - ptr) == 0) || (len == 0) || (p[1] == '.'))
 
121
+                               return(-1);
 
122
+               } else if (*p == '.') {
 
123
+                       /* each label has to be 1-63 characters;
 
124
+                          we allow [.] at the end ('foo.bar.')   */
 
125
+                       size_t d = p - ptr;
 
126
+                       if ((d <= 0) || (d >= 64))
 
127
+                               return(-1);
 
128
+                       ptr = p + 1; /* jump to the next label    */
 
129
+                       if ((dots > 0) && (len > 0))
 
130
+                               dots--;
 
131
+               } else if (isalnum((unsigned char)*p) == 0) {
 
132
+                       /* also numbers at the begin are fine     */
 
133
+                       return(-1);
 
134
+               }
 
135
+       }
 
136
+       return(dots ? -1 : 0);
 
137
+}
 
138
+
 
139
+static int check_domain_name_list(const char *ptr, size_t len, int dots)
 
140
+{
 
141
+       const char *p;
 
142
+       int ret = -1; /* at least one needed */
 
143
+
 
144
+       if ((ptr == NULL) || (len == 0))
 
145
+               return(-1);
 
146
+
 
147
+       for (p=ptr; (*p != 0) && (len > 0); p++, len--) {
 
148
+               if (*p != ' ')
 
149
+                       continue;
 
150
+               if (p > ptr) {
 
151
+                       if (check_domain_name(ptr, p - ptr, dots) != 0)
 
152
+                               return(-1);
 
153
+                       ret = 0;
 
154
+               }
 
155
+               ptr = p + 1;
 
156
+       }
 
157
+       if (p > ptr)
 
158
+               return(check_domain_name(ptr, p - ptr, dots));
 
159
+       else
 
160
+               return(ret);
 
161
+}
 
162
+
 
163
+static int check_option_values(struct universe *universe,
 
164
+                              unsigned int opt,
 
165
+                              const char *ptr,
 
166
+                              size_t len)
 
167
+{
 
168
+       if (ptr == NULL)
 
169
+               return(-1);
 
170
+
 
171
+       /* just reject options we want to protect, will be escaped anyway */
 
172
+       if ((universe == NULL) || (universe == &dhcp_universe)) {
 
173
+               switch(opt) {
 
174
+                     case DHO_HOST_NAME:
 
175
+                     case DHO_NIS_DOMAIN:
 
176
+                     case DHO_NETBIOS_SCOPE:
 
177
+                       return check_domain_name(ptr, len, 0);
 
178
+                       break;
 
179
+                     case DHO_DOMAIN_NAME: /* accept a list for compatibiliy */
 
180
+                       return check_domain_name_list(ptr, len, 0);
 
181
+                       break;
 
182
+                     case DHO_ROOT_PATH:
 
183
+                       if (len == 0)
 
184
+                               return(-1);
 
185
+                       for (; (*ptr != 0) && (len-- > 0); ptr++) {
 
186
+                               if(!(isalnum((unsigned char)*ptr) ||
 
187
+                                    *ptr == '#'  || *ptr == '%' ||
 
188
+                                    *ptr == '+'  || *ptr == '-' ||
 
189
+                                    *ptr == '_'  || *ptr == ':' ||
 
190
+                                    *ptr == '.'  || *ptr == ',' ||
 
191
+                                    *ptr == '@'  || *ptr == '~' ||
 
192
+                                    *ptr == '\\' || *ptr == '/' ||
 
193
+                                    *ptr == '['  || *ptr == ']' ||
 
194
+                                    *ptr == '='  || *ptr == ' '))
 
195
+                                       return(-1);
 
196
+                       }
 
197
+                       return(0);
 
198
+                       break;
 
199
+               }
 
200
+       }
 
201
+
 
202
+       return(0);
 
203
+}
 
204
 
205
diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' dhcp3-3.1.3~/common/options.c dhcp3-3.1.3/common/options.c
 
206
--- dhcp3-3.1.3~/common/options.c       2011-04-11 08:57:02.966060280 -0400
 
207
+++ dhcp3-3.1.3/common/options.c        2011-04-11 08:57:16.536060277 -0400
 
208
@@ -2951,7 +2951,8 @@
 
209
                                count += 4;
 
210
                        }
 
211
                } else if (**src == '"' || **src == '\'' || **src == '$' ||
 
212
-                          **src == '`' || **src == '\\') {
 
213
+                          **src == '`' || **src == '\\' || **src == '|' ||
 
214
+                          **src == '&') {
 
215
                        if (*dst + 2 > dend)
 
216
                                return -1;
 
217