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, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "libelf-private.h"
19
20 /* ------------------------------------------------------------------------ */
21 /* xen features */
22
23 static const char *const elf_xen_feature_names[] = {
24 [XENFEAT_writable_page_tables] = "writable_page_tables",
25 [XENFEAT_writable_descriptor_tables] = "writable_descriptor_tables",
26 [XENFEAT_auto_translated_physmap] = "auto_translated_physmap",
27 [XENFEAT_supervisor_mode_kernel] = "supervisor_mode_kernel",
28 [XENFEAT_pae_pgdir_above_4gb] = "pae_pgdir_above_4gb",
29 [XENFEAT_hvm_callback_vector] = "hvm_callback_vector",
30 [XENFEAT_dom0] = "dom0"
31 };
32 static const unsigned elf_xen_features =
33 sizeof(elf_xen_feature_names) / sizeof(elf_xen_feature_names[0]);
34
elf_xen_parse_features(const char * features,uint32_t * supported,uint32_t * required)35 elf_errorstatus elf_xen_parse_features(const char *features,
36 uint32_t *supported,
37 uint32_t *required)
38 {
39 unsigned char feature[64];
40 unsigned pos, len, i;
41
42 if ( features == NULL )
43 return 0;
44
45 for ( pos = 0; features[pos] != '\0'; pos += len )
46 {
47 elf_memset_unchecked(feature, 0, sizeof(feature));
48 for ( len = 0;; len++ )
49 {
50 if ( len >= sizeof(feature)-1 )
51 break;
52 if ( features[pos + len] == '\0' )
53 break;
54 if ( features[pos + len] == '|' )
55 {
56 len++;
57 break;
58 }
59 feature[len] = features[pos + len];
60 }
61
62 for ( i = 0; i < elf_xen_features; i++ )
63 {
64 if ( !elf_xen_feature_names[i] )
65 continue;
66 if ( feature[0] == '!' )
67 {
68 /* required */
69 if ( !strcmp(feature + 1, elf_xen_feature_names[i]) )
70 {
71 elf_xen_feature_set(i, supported);
72 if ( required )
73 elf_xen_feature_set(i, required);
74 break;
75 }
76 }
77 else
78 {
79 /* supported */
80 if ( !strcmp(feature, elf_xen_feature_names[i]) )
81 {
82 elf_xen_feature_set(i, supported);
83 break;
84 }
85 }
86 }
87 if ( i == elf_xen_features && required && feature[0] == '!' )
88 return -1;
89 }
90
91 return 0;
92 }
93
94 /* ------------------------------------------------------------------------ */
95 /* xen elf notes */
96
elf_xen_parse_note(struct elf_binary * elf,struct elf_dom_parms * parms,ELF_HANDLE_DECL (elf_note)note)97 elf_errorstatus elf_xen_parse_note(struct elf_binary *elf,
98 struct elf_dom_parms *parms,
99 ELF_HANDLE_DECL(elf_note) note)
100 {
101 /* *INDENT-OFF* */
102 static const struct {
103 char *name;
104 bool str;
105 } note_desc[] = {
106 [XEN_ELFNOTE_ENTRY] = { "ENTRY", 0},
107 [XEN_ELFNOTE_HYPERCALL_PAGE] = { "HYPERCALL_PAGE", 0},
108 [XEN_ELFNOTE_VIRT_BASE] = { "VIRT_BASE", 0},
109 [XEN_ELFNOTE_INIT_P2M] = { "INIT_P2M", 0},
110 [XEN_ELFNOTE_PADDR_OFFSET] = { "PADDR_OFFSET", 0},
111 [XEN_ELFNOTE_HV_START_LOW] = { "HV_START_LOW", 0},
112 [XEN_ELFNOTE_XEN_VERSION] = { "XEN_VERSION", 1},
113 [XEN_ELFNOTE_GUEST_OS] = { "GUEST_OS", 1},
114 [XEN_ELFNOTE_GUEST_VERSION] = { "GUEST_VERSION", 1},
115 [XEN_ELFNOTE_LOADER] = { "LOADER", 1},
116 [XEN_ELFNOTE_PAE_MODE] = { "PAE_MODE", 1},
117 [XEN_ELFNOTE_FEATURES] = { "FEATURES", 1},
118 [XEN_ELFNOTE_SUPPORTED_FEATURES] = { "SUPPORTED_FEATURES", 0},
119 [XEN_ELFNOTE_BSD_SYMTAB] = { "BSD_SYMTAB", 1},
120 [XEN_ELFNOTE_SUSPEND_CANCEL] = { "SUSPEND_CANCEL", 0 },
121 [XEN_ELFNOTE_MOD_START_PFN] = { "MOD_START_PFN", 0 },
122 [XEN_ELFNOTE_PHYS32_ENTRY] = { "PHYS32_ENTRY", 0 },
123 };
124 /* *INDENT-ON* */
125
126 const char *str = NULL;
127 uint64_t val = 0;
128 unsigned int i;
129 unsigned type = elf_uval(elf, note, type);
130
131 if ( (type >= sizeof(note_desc) / sizeof(note_desc[0])) ||
132 (note_desc[type].name == NULL) )
133 {
134 elf_msg(elf, "ELF: note: unknown (%#x)\n", type);
135 return 0;
136 }
137
138 if ( note_desc[type].str )
139 {
140 str = elf_strval(elf, elf_note_desc(elf, note));
141 if (str == NULL)
142 /* elf_strval will mark elf broken if it fails so no need to log */
143 return 0;
144 elf_msg(elf, "ELF: note: %s = \"%s\"\n", note_desc[type].name, str);
145 parms->elf_notes[type].type = XEN_ENT_STR;
146 parms->elf_notes[type].data.str = str;
147 }
148 else
149 {
150 val = elf_note_numeric(elf, note);
151 elf_msg(elf, "ELF: note: %s = %#" PRIx64 "\n", note_desc[type].name, val);
152 parms->elf_notes[type].type = XEN_ENT_LONG;
153 parms->elf_notes[type].data.num = val;
154 }
155 parms->elf_notes[type].name = note_desc[type].name;
156
157 switch ( type )
158 {
159 case XEN_ELFNOTE_LOADER:
160 safe_strcpy(parms->loader, str);
161 break;
162 case XEN_ELFNOTE_GUEST_OS:
163 safe_strcpy(parms->guest_os, str);
164 break;
165 case XEN_ELFNOTE_GUEST_VERSION:
166 safe_strcpy(parms->guest_ver, str);
167 break;
168 case XEN_ELFNOTE_XEN_VERSION:
169 safe_strcpy(parms->xen_ver, str);
170 break;
171 case XEN_ELFNOTE_PAE_MODE:
172 if ( !strcmp(str, "yes") )
173 parms->pae = XEN_PAE_EXTCR3;
174 if ( strstr(str, "bimodal") )
175 parms->pae = XEN_PAE_BIMODAL;
176 break;
177 case XEN_ELFNOTE_BSD_SYMTAB:
178 if ( !strcmp(str, "yes") )
179 parms->bsd_symtab = 1;
180 break;
181
182 case XEN_ELFNOTE_VIRT_BASE:
183 parms->virt_base = val;
184 break;
185 case XEN_ELFNOTE_ENTRY:
186 parms->virt_entry = val;
187 break;
188 case XEN_ELFNOTE_INIT_P2M:
189 parms->p2m_base = val;
190 break;
191 case XEN_ELFNOTE_MOD_START_PFN:
192 parms->unmapped_initrd = !!val;
193 break;
194 case XEN_ELFNOTE_PADDR_OFFSET:
195 parms->elf_paddr_offset = val;
196 break;
197 case XEN_ELFNOTE_HYPERCALL_PAGE:
198 parms->virt_hypercall = val;
199 break;
200 case XEN_ELFNOTE_HV_START_LOW:
201 parms->virt_hv_start_low = val;
202 break;
203
204 case XEN_ELFNOTE_FEATURES:
205 if ( elf_xen_parse_features(str, parms->f_supported,
206 parms->f_required) )
207 return -1;
208 break;
209
210 case XEN_ELFNOTE_SUPPORTED_FEATURES:
211 for ( i = 0; i < XENFEAT_NR_SUBMAPS; ++i )
212 parms->f_supported[i] |= elf_note_numeric_array(
213 elf, note, sizeof(*parms->f_supported), i);
214 break;
215
216 case XEN_ELFNOTE_PHYS32_ENTRY:
217 parms->phys_entry = val;
218 break;
219 }
220 return 0;
221 }
222
223 #define ELF_NOTE_INVALID (~0U)
224
elf_xen_parse_notes(struct elf_binary * elf,struct elf_dom_parms * parms,elf_ptrval start,elf_ptrval end,unsigned * total_note_count)225 static unsigned elf_xen_parse_notes(struct elf_binary *elf,
226 struct elf_dom_parms *parms,
227 elf_ptrval start,
228 elf_ptrval end,
229 unsigned *total_note_count)
230 {
231 unsigned xen_elfnotes = 0;
232 ELF_HANDLE_DECL(elf_note) note;
233 const char *note_name;
234
235 parms->elf_note_start = start;
236 parms->elf_note_end = end;
237 for ( note = ELF_MAKE_HANDLE(elf_note, parms->elf_note_start);
238 ELF_HANDLE_PTRVAL(note) < parms->elf_note_end;
239 note = elf_note_next(elf, note) )
240 {
241 #ifdef __XEN__
242 process_pending_softirqs();
243 #endif
244
245 if ( *total_note_count >= ELF_MAX_TOTAL_NOTE_COUNT )
246 {
247 elf_mark_broken(elf, "too many ELF notes");
248 break;
249 }
250 (*total_note_count)++;
251 note_name = elf_note_name(elf, note);
252 if ( note_name == NULL )
253 continue;
254 if ( strcmp(note_name, "Xen") )
255 continue;
256 if ( elf_xen_parse_note(elf, parms, note) )
257 return ELF_NOTE_INVALID;
258 xen_elfnotes++;
259 }
260 return xen_elfnotes;
261 }
262
263 /* ------------------------------------------------------------------------ */
264 /* __xen_guest section */
265
elf_xen_parse_guest_info(struct elf_binary * elf,struct elf_dom_parms * parms)266 elf_errorstatus elf_xen_parse_guest_info(struct elf_binary *elf,
267 struct elf_dom_parms *parms)
268 {
269 elf_ptrval h;
270 unsigned char name[32], value[128];
271 unsigned len;
272 elf_errorstatus ret = 0;
273
274 h = parms->guest_info;
275 #define STAR(h) (elf_access_unsigned(elf, (h), 0, 1))
276 while ( STAR(h) )
277 {
278 elf_memset_unchecked(name, 0, sizeof(name));
279 elf_memset_unchecked(value, 0, sizeof(value));
280 for ( len = 0;; len++, h++ )
281 {
282 if ( len >= sizeof(name)-1 )
283 break;
284 if ( STAR(h) == '\0' )
285 break;
286 if ( STAR(h) == ',' )
287 {
288 h++;
289 break;
290 }
291 if ( STAR(h) == '=' )
292 {
293 h++;
294 for ( len = 0;; len++, h++ )
295 {
296 if ( len >= sizeof(value)-1 )
297 break;
298 if ( STAR(h) == '\0' )
299 break;
300 if ( STAR(h) == ',' )
301 {
302 h++;
303 break;
304 }
305 value[len] = STAR(h);
306 }
307 break;
308 }
309 name[len] = STAR(h);
310 }
311 elf_msg(elf, "ELF: %s=\"%s\"\n", name, value);
312
313 /* strings */
314 if ( !strcmp(name, "LOADER") )
315 safe_strcpy(parms->loader, value);
316 if ( !strcmp(name, "GUEST_OS") )
317 safe_strcpy(parms->guest_os, value);
318 if ( !strcmp(name, "GUEST_VER") )
319 safe_strcpy(parms->guest_ver, value);
320 if ( !strcmp(name, "XEN_VER") )
321 safe_strcpy(parms->xen_ver, value);
322 if ( !strcmp(name, "PAE") )
323 {
324 if ( !strcmp(value, "yes[extended-cr3]") )
325 parms->pae = XEN_PAE_EXTCR3;
326 else if ( !strncmp(value, "yes", 3) )
327 parms->pae = XEN_PAE_YES;
328 }
329 if ( !strcmp(name, "BSD_SYMTAB") )
330 parms->bsd_symtab = 1;
331
332 /* longs */
333 if ( !strcmp(name, "VIRT_BASE") )
334 parms->virt_base = strtoull(value, NULL, 0);
335 if ( !strcmp(name, "VIRT_ENTRY") )
336 parms->virt_entry = strtoull(value, NULL, 0);
337 if ( !strcmp(name, "ELF_PADDR_OFFSET") )
338 parms->elf_paddr_offset = strtoull(value, NULL, 0);
339 if ( !strcmp(name, "HYPERCALL_PAGE") )
340 parms->virt_hypercall = strtoull(value, NULL, 0) << 12;
341
342 /* other */
343 if ( !strcmp(name, "FEATURES") )
344 if ( elf_xen_parse_features(value, parms->f_supported,
345 parms->f_required) )
346 {
347 ret = -1;
348 break;
349 }
350 }
351
352 if ( (parms->virt_base != UNSET_ADDR) &&
353 (parms->virt_hypercall != UNSET_ADDR) )
354 parms->virt_hypercall += parms->virt_base;
355
356 return ret;
357 }
358
359 /* ------------------------------------------------------------------------ */
360 /* sanity checks */
361
elf_xen_note_check(struct elf_binary * elf,struct elf_dom_parms * parms)362 static elf_errorstatus elf_xen_note_check(struct elf_binary *elf,
363 struct elf_dom_parms *parms)
364 {
365 if ( (ELF_PTRVAL_INVALID(parms->elf_note_start)) &&
366 (ELF_PTRVAL_INVALID(parms->guest_info)) )
367 {
368 unsigned machine = elf_uval(elf, elf->ehdr, e_machine);
369 if ( (machine == EM_386) || (machine == EM_X86_64) )
370 {
371 elf_err(elf, "ERROR: Not a Xen-ELF image: "
372 "No ELF notes or '__xen_guest' section found\n");
373 return -1;
374 }
375 return 0;
376 }
377
378 if ( elf_uval(elf, elf->ehdr, e_machine) == EM_ARM )
379 {
380 elf_msg(elf, "ELF: Not bothering with notes on ARM\n");
381 return 0;
382 }
383
384 /* PVH only requires one ELF note to be set */
385 if ( parms->phys_entry != UNSET_ADDR32 )
386 {
387 elf_msg(elf, "ELF: Found PVH image\n");
388 return 0;
389 }
390
391 /* Check the contents of the Xen notes or guest string. */
392 if ( ((strlen(parms->loader) == 0) ||
393 strncmp(parms->loader, "generic", 7)) &&
394 ((strlen(parms->guest_os) == 0) ||
395 strncmp(parms->guest_os, "linux", 5)) )
396 {
397 elf_err(elf,
398 "ERROR: Will only load images built for the generic loader or Linux images"
399 " (Not '%.*s' and '%.*s') or with PHYS32_ENTRY set\n",
400 (int)sizeof(parms->loader), parms->loader,
401 (int)sizeof(parms->guest_os), parms->guest_os);
402 return -1;
403 }
404
405 if ( (strlen(parms->xen_ver) == 0) ||
406 strncmp(parms->xen_ver, "xen-3.0", 7) )
407 {
408 elf_err(elf, "ERROR: Xen will only load images built for Xen v3.0 "
409 "(Not '%.*s')\n",
410 (int)sizeof(parms->xen_ver), parms->xen_ver);
411 return -1;
412 }
413 return 0;
414 }
415
elf_xen_addr_calc_check(struct elf_binary * elf,struct elf_dom_parms * parms)416 static elf_errorstatus elf_xen_addr_calc_check(struct elf_binary *elf,
417 struct elf_dom_parms *parms)
418 {
419 uint64_t virt_offset;
420
421 if ( (parms->elf_paddr_offset != UNSET_ADDR) &&
422 (parms->virt_base == UNSET_ADDR) )
423 {
424 elf_err(elf, "ERROR: ELF_PADDR_OFFSET set, VIRT_BASE unset\n");
425 return -1;
426 }
427
428 /* Initial guess for virt_base is 0 if it is not explicitly defined. */
429 if ( parms->virt_base == UNSET_ADDR )
430 {
431 parms->virt_base = 0;
432 elf_msg(elf, "ELF: VIRT_BASE unset, using %#" PRIx64 "\n",
433 parms->virt_base);
434 }
435
436 /*
437 * If we are using the legacy __xen_guest section then elf_pa_off
438 * defaults to v_start in order to maintain compatibility with
439 * older hypervisors which set padd in the ELF header to
440 * virt_base.
441 *
442 * If we are using the modern ELF notes interface then the default
443 * is 0.
444 */
445 if ( parms->elf_paddr_offset == UNSET_ADDR )
446 {
447 if ( parms->elf_note_start )
448 parms->elf_paddr_offset = 0;
449 else
450 parms->elf_paddr_offset = parms->virt_base;
451 elf_msg(elf, "ELF_PADDR_OFFSET unset, using %#" PRIx64 "\n",
452 parms->elf_paddr_offset);
453 }
454
455 virt_offset = parms->virt_base - parms->elf_paddr_offset;
456 parms->virt_kstart = elf->pstart + virt_offset;
457 parms->virt_kend = elf->pend + virt_offset;
458
459 if ( parms->virt_entry == UNSET_ADDR )
460 parms->virt_entry = elf_uval(elf, elf->ehdr, e_entry);
461
462 if ( parms->bsd_symtab )
463 {
464 elf_parse_bsdsyms(elf, elf->pend);
465 if ( elf->bsd_symtab_pend )
466 parms->virt_kend = elf->bsd_symtab_pend + virt_offset;
467 }
468
469 elf_msg(elf, "ELF: addresses:\n");
470 elf_msg(elf, " virt_base = 0x%" PRIx64 "\n", parms->virt_base);
471 elf_msg(elf, " elf_paddr_offset = 0x%" PRIx64 "\n", parms->elf_paddr_offset);
472 elf_msg(elf, " virt_offset = 0x%" PRIx64 "\n", virt_offset);
473 elf_msg(elf, " virt_kstart = 0x%" PRIx64 "\n", parms->virt_kstart);
474 elf_msg(elf, " virt_kend = 0x%" PRIx64 "\n", parms->virt_kend);
475 elf_msg(elf, " virt_entry = 0x%" PRIx64 "\n", parms->virt_entry);
476 elf_msg(elf, " p2m_base = 0x%" PRIx64 "\n", parms->p2m_base);
477
478 if ( (parms->virt_kstart > parms->virt_kend) ||
479 (parms->virt_entry < parms->virt_kstart) ||
480 (parms->virt_entry > parms->virt_kend) ||
481 (parms->virt_base > parms->virt_kstart) )
482 {
483 elf_err(elf, "ERROR: ELF start or entries are out of bounds\n");
484 return -1;
485 }
486
487 if ( (parms->p2m_base != UNSET_ADDR) &&
488 (parms->p2m_base >= parms->virt_kstart) &&
489 (parms->p2m_base < parms->virt_kend) )
490 {
491 elf_err(elf, "ERROR: P->M table base is out of bounds\n");
492 return -1;
493 }
494
495 return 0;
496 }
497
498 /* ------------------------------------------------------------------------ */
499 /* glue it all together ... */
500
elf_xen_parse(struct elf_binary * elf,struct elf_dom_parms * parms)501 elf_errorstatus elf_xen_parse(struct elf_binary *elf,
502 struct elf_dom_parms *parms)
503 {
504 ELF_HANDLE_DECL(elf_shdr) shdr;
505 ELF_HANDLE_DECL(elf_phdr) phdr;
506 unsigned xen_elfnotes = 0;
507 unsigned i, count, more_notes;
508 unsigned total_note_count = 0;
509
510 elf_memset_unchecked(parms, 0, sizeof(*parms));
511 parms->virt_base = UNSET_ADDR;
512 parms->virt_entry = UNSET_ADDR;
513 parms->virt_hypercall = UNSET_ADDR;
514 parms->virt_hv_start_low = UNSET_ADDR;
515 parms->p2m_base = UNSET_ADDR;
516 parms->elf_paddr_offset = UNSET_ADDR;
517 parms->phys_entry = UNSET_ADDR32;
518
519 /* Find and parse elf notes. */
520 count = elf_phdr_count(elf);
521 for ( i = 0; i < count; i++ )
522 {
523 phdr = elf_phdr_by_index(elf, i);
524 if ( !elf_access_ok(elf, ELF_HANDLE_PTRVAL(phdr), 1) )
525 /* input has an insane program header count field */
526 break;
527 if ( elf_uval(elf, phdr, p_type) != PT_NOTE )
528 continue;
529
530 /*
531 * Some versions of binutils do not correctly set p_offset for
532 * note segments.
533 */
534 if (elf_uval(elf, phdr, p_offset) == 0)
535 continue;
536
537 more_notes = elf_xen_parse_notes(elf, parms,
538 elf_segment_start(elf, phdr),
539 elf_segment_end(elf, phdr),
540 &total_note_count);
541 if ( more_notes == ELF_NOTE_INVALID )
542 return -1;
543
544 xen_elfnotes += more_notes;
545 }
546
547 /*
548 * Fall back to any SHT_NOTE sections if no valid note segments
549 * were found.
550 */
551 if ( xen_elfnotes == 0 )
552 {
553 count = elf_shdr_count(elf);
554 for ( i = 1; i < count; i++ )
555 {
556 shdr = elf_shdr_by_index(elf, i);
557 if ( !elf_access_ok(elf, ELF_HANDLE_PTRVAL(shdr), 1) )
558 /* input has an insane section header count field */
559 break;
560
561 if ( elf_uval(elf, shdr, sh_type) != SHT_NOTE )
562 continue;
563
564 more_notes = elf_xen_parse_notes(elf, parms,
565 elf_section_start(elf, shdr),
566 elf_section_end(elf, shdr),
567 &total_note_count);
568
569 if ( more_notes == ELF_NOTE_INVALID )
570 return -1;
571
572 if ( xen_elfnotes == 0 && more_notes > 0 )
573 elf_msg(elf, "ELF: using notes from SHT_NOTE section\n");
574
575 xen_elfnotes += more_notes;
576 }
577
578 }
579
580 /*
581 * Finally fall back to the __xen_guest section.
582 */
583 if ( xen_elfnotes == 0 )
584 {
585 shdr = elf_shdr_by_name(elf, "__xen_guest");
586 if ( ELF_HANDLE_VALID(shdr) )
587 {
588 parms->guest_info = elf_section_start(elf, shdr);
589 parms->elf_note_start = ELF_INVALID_PTRVAL;
590 parms->elf_note_end = ELF_INVALID_PTRVAL;
591 elf_msg(elf, "ELF: __xen_guest: \"%s\"\n",
592 elf_strfmt(elf, parms->guest_info));
593 elf_xen_parse_guest_info(elf, parms);
594 }
595 }
596
597 if ( elf_xen_note_check(elf, parms) != 0 )
598 return -1;
599 if ( elf_xen_addr_calc_check(elf, parms) != 0 )
600 return -1;
601 return 0;
602 }
603
604 /*
605 * Local variables:
606 * mode: C
607 * c-file-style: "BSD"
608 * c-basic-offset: 4
609 * tab-width: 4
610 * indent-tabs-mode: nil
611 * End:
612 */
613