debuggers.hg

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