debuggers.hg

view xen/common/libelf/libelf-dominfo.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 7f3ccf376aad
children
line source
1 /*
2 * parse xen-specific informations out of elf kernel binaries.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation;
7 * version 2.1 of the License.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
19 #include "libelf-private.h"
21 /* ------------------------------------------------------------------------ */
22 /* xen features */
24 static const char *const elf_xen_feature_names[] = {
25 [XENFEAT_writable_page_tables] = "writable_page_tables",
26 [XENFEAT_writable_descriptor_tables] = "writable_descriptor_tables",
27 [XENFEAT_auto_translated_physmap] = "auto_translated_physmap",
28 [XENFEAT_supervisor_mode_kernel] = "supervisor_mode_kernel",
29 [XENFEAT_pae_pgdir_above_4gb] = "pae_pgdir_above_4gb"
30 };
31 static const int elf_xen_features =
32 sizeof(elf_xen_feature_names) / sizeof(elf_xen_feature_names[0]);
34 int elf_xen_parse_features(const char *features,
35 uint32_t *supported,
36 uint32_t *required)
37 {
38 char feature[64];
39 int pos, len, i;
41 if ( features == NULL )
42 return 0;
44 for ( pos = 0; features[pos] != '\0'; pos += len )
45 {
46 memset(feature, 0, sizeof(feature));
47 for ( len = 0;; len++ )
48 {
49 if ( len >= sizeof(feature)-1 )
50 break;
51 if ( features[pos + len] == '\0' )
52 break;
53 if ( features[pos + len] == '|' )
54 {
55 len++;
56 break;
57 }
58 feature[len] = features[pos + len];
59 }
61 for ( i = 0; i < elf_xen_features; i++ )
62 {
63 if ( !elf_xen_feature_names[i] )
64 continue;
65 if ( (required != NULL) && (feature[0] == '!') )
66 {
67 /* required */
68 if ( !strcmp(feature + 1, elf_xen_feature_names[i]) )
69 {
70 elf_xen_feature_set(i, supported);
71 elf_xen_feature_set(i, required);
72 break;
73 }
74 }
75 else
76 {
77 /* supported */
78 if ( !strcmp(feature, elf_xen_feature_names[i]) )
79 {
80 elf_xen_feature_set(i, supported);
81 break;
82 }
83 }
84 }
85 if ( i == elf_xen_features )
86 return -1;
87 }
89 return 0;
90 }
92 /* ------------------------------------------------------------------------ */
93 /* xen elf notes */
95 int elf_xen_parse_note(struct elf_binary *elf,
96 struct elf_dom_parms *parms,
97 const elf_note *note)
98 {
99 /* *INDENT-OFF* */
100 static const struct {
101 char *name;
102 int str;
103 } note_desc[] = {
104 [XEN_ELFNOTE_ENTRY] = { "ENTRY", 0},
105 [XEN_ELFNOTE_HYPERCALL_PAGE] = { "HYPERCALL_PAGE", 0},
106 [XEN_ELFNOTE_VIRT_BASE] = { "VIRT_BASE", 0},
107 [XEN_ELFNOTE_INIT_P2M] = { "INIT_P2M", 0},
108 [XEN_ELFNOTE_PADDR_OFFSET] = { "PADDR_OFFSET", 0},
109 [XEN_ELFNOTE_HV_START_LOW] = { "HV_START_LOW", 0},
110 [XEN_ELFNOTE_XEN_VERSION] = { "XEN_VERSION", 1},
111 [XEN_ELFNOTE_GUEST_OS] = { "GUEST_OS", 1},
112 [XEN_ELFNOTE_GUEST_VERSION] = { "GUEST_VERSION", 1},
113 [XEN_ELFNOTE_LOADER] = { "LOADER", 1},
114 [XEN_ELFNOTE_PAE_MODE] = { "PAE_MODE", 1},
115 [XEN_ELFNOTE_FEATURES] = { "FEATURES", 1},
116 [XEN_ELFNOTE_BSD_SYMTAB] = { "BSD_SYMTAB", 1},
117 [XEN_ELFNOTE_SUSPEND_CANCEL] = { "SUSPEND_CANCEL", 0 },
118 [XEN_ELFNOTE_MOD_START_PFN] = { "MOD_START_PFN", 0 },
119 };
120 /* *INDENT-ON* */
122 const char *str = NULL;
123 uint64_t val = 0;
124 int type = elf_uval(elf, note, type);
126 if ( (type >= sizeof(note_desc) / sizeof(note_desc[0])) ||
127 (note_desc[type].name == NULL) )
128 {
129 elf_msg(elf, "%s: unknown xen elf note (0x%x)\n",
130 __FUNCTION__, type);
131 return 0;
132 }
134 if ( note_desc[type].str )
135 {
136 str = elf_note_desc(elf, note);
137 elf_msg(elf, "%s: %s = \"%s\"\n", __FUNCTION__,
138 note_desc[type].name, str);
139 parms->elf_notes[type].type = XEN_ENT_STR;
140 parms->elf_notes[type].data.str = str;
141 }
142 else
143 {
144 val = elf_note_numeric(elf, note);
145 elf_msg(elf, "%s: %s = 0x%" PRIx64 "\n", __FUNCTION__,
146 note_desc[type].name, val);
147 parms->elf_notes[type].type = XEN_ENT_LONG;
148 parms->elf_notes[type].data.num = val;
149 }
150 parms->elf_notes[type].name = note_desc[type].name;
152 switch ( type )
153 {
154 case XEN_ELFNOTE_LOADER:
155 safe_strcpy(parms->loader, str);
156 break;
157 case XEN_ELFNOTE_GUEST_OS:
158 safe_strcpy(parms->guest_os, str);
159 break;
160 case XEN_ELFNOTE_GUEST_VERSION:
161 safe_strcpy(parms->guest_ver, str);
162 break;
163 case XEN_ELFNOTE_XEN_VERSION:
164 safe_strcpy(parms->xen_ver, str);
165 break;
166 case XEN_ELFNOTE_PAE_MODE:
167 if ( !strcmp(str, "yes") )
168 parms->pae = 2 /* extended_cr3 */;
169 if ( strstr(str, "bimodal") )
170 parms->pae = 3 /* bimodal */;
171 break;
172 case XEN_ELFNOTE_BSD_SYMTAB:
173 if ( !strcmp(str, "yes") )
174 parms->bsd_symtab = 1;
175 break;
177 case XEN_ELFNOTE_VIRT_BASE:
178 parms->virt_base = val;
179 break;
180 case XEN_ELFNOTE_ENTRY:
181 parms->virt_entry = val;
182 break;
183 case XEN_ELFNOTE_INIT_P2M:
184 parms->p2m_base = val;
185 break;
186 case XEN_ELFNOTE_PADDR_OFFSET:
187 parms->elf_paddr_offset = val;
188 break;
189 case XEN_ELFNOTE_HYPERCALL_PAGE:
190 parms->virt_hypercall = val;
191 break;
192 case XEN_ELFNOTE_HV_START_LOW:
193 parms->virt_hv_start_low = val;
194 break;
196 case XEN_ELFNOTE_FEATURES:
197 if ( elf_xen_parse_features(str, parms->f_supported,
198 parms->f_required) )
199 return -1;
200 break;
202 }
203 return 0;
204 }
206 static int elf_xen_parse_notes(struct elf_binary *elf,
207 struct elf_dom_parms *parms,
208 const void *start, const void *end)
209 {
210 int xen_elfnotes = 0;
211 const elf_note *note;
213 parms->elf_note_start = start;
214 parms->elf_note_end = end;
215 for ( note = parms->elf_note_start;
216 (void *)note < parms->elf_note_end;
217 note = elf_note_next(elf, note) )
218 {
219 if ( strcmp(elf_note_name(elf, note), "Xen") )
220 continue;
221 if ( elf_xen_parse_note(elf, parms, note) )
222 return -1;
223 xen_elfnotes++;
224 }
225 return xen_elfnotes;
226 }
228 /* ------------------------------------------------------------------------ */
229 /* __xen_guest section */
231 int elf_xen_parse_guest_info(struct elf_binary *elf,
232 struct elf_dom_parms *parms)
233 {
234 const char *h;
235 char name[32], value[128];
236 int len;
238 h = parms->guest_info;
239 while ( *h )
240 {
241 memset(name, 0, sizeof(name));
242 memset(value, 0, sizeof(value));
243 for ( len = 0;; len++, h++ )
244 {
245 if ( len >= sizeof(name)-1 )
246 break;
247 if ( *h == '\0' )
248 break;
249 if ( *h == ',' )
250 {
251 h++;
252 break;
253 }
254 if ( *h == '=' )
255 {
256 h++;
257 for ( len = 0;; len++, h++ )
258 {
259 if ( len >= sizeof(value)-1 )
260 break;
261 if ( *h == '\0' )
262 break;
263 if ( *h == ',' )
264 {
265 h++;
266 break;
267 }
268 value[len] = *h;
269 }
270 break;
271 }
272 name[len] = *h;
273 }
274 elf_msg(elf, "%s: %s=\"%s\"\n", __FUNCTION__, name, value);
276 /* strings */
277 if ( !strcmp(name, "LOADER") )
278 safe_strcpy(parms->loader, value);
279 if ( !strcmp(name, "GUEST_OS") )
280 safe_strcpy(parms->guest_os, value);
281 if ( !strcmp(name, "GUEST_VER") )
282 safe_strcpy(parms->guest_ver, value);
283 if ( !strcmp(name, "XEN_VER") )
284 safe_strcpy(parms->xen_ver, value);
285 if ( !strcmp(name, "PAE") )
286 {
287 if ( !strcmp(value, "yes[extended-cr3]") )
288 parms->pae = 2 /* extended_cr3 */;
289 else if ( !strncmp(value, "yes", 3) )
290 parms->pae = 1 /* yes */;
291 }
292 if ( !strcmp(name, "BSD_SYMTAB") )
293 parms->bsd_symtab = 1;
295 /* longs */
296 if ( !strcmp(name, "VIRT_BASE") )
297 parms->virt_base = strtoull(value, NULL, 0);
298 if ( !strcmp(name, "VIRT_ENTRY") )
299 parms->virt_entry = strtoull(value, NULL, 0);
300 if ( !strcmp(name, "ELF_PADDR_OFFSET") )
301 parms->elf_paddr_offset = strtoull(value, NULL, 0);
302 if ( !strcmp(name, "HYPERCALL_PAGE") )
303 parms->virt_hypercall = (strtoull(value, NULL, 0) << 12) +
304 parms->virt_base;
306 /* other */
307 if ( !strcmp(name, "FEATURES") )
308 if ( elf_xen_parse_features(value, parms->f_supported,
309 parms->f_required) )
310 return -1;
311 }
312 return 0;
313 }
315 /* ------------------------------------------------------------------------ */
316 /* sanity checks */
318 static int elf_xen_note_check(struct elf_binary *elf,
319 struct elf_dom_parms *parms)
320 {
321 if ( (parms->elf_note_start == NULL) && (parms->guest_info == NULL) )
322 {
323 int machine = elf_uval(elf, elf->ehdr, e_machine);
324 if ( (machine == EM_386) || (machine == EM_X86_64) )
325 {
326 elf_err(elf, "%s: ERROR: Not a Xen-ELF image: "
327 "No ELF notes or '__xen_guest' section found.\n",
328 __FUNCTION__);
329 return -1;
330 }
331 return 0;
332 }
334 /* Check the contents of the Xen notes or guest string. */
335 if ( ((strlen(parms->loader) == 0) ||
336 strncmp(parms->loader, "generic", 7)) &&
337 ((strlen(parms->guest_os) == 0) ||
338 strncmp(parms->guest_os, "linux", 5)) )
339 {
340 elf_err(elf, "%s: ERROR: Will only load images built for the generic "
341 "loader or Linux images", __FUNCTION__);
342 return -1;
343 }
345 if ( (strlen(parms->xen_ver) == 0) ||
346 strncmp(parms->xen_ver, "xen-3.0", 7) )
347 {
348 elf_err(elf, "%s: ERROR: Xen will only load images built "
349 "for Xen v3.0\n", __FUNCTION__);
350 return -1;
351 }
352 return 0;
353 }
355 static int elf_xen_addr_calc_check(struct elf_binary *elf,
356 struct elf_dom_parms *parms)
357 {
358 if ( (parms->elf_paddr_offset != UNSET_ADDR) &&
359 (parms->virt_base == UNSET_ADDR) )
360 {
361 elf_err(elf, "%s: ERROR: ELF_PADDR_OFFSET set, VIRT_BASE unset\n",
362 __FUNCTION__);
363 return -1;
364 }
366 /* Initial guess for virt_base is 0 if it is not explicitly defined. */
367 if ( parms->virt_base == UNSET_ADDR )
368 {
369 parms->virt_base = 0;
370 elf_msg(elf, "%s: VIRT_BASE unset, using 0x%" PRIx64 "\n",
371 __FUNCTION__, parms->virt_base);
372 }
374 /*
375 * If we are using the legacy __xen_guest section then elf_pa_off
376 * defaults to v_start in order to maintain compatibility with
377 * older hypervisors which set padd in the ELF header to
378 * virt_base.
379 *
380 * If we are using the modern ELF notes interface then the default
381 * is 0.
382 */
383 if ( parms->elf_paddr_offset == UNSET_ADDR )
384 {
385 if ( parms->elf_note_start )
386 parms->elf_paddr_offset = 0;
387 else
388 parms->elf_paddr_offset = parms->virt_base;
389 elf_msg(elf, "%s: ELF_PADDR_OFFSET unset, using 0x%" PRIx64 "\n",
390 __FUNCTION__, parms->elf_paddr_offset);
391 }
393 parms->virt_offset = parms->virt_base - parms->elf_paddr_offset;
394 parms->virt_kstart = elf->pstart + parms->virt_offset;
395 parms->virt_kend = elf->pend + parms->virt_offset;
397 if ( parms->virt_entry == UNSET_ADDR )
398 parms->virt_entry = elf_uval(elf, elf->ehdr, e_entry);
400 if ( parms->bsd_symtab )
401 {
402 elf_parse_bsdsyms(elf, parms->virt_kend);
403 if ( elf->bsd_symtab_pend )
404 parms->virt_kend = elf->bsd_symtab_pend + parms->virt_offset;
405 }
407 elf_msg(elf, "%s: addresses:\n", __FUNCTION__);
408 elf_msg(elf, " virt_base = 0x%" PRIx64 "\n", parms->virt_base);
409 elf_msg(elf, " elf_paddr_offset = 0x%" PRIx64 "\n", parms->elf_paddr_offset);
410 elf_msg(elf, " virt_offset = 0x%" PRIx64 "\n", parms->virt_offset);
411 elf_msg(elf, " virt_kstart = 0x%" PRIx64 "\n", parms->virt_kstart);
412 elf_msg(elf, " virt_kend = 0x%" PRIx64 "\n", parms->virt_kend);
413 elf_msg(elf, " virt_entry = 0x%" PRIx64 "\n", parms->virt_entry);
414 elf_msg(elf, " p2m_base = 0x%" PRIx64 "\n", parms->p2m_base);
416 if ( (parms->virt_kstart > parms->virt_kend) ||
417 (parms->virt_entry < parms->virt_kstart) ||
418 (parms->virt_entry > parms->virt_kend) ||
419 (parms->virt_base > parms->virt_kstart) )
420 {
421 elf_err(elf, "%s: ERROR: ELF start or entries are out of bounds.\n",
422 __FUNCTION__);
423 return -1;
424 }
426 if ( (parms->p2m_base != UNSET_ADDR) &&
427 (parms->p2m_base >= parms->virt_kstart) &&
428 (parms->p2m_base < parms->virt_kend) )
429 {
430 elf_err(elf, "%s: ERROR: P->M table base is out of bounds.\n",
431 __FUNCTION__);
432 return -1;
433 }
435 return 0;
436 }
438 /* ------------------------------------------------------------------------ */
439 /* glue it all together ... */
441 int elf_xen_parse(struct elf_binary *elf,
442 struct elf_dom_parms *parms)
443 {
444 const elf_shdr *shdr;
445 const elf_phdr *phdr;
446 int xen_elfnotes = 0;
447 int i, count, rc;
449 memset(parms, 0, sizeof(*parms));
450 parms->virt_base = UNSET_ADDR;
451 parms->virt_entry = UNSET_ADDR;
452 parms->virt_hypercall = UNSET_ADDR;
453 parms->virt_hv_start_low = UNSET_ADDR;
454 parms->p2m_base = UNSET_ADDR;
455 parms->elf_paddr_offset = UNSET_ADDR;
457 /* Find and parse elf notes. */
458 count = elf_phdr_count(elf);
459 for ( i = 0; i < count; i++ )
460 {
461 phdr = elf_phdr_by_index(elf, i);
462 if ( elf_uval(elf, phdr, p_type) != PT_NOTE )
463 continue;
465 /*
466 * Some versions of binutils do not correctly set p_offset for
467 * note segments.
468 */
469 if (elf_uval(elf, phdr, p_offset) == 0)
470 continue;
472 rc = elf_xen_parse_notes(elf, parms,
473 elf_segment_start(elf, phdr),
474 elf_segment_end(elf, phdr));
475 if ( rc == -1 )
476 return -1;
478 xen_elfnotes += rc;
479 }
481 /*
482 * Fall back to any SHT_NOTE sections if no valid note segments
483 * were found.
484 */
485 if ( xen_elfnotes == 0 )
486 {
487 count = elf_shdr_count(elf);
488 for ( i = 0; i < count; i++ )
489 {
490 shdr = elf_shdr_by_index(elf, i);
492 if ( elf_uval(elf, shdr, sh_type) != SHT_NOTE )
493 continue;
495 rc = elf_xen_parse_notes(elf, parms,
496 elf_section_start(elf, shdr),
497 elf_section_end(elf, shdr));
499 if ( rc == -1 )
500 return -1;
502 if ( xen_elfnotes == 0 && rc > 0 )
503 elf_msg(elf, "%s: using notes from SHT_NOTE section\n", __FUNCTION__);
505 xen_elfnotes += rc;
506 }
508 }
510 /*
511 * Finally fall back to the __xen_guest section.
512 */
513 if ( xen_elfnotes == 0 )
514 {
515 count = elf_shdr_count(elf);
516 for ( i = 0; i < count; i++ )
517 {
518 shdr = elf_shdr_by_name(elf, "__xen_guest");
519 if ( shdr )
520 {
521 parms->guest_info = elf_section_start(elf, shdr);
522 parms->elf_note_start = NULL;
523 parms->elf_note_end = NULL;
524 elf_msg(elf, "%s: __xen_guest: \"%s\"\n", __FUNCTION__,
525 parms->guest_info);
526 elf_xen_parse_guest_info(elf, parms);
527 break;
528 }
529 }
530 }
532 if ( elf_xen_note_check(elf, parms) != 0 )
533 return -1;
534 if ( elf_xen_addr_calc_check(elf, parms) != 0 )
535 return -1;
536 return 0;
537 }
539 /*
540 * Local variables:
541 * mode: C
542 * c-set-style: "BSD"
543 * c-basic-offset: 4
544 * tab-width: 4
545 * indent-tabs-mode: nil
546 * End:
547 */