debuggers.hg

view tools/libxl/libxlu_cfg.c @ 22855:1d1eec7e1fb4

xl: Perform minimal validation of virtual disk file while parsing config file

This patch performs some very basic validation on the virtual disk
file passed through the config file. This validation ensures that we
don't go too far with the initialization like spawn qemu and more
while there could be some potentially fundamental issues.

[ Patch fixed up to work with PHYSTYPE_EMPTY 22808:6ec61438713a -iwj ]

Signed-off-by: Kamala Narasimhan <kamala.narasimhan@citrix.com>
Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
Committed-by: Ian Jackson <ian.jackson@eu.citrix.com>
author Kamala Narasimhan <kamala.narasimhan@gmail.com>
date Tue Jan 25 18:09:49 2011 +0000 (2011-01-25)
parents cb94dbe20f97
children
line source
2 #include "libxlu_internal.h"
3 #include "libxlu_cfg_y.h"
4 #include "libxlu_cfg_l.h"
5 #include "libxlu_cfg_i.h"
7 XLU_Config *xlu_cfg_init(FILE *report, const char *report_filename) {
8 XLU_Config *cfg;
10 cfg= malloc(sizeof(*cfg));
11 if (!cfg) return 0;
13 cfg->report= report;
14 cfg->filename= strdup(report_filename);
15 if (!cfg->filename) { free(cfg); return 0; }
17 cfg->settings= 0;
18 return cfg;
19 }
21 static int ctx_prep(CfgParseContext *ctx, XLU_Config *cfg) {
22 int e;
24 ctx->cfg= cfg;
25 ctx->err= 0;
26 ctx->lexerrlineno= -1;
27 ctx->likely_python= 0;
28 ctx->scanner= 0;
30 e= xlu__cfg_yylex_init_extra(ctx, &ctx->scanner);
31 if (e) {
32 fprintf(cfg->report,"%s: unable to create scanner: %s\n",
33 cfg->filename, strerror(e));
34 return e;
35 }
36 return 0;
37 }
39 static void ctx_dispose(CfgParseContext *ctx) {
40 if (ctx->scanner) xlu__cfg_yylex_destroy(ctx->scanner);
41 }
43 static void parse(CfgParseContext *ctx) {
44 /* On return, ctx.err will be updated with the error status. */
45 int r;
46 r= xlu__cfg_yyparse(ctx);
47 if (r) assert(ctx->err);
49 if (ctx->err && ctx->likely_python) {
50 fputs(
51 "warning: Config file looks like it contains Python code.\n"
52 "warning: Arbitrary Python is no longer supported.\n"
53 "warning: See http://wiki.xen.org/xenwiki/PythonInXlConfig\n",
54 ctx->cfg->report);
55 }
56 }
58 int xlu_cfg_readfile(XLU_Config *cfg, const char *real_filename) {
59 FILE *f = 0;
60 int e;
62 CfgParseContext ctx;
63 e = ctx_prep(&ctx, cfg);
64 if (e) { ctx.err= e; goto xe; }
66 f= fopen(real_filename, "r");
67 if (!f) {
68 ctx.err = errno;
69 fprintf(cfg->report,"%s: unable to open configuration file: %s\n",
70 real_filename, strerror(e));
71 goto xe;
72 }
74 xlu__cfg_yyrestart(f, ctx.scanner);
76 parse(&ctx);
78 xe:
79 ctx_dispose(&ctx);
80 if (f) fclose(f);
82 return ctx.err;
83 }
85 int xlu_cfg_readdata(XLU_Config *cfg, const char *data, int length) {
86 int e;
87 YY_BUFFER_STATE buf= 0;
89 CfgParseContext ctx;
90 e= ctx_prep(&ctx, cfg);
91 if (e) { ctx.err= e; goto xe; }
93 buf = xlu__cfg_yy_scan_bytes(data, length, ctx.scanner);
94 if (!buf) {
95 fprintf(cfg->report,"%s: unable to allocate scanner buffer\n",
96 cfg->filename);
97 ctx.err= ENOMEM;
98 goto xe;
99 }
101 parse(&ctx);
103 xe:
104 if (buf) xlu__cfg_yy_delete_buffer(buf, ctx.scanner);
105 ctx_dispose(&ctx);
107 return ctx.err;
108 }
110 void xlu__cfg_set_free(XLU_ConfigSetting *set) {
111 int i;
113 if (!set) return;
114 free(set->name);
115 for (i=0; i<set->nvalues; i++)
116 free(set->values[i]);
117 free(set->values);
118 free(set);
119 }
121 void xlu_cfg_destroy(XLU_Config *cfg) {
122 XLU_ConfigSetting *set, *set_next;
124 for (set= cfg->settings;
125 set;
126 set= set_next) {
127 set_next= set->next;
128 xlu__cfg_set_free(set);
129 }
130 free(cfg->filename);
131 free(cfg);
132 }
134 static XLU_ConfigSetting *find(const XLU_Config *cfg, const char *n) {
135 XLU_ConfigSetting *set;
137 for (set= cfg->settings;
138 set;
139 set= set->next)
140 if (!strcmp(set->name, n))
141 return set;
142 return 0;
143 }
145 static int find_atom(const XLU_Config *cfg, const char *n,
146 XLU_ConfigSetting **set_r) {
147 XLU_ConfigSetting *set;
149 set= find(cfg,n);
150 if (!set) return ESRCH;
152 if (set->avalues!=1) {
153 fprintf(cfg->report,
154 "%s:%d: warning: parameter `%s' is"
155 " a list but should be a single value\n",
156 cfg->filename, set->lineno, n);
157 return EINVAL;
158 }
159 *set_r= set;
160 return 0;
161 }
163 int xlu_cfg_get_string(const XLU_Config *cfg, const char *n,
164 const char **value_r) {
165 XLU_ConfigSetting *set;
166 int e;
168 e= find_atom(cfg,n,&set); if (e) return e;
169 *value_r= set->values[0];
170 return 0;
171 }
173 int xlu_cfg_replace_string(const XLU_Config *cfg, const char *n,
174 char **value_r) {
175 XLU_ConfigSetting *set;
176 int e;
178 e= find_atom(cfg,n,&set); if (e) return e;
179 free(*value_r);
180 *value_r= strdup(set->values[0]);
181 return 0;
182 }
184 int xlu_cfg_get_long(const XLU_Config *cfg, const char *n,
185 long *value_r) {
186 long l;
187 XLU_ConfigSetting *set;
188 int e;
189 char *ep;
191 e= find_atom(cfg,n,&set); if (e) return e;
192 errno= 0; l= strtol(set->values[0], &ep, 0);
193 e= errno;
194 if (errno) {
195 e= errno;
196 assert(e==EINVAL || e==ERANGE);
197 fprintf(cfg->report,
198 "%s:%d: warning: parameter `%s' could not be parsed"
199 " as a number: %s\n",
200 cfg->filename, set->lineno, n, strerror(e));
201 return e;
202 }
203 if (*ep || ep==set->values[0]) {
204 fprintf(cfg->report,
205 "%s:%d: warning: parameter `%s' is not a valid number\n",
206 cfg->filename, set->lineno, n);
207 return EINVAL;
208 }
209 *value_r= l;
210 return 0;
211 }
214 int xlu_cfg_get_list(const XLU_Config *cfg, const char *n,
215 XLU_ConfigList **list_r, int *entries_r, int dont_warn) {
216 XLU_ConfigSetting *set;
217 set= find(cfg,n); if (!set) return ESRCH;
218 if (set->avalues==1) {
219 if (!dont_warn) {
220 fprintf(cfg->report,
221 "%s:%d: warning: parameter `%s' is a single value"
222 " but should be a list\n",
223 cfg->filename, set->lineno, n);
224 }
225 return EINVAL;
226 }
227 if (list_r) *list_r= set;
228 if (entries_r) *entries_r= set->nvalues;
229 return 0;
230 }
232 const char *xlu_cfg_get_listitem(const XLU_ConfigList *set, int entry) {
233 if (entry < 0 || entry >= set->nvalues) return 0;
234 return set->values[entry];
235 }
238 XLU_ConfigSetting *xlu__cfg_set_mk(CfgParseContext *ctx,
239 int alloc, char *atom) {
240 XLU_ConfigSetting *set= 0;
242 if (ctx->err) goto x;
243 assert(!!alloc == !!atom);
245 set= malloc(sizeof(*set));
246 if (!set) goto xe;
248 set->name= 0; /* tbd */
249 set->avalues= alloc;
251 if (!alloc) {
252 set->nvalues= 0;
253 set->values= 0;
254 } else {
255 set->values= malloc(sizeof(*set->values) * alloc);
256 if (!set->values) goto xe;
258 set->nvalues= 1;
259 set->values[0]= atom;
260 }
261 return set;
263 xe:
264 ctx->err= errno;
265 x:
266 free(set);
267 free(atom);
268 return 0;
269 }
271 void xlu__cfg_set_add(CfgParseContext *ctx, XLU_ConfigSetting *set,
272 char *atom) {
273 if (ctx->err) return;
275 assert(atom);
277 if (set->nvalues >= set->avalues) {
278 int new_avalues;
279 char **new_values;
281 if (set->avalues > INT_MAX / 100) { ctx->err= ERANGE; return; }
282 new_avalues= set->avalues * 4;
283 new_values= realloc(set->values,
284 sizeof(*new_values) * new_avalues);
285 if (!new_values) { ctx->err= errno; free(atom); return; }
286 set->values= new_values;
287 set->avalues= new_avalues;
288 }
289 set->values[set->nvalues++]= atom;
290 }
292 void xlu__cfg_set_store(CfgParseContext *ctx, char *name,
293 XLU_ConfigSetting *set, int lineno) {
294 if (ctx->err) return;
296 assert(name);
297 set->name= name;
298 set->lineno= lineno;
299 set->next= ctx->cfg->settings;
300 ctx->cfg->settings= set;
301 }
303 char *xlu__cfgl_strdup(CfgParseContext *ctx, const char *src) {
304 char *result;
306 if (ctx->err) return 0;
307 result= strdup(src);
308 if (!result) ctx->err= errno;
309 return result;
310 }
312 char *xlu__cfgl_dequote(CfgParseContext *ctx, const char *src) {
313 char *result;
314 const char *p;
315 char *q;
316 int len, c, nc;
318 if (ctx->err) return 0;
320 len= strlen(src);
321 assert(len>=2 && src[0]==src[len-1]);
323 result= malloc(len-1);
324 if (!result) { ctx->err= errno; return 0; }
326 q= result;
328 for (p= src+1;
329 p < src+len-1;
330 ) {
331 c= *p++;
332 if (c=='\\') {
333 assert(p < src+len-1);
334 nc= *p++;
335 if (nc=='"' || nc=='\'' || nc=='\\') {
336 *q++= nc;
337 } else if (nc=='a') { *q++= '\007';
338 } else if (nc=='b') { *q++= '\010';
339 } else if (nc=='f') { *q++= '\014';
340 } else if (nc=='n') { *q++= '\n';
341 } else if (nc=='r') { *q++= '\r';
342 } else if (nc=='t') { *q++= '\t';
343 } else if (nc=='v') { *q++= '\013';
344 } else if (nc=='x') {
346 #define NUMERIC_CHAR(minlen,maxlen,base,basetext) do{ \
347 char numbuf[(maxlen)+1], *ep; \
348 unsigned long val; \
349 \
350 strncpy(numbuf,p,(maxlen)); \
351 numbuf[(maxlen)]= 0; \
352 val= strtoul(numbuf, &ep, (base)); \
353 if (ep <= numbuf+(minlen)) { \
354 xlu__cfgl_lexicalerror(ctx,"invalid digit after" \
355 " backslash " basetext "numerical character escape" \
356 " in quoted string"); \
357 ctx->err= EINVAL; \
358 goto x; \
359 } \
360 p += (ep - numbuf); \
361 }while(0)
363 p++;
364 NUMERIC_CHAR(2,2,16,"hex");
365 } else if (nc>='0' && nc<='7') {
366 NUMERIC_CHAR(1,3,10,"octal");
367 }
368 assert(p <= src+len-1);
369 } else {
370 *q++= c;
371 }
372 }
374 x:
375 *q++= 0;
376 return result;
377 }
379 void xlu__cfgl_lexicalerror(CfgParseContext *ctx, char const *msg) {
380 YYLTYPE loc;
381 loc.first_line= xlu__cfg_yyget_lineno(ctx->scanner);
382 xlu__cfg_yyerror(&loc, ctx, msg);
383 ctx->lexerrlineno= loc.first_line;
384 }
386 void xlu__cfg_yyerror(YYLTYPE *loc, CfgParseContext *ctx, char const *msg) {
387 const char *text, *newline;
388 int len, lineno;
390 lineno= loc->first_line;
391 if (lineno <= ctx->lexerrlineno) return;
393 text= xlu__cfg_yyget_text(ctx->scanner);
394 len= xlu__cfg_yyget_leng(ctx->scanner);
395 newline= "";
396 if (len>0 && text[len-1]=='\n') {
397 len--;
398 lineno--;
399 if (!len) {
400 newline= "<newline>";
401 }
402 }
403 while (len>0 && (text[len-1]=='\t' || text[len-1]==' ')) {
404 len--;
405 }
407 fprintf(ctx->cfg->report,
408 "%s:%d: config parsing error near %s%.*s%s%s: %s\n",
409 ctx->cfg->filename, lineno,
410 len?"`":"", len, text, len?"'":"", newline,
411 msg);
412 if (!ctx->err) ctx->err= EINVAL;
413 }