Line 0
Link Here
|
|
|
1 |
From 593fe52faa1b85567a7ec20c69d8cfbc7368ae5b Mon Sep 17 00:00:00 2001 |
2 |
From: Ian Jackson <ian.jackson@eu.citrix.com> |
3 |
Date: Mon, 15 Jun 2015 14:50:42 +0100 |
4 |
Subject: [PATCH] xl: Sane handling of extra config file arguments |
5 |
|
6 |
Various xl sub-commands take additional parameters containing = as |
7 |
additional config fragments. |
8 |
|
9 |
The handling of these config fragments has a number of bugs: |
10 |
|
11 |
1. Use of a static 1024-byte buffer. (If truncation would occur, |
12 |
with semi-trusted input, a security risk arises due to quotes |
13 |
being lost.) |
14 |
|
15 |
2. Mishandling of the return value from snprintf, so that if |
16 |
truncation occurs, the to-write pointer is updated with the |
17 |
wanted-to-write length, resulting in stack corruption. (This is |
18 |
XSA-137.) |
19 |
|
20 |
3. Clone-and-hack of the code for constructing the appended |
21 |
config file. |
22 |
|
23 |
These are fixed here, by introducing a new function |
24 |
`string_realloc_append' and using it everywhere. The `extra_info' |
25 |
buffers are replaced by pointers, which start off NULL and are |
26 |
explicitly freed on all return paths. |
27 |
|
28 |
The separate variable which will become dom_info.extra_config is |
29 |
abolished (which involves moving the clearing of dom_info). |
30 |
|
31 |
Additional bugs I observe, not fixed here: |
32 |
|
33 |
4. The functions which now call string_realloc_append use ad-hoc |
34 |
error returns, with multiple calls to `return'. This currently |
35 |
necessitates multiple new calls to `free'. |
36 |
|
37 |
5. Many of the paths in xl call exit(-rc) where rc is a libxl status |
38 |
code. This is a ridiculous exit status `convention'. |
39 |
|
40 |
6. The loops for handling extra config data are clone-and-hacks. |
41 |
|
42 |
7. Once the extra config buffer is accumulated, it must be combined |
43 |
with the appropriate main config file. The code to do this |
44 |
combining is clone-and-hacked too. |
45 |
|
46 |
Signed-off-by: Ian Jackson <Ian.Jackson@eu.citrix.com> |
47 |
Tested-by: Ian Jackson <Ian.Jackson@eu.citrix.com> |
48 |
Acked-by: Ian Campbell <ian,campbell@citrix.com> |
49 |
--- |
50 |
v2: Use SSIZE_MAX, not INT_MAX. |
51 |
Check *accumulate for NULL, not accumulate. |
52 |
Move memset of dom_info. |
53 |
--- |
54 |
tools/libxl/xl_cmdimpl.c | 64 +++++++++++++++++++++++++++++----------------- |
55 |
1 file changed, 40 insertions(+), 24 deletions(-) |
56 |
|
57 |
diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c |
58 |
index c858068..c01a851 100644 |
59 |
--- a/tools/libxl/xl_cmdimpl.c |
60 |
+++ b/tools/libxl/xl_cmdimpl.c |
61 |
@@ -151,7 +151,7 @@ struct domain_create { |
62 |
int console_autoconnect; |
63 |
int checkpointed_stream; |
64 |
const char *config_file; |
65 |
- const char *extra_config; /* extra config string */ |
66 |
+ char *extra_config; /* extra config string */ |
67 |
const char *restore_file; |
68 |
int migrate_fd; /* -1 means none */ |
69 |
char **migration_domname_r; /* from malloc */ |
70 |
@@ -4805,11 +4805,25 @@ int main_vm_list(int argc, char **argv) |
71 |
return 0; |
72 |
} |
73 |
|
74 |
+static void string_realloc_append(char **accumulate, const char *more) |
75 |
+{ |
76 |
+ /* Appends more to accumulate. Accumulate is either NULL, or |
77 |
+ * points (always) to a malloc'd nul-terminated string. */ |
78 |
+ |
79 |
+ size_t oldlen = *accumulate ? strlen(*accumulate) : 0; |
80 |
+ size_t morelen = strlen(more) + 1/*nul*/; |
81 |
+ if (oldlen > SSIZE_MAX || morelen > SSIZE_MAX - oldlen) { |
82 |
+ fprintf(stderr,"Additional config data far too large\n"); |
83 |
+ exit(-ERROR_FAIL); |
84 |
+ } |
85 |
+ |
86 |
+ *accumulate = xrealloc(*accumulate, oldlen + morelen); |
87 |
+ memcpy(*accumulate + oldlen, more, morelen); |
88 |
+} |
89 |
+ |
90 |
int main_create(int argc, char **argv) |
91 |
{ |
92 |
const char *filename = NULL; |
93 |
- char *p; |
94 |
- char extra_config[1024]; |
95 |
struct domain_create dom_info; |
96 |
int paused = 0, debug = 0, daemonize = 1, console_autoconnect = 0, |
97 |
quiet = 0, monitor = 1, vnc = 0, vncautopass = 0; |
98 |
@@ -4824,6 +4838,8 @@ int main_create(int argc, char **argv) |
99 |
{0, 0, 0, 0} |
100 |
}; |
101 |
|
102 |
+ dom_info.extra_config = NULL; |
103 |
+ |
104 |
if (argv[1] && argv[1][0] != '-' && !strchr(argv[1], '=')) { |
105 |
filename = argv[1]; |
106 |
argc--; argv++; |
107 |
@@ -4863,20 +4879,21 @@ int main_create(int argc, char **argv) |
108 |
break; |
109 |
} |
110 |
|
111 |
- extra_config[0] = '\0'; |
112 |
- for (p = extra_config; optind < argc; optind++) { |
113 |
+ memset(&dom_info, 0, sizeof(dom_info)); |
114 |
+ |
115 |
+ for (; optind < argc; optind++) { |
116 |
if (strchr(argv[optind], '=') != NULL) { |
117 |
- p += snprintf(p, sizeof(extra_config) - (p - extra_config), |
118 |
- "%s\n", argv[optind]); |
119 |
+ string_realloc_append(&dom_info.extra_config, argv[optind]); |
120 |
+ string_realloc_append(&dom_info.extra_config, "\n"); |
121 |
} else if (!filename) { |
122 |
filename = argv[optind]; |
123 |
} else { |
124 |
help("create"); |
125 |
+ free(dom_info.extra_config); |
126 |
return 2; |
127 |
} |
128 |
} |
129 |
|
130 |
- memset(&dom_info, 0, sizeof(dom_info)); |
131 |
dom_info.debug = debug; |
132 |
dom_info.daemonize = daemonize; |
133 |
dom_info.monitor = monitor; |
134 |
@@ -4884,16 +4901,18 @@ int main_create(int argc, char **argv) |
135 |
dom_info.dryrun = dryrun_only; |
136 |
dom_info.quiet = quiet; |
137 |
dom_info.config_file = filename; |
138 |
- dom_info.extra_config = extra_config; |
139 |
dom_info.migrate_fd = -1; |
140 |
dom_info.vnc = vnc; |
141 |
dom_info.vncautopass = vncautopass; |
142 |
dom_info.console_autoconnect = console_autoconnect; |
143 |
|
144 |
rc = create_domain(&dom_info); |
145 |
- if (rc < 0) |
146 |
+ if (rc < 0) { |
147 |
+ free(dom_info.extra_config); |
148 |
return -rc; |
149 |
+ } |
150 |
|
151 |
+ free(dom_info.extra_config); |
152 |
return 0; |
153 |
} |
154 |
|
155 |
@@ -4901,8 +4920,7 @@ int main_config_update(int argc, char **argv) |
156 |
{ |
157 |
uint32_t domid; |
158 |
const char *filename = NULL; |
159 |
- char *p; |
160 |
- char extra_config[1024]; |
161 |
+ char *extra_config = NULL; |
162 |
void *config_data = 0; |
163 |
int config_len = 0; |
164 |
libxl_domain_config d_config; |
165 |
@@ -4940,15 +4958,15 @@ int main_config_update(int argc, char **argv) |
166 |
break; |
167 |
} |
168 |
|
169 |
- extra_config[0] = '\0'; |
170 |
- for (p = extra_config; optind < argc; optind++) { |
171 |
+ for (; optind < argc; optind++) { |
172 |
if (strchr(argv[optind], '=') != NULL) { |
173 |
- p += snprintf(p, sizeof(extra_config) - (p - extra_config), |
174 |
- "%s\n", argv[optind]); |
175 |
+ string_realloc_append(&extra_config, argv[optind]); |
176 |
+ string_realloc_append(&extra_config, "\n"); |
177 |
} else if (!filename) { |
178 |
filename = argv[optind]; |
179 |
} else { |
180 |
help("create"); |
181 |
+ free(extra_config); |
182 |
return 2; |
183 |
} |
184 |
} |
185 |
@@ -4957,7 +4975,8 @@ int main_config_update(int argc, char **argv) |
186 |
rc = libxl_read_file_contents(ctx, filename, |
187 |
&config_data, &config_len); |
188 |
if (rc) { fprintf(stderr, "Failed to read config file: %s: %s\n", |
189 |
- filename, strerror(errno)); return ERROR_FAIL; } |
190 |
+ filename, strerror(errno)); |
191 |
+ free(extra_config); return ERROR_FAIL; } |
192 |
if (strlen(extra_config)) { |
193 |
if (config_len > INT_MAX - (strlen(extra_config) + 2 + 1)) { |
194 |
fprintf(stderr, "Failed to attach extra configration\n"); |
195 |
@@ -4998,7 +5017,7 @@ int main_config_update(int argc, char **argv) |
196 |
libxl_domain_config_dispose(&d_config); |
197 |
|
198 |
free(config_data); |
199 |
- |
200 |
+ free(extra_config); |
201 |
return 0; |
202 |
} |
203 |
|
204 |
@@ -7255,7 +7274,7 @@ int main_cpupoolcreate(int argc, char **argv) |
205 |
{ |
206 |
const char *filename = NULL, *config_src=NULL; |
207 |
const char *p; |
208 |
- char extra_config[1024]; |
209 |
+ char *extra_config = NULL; |
210 |
int opt; |
211 |
static struct option opts[] = { |
212 |
{"defconfig", 1, 0, 'f'}, |
213 |
@@ -7289,13 +7308,10 @@ int main_cpupoolcreate(int argc, char **argv) |
214 |
break; |
215 |
} |
216 |
|
217 |
- memset(extra_config, 0, sizeof(extra_config)); |
218 |
while (optind < argc) { |
219 |
if ((p = strchr(argv[optind], '='))) { |
220 |
- if (strlen(extra_config) + 1 + strlen(argv[optind]) < sizeof(extra_config)) { |
221 |
- strcat(extra_config, "\n"); |
222 |
- strcat(extra_config, argv[optind]); |
223 |
- } |
224 |
+ string_realloc_append(&extra_config, "\n"); |
225 |
+ string_realloc_append(&extra_config, argv[optind]); |
226 |
} else if (!filename) { |
227 |
filename = argv[optind]; |
228 |
} else { |
229 |
-- |
230 |
1.7.10.4 |
231 |
|