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
273 h = parms->guest_info;
274 #define STAR(h) (elf_access_unsigned(elf, (h), 0, 1))
275 while ( STAR(h) )
276 {
277 elf_memset_unchecked(name, 0, sizeof(name));
278 elf_memset_unchecked(value, 0, sizeof(value));
279 for ( len = 0;; len++, h++ )
280 {
281 if ( len >= sizeof(name)-1 )
282 break;
283 if ( STAR(h) == '\0' )
284 break;
285 if ( STAR(h) == ',' )
286 {
287 h++;
288 break;
289 }
290 if ( STAR(h) == '=' )
291 {
292 h++;
293 for ( len = 0;; len++, h++ )
294 {
295 if ( len >= sizeof(value)-1 )
296 break;
297 if ( STAR(h) == '\0' )
298 break;
299 if ( STAR(h) == ',' )
300 {
301 h++;
302 break;
303 }
304 value[len] = STAR(h);
305 }
306 break;
307 }
308 name[len] = STAR(h);
309 }
310 elf_msg(elf, "ELF: %s=\"%s\"\n", name, value);
311
312 /* strings */
313 if ( !strcmp(name, "LOADER") )
314 safe_strcpy(parms->loader, value);
315 if ( !strcmp(name, "GUEST_OS") )
316 safe_strcpy(parms->guest_os, value);
317 if ( !strcmp(name, "GUEST_VER") )
318 safe_strcpy(parms->guest_ver, value);
319 if ( !strcmp(name, "XEN_VER") )
320 safe_strcpy(parms->xen_ver, value);
321 if ( !strcmp(name, "PAE") )
322 {
323 if ( !strcmp(value, "yes[extended-cr3]") )
324 parms->pae = XEN_PAE_EXTCR3;
325 else if ( !strncmp(value, "yes", 3) )
326 parms->pae = XEN_PAE_YES;
327 }
328 if ( !strcmp(name, "BSD_SYMTAB") )
329 parms->bsd_symtab = 1;
330
331 /* longs */
332 if ( !strcmp(name, "VIRT_BASE") )
333 parms->virt_base = strtoull(value, NULL, 0);
334 if ( !strcmp(name, "VIRT_ENTRY") )
335 parms->virt_entry = strtoull(value, NULL, 0);
336 if ( !strcmp(name, "ELF_PADDR_OFFSET") )
337 parms->elf_paddr_offset = strtoull(value, NULL, 0);
338 if ( !strcmp(name, "HYPERCALL_PAGE") )
339 parms->virt_hypercall = (strtoull(value, NULL, 0) << 12) +
340 parms->virt_base;
341
342 /* other */
343 if ( !strcmp(name, "FEATURES") )
344 if ( elf_xen_parse_features(value, parms->f_supported,
345 parms->f_required) )
346 return -1;
347 }
348 return 0;
349 }
350
351 /* ------------------------------------------------------------------------ */
352 /* sanity checks */
353
elf_xen_note_check(struct elf_binary * elf,struct elf_dom_parms * parms)354 static elf_errorstatus elf_xen_note_check(struct elf_binary *elf,
355 struct elf_dom_parms *parms)
356 {
357 if ( (ELF_PTRVAL_INVALID(parms->elf_note_start)) &&
358 (ELF_PTRVAL_INVALID(parms->guest_info)) )
359 {
360 unsigned machine = elf_uval(elf, elf->ehdr, e_machine);
361 if ( (machine == EM_386) || (machine == EM_X86_64) )
362 {
363 elf_err(elf, "ERROR: Not a Xen-ELF image: "
364 "No ELF notes or '__xen_guest' section found\n");
365 return -1;
366 }
367 return 0;
368 }
369
370 if ( elf_uval(elf, elf->ehdr, e_machine) == EM_ARM )
371 {
372 elf_msg(elf, "ELF: Not bothering with notes on ARM\n");
373 return 0;
374 }
375
376 /* PVH only requires one ELF note to be set */
377 if ( parms->phys_entry != UNSET_ADDR32 )
378 {
379 elf_msg(elf, "ELF: Found PVH image\n");
380 return 0;
381 }
382
383 /* Check the contents of the Xen notes or guest string. */
384 if ( ((strlen(parms->loader) == 0) ||
385 strncmp(parms->loader, "generic", 7)) &&
386 ((strlen(parms->guest_os) == 0) ||
387 strncmp(parms->guest_os, "linux", 5)) )
388 {
389 elf_err(elf,
390 "ERROR: Will only load images built for the generic loader or Linux images"
391 " (Not '%.*s' and '%.*s') or with PHYS32_ENTRY set\n",
392 (int)sizeof(parms->loader), parms->loader,
393 (int)sizeof(parms->guest_os), parms->guest_os);
394 return -1;
395 }
396
397 if ( (strlen(parms->xen_ver) == 0) ||
398 strncmp(parms->xen_ver, "xen-3.0", 7) )
399 {
400 elf_err(elf, "ERROR: Xen will only load images built for Xen v3.0 "
401 "(Not '%.*s')\n",
402 (int)sizeof(parms->xen_ver), parms->xen_ver);
403 return -1;
404 }
405 return 0;
406 }
407
elf_xen_addr_calc_check(struct elf_binary * elf,struct elf_dom_parms * parms)408 static elf_errorstatus elf_xen_addr_calc_check(struct elf_binary *elf,
409 struct elf_dom_parms *parms)
410 {
411 uint64_t virt_offset;
412
413 if ( (parms->elf_paddr_offset != UNSET_ADDR) &&
414 (parms->virt_base == UNSET_ADDR) )
415 {
416 elf_err(elf, "ERROR: ELF_PADDR_OFFSET set, VIRT_BASE unset\n");
417 return -1;
418 }
419
420 /* Initial guess for virt_base is 0 if it is not explicitly defined. */
421 if ( parms->virt_base == UNSET_ADDR )
422 {
423 parms->virt_base = 0;
424 elf_msg(elf, "ELF: VIRT_BASE unset, using %#" PRIx64 "\n",
425 parms->virt_base);
426 }
427
428 /*
429 * If we are using the legacy __xen_guest section then elf_pa_off
430 * defaults to v_start in order to maintain compatibility with
431 * older hypervisors which set padd in the ELF header to
432 * virt_base.
433 *
434 * If we are using the modern ELF notes interface then the default
435 * is 0.
436 */
437 if ( parms->elf_paddr_offset == UNSET_ADDR )
438 {
439 if ( parms->elf_note_start )
440 parms->elf_paddr_offset = 0;
441 else
442 parms->elf_paddr_offset = parms->virt_base;
443 elf_msg(elf, "ELF_PADDR_OFFSET unset, using %#" PRIx64 "\n",
444 parms->elf_paddr_offset);
445 }
446
447 virt_offset = parms->virt_base - parms->elf_paddr_offset;
448 parms->virt_kstart = elf->pstart + virt_offset;
449 parms->virt_kend = elf->pend + virt_offset;
450
451 if ( parms->virt_entry == UNSET_ADDR )
452 parms->virt_entry = elf_uval(elf, elf->ehdr, e_entry);
453
454 if ( parms->bsd_symtab )
455 {
456 elf_parse_bsdsyms(elf, elf->pend);
457 if ( elf->bsd_symtab_pend )
458 parms->virt_kend = elf->bsd_symtab_pend + virt_offset;
459 }
460
461 elf_msg(elf, "ELF: addresses:\n");
462 elf_msg(elf, " virt_base = 0x%" PRIx64 "\n", parms->virt_base);
463 elf_msg(elf, " elf_paddr_offset = 0x%" PRIx64 "\n", parms->elf_paddr_offset);
464 elf_msg(elf, " virt_offset = 0x%" PRIx64 "\n", virt_offset);
465 elf_msg(elf, " virt_kstart = 0x%" PRIx64 "\n", parms->virt_kstart);
466 elf_msg(elf, " virt_kend = 0x%" PRIx64 "\n", parms->virt_kend);
467 elf_msg(elf, " virt_entry = 0x%" PRIx64 "\n", parms->virt_entry);
468 elf_msg(elf, " p2m_base = 0x%" PRIx64 "\n", parms->p2m_base);
469
470 if ( (parms->virt_kstart > parms->virt_kend) ||
471 (parms->virt_entry < parms->virt_kstart) ||
472 (parms->virt_entry > parms->virt_kend) ||
473 (parms->virt_base > parms->virt_kstart) )
474 {
475 elf_err(elf, "ERROR: ELF start or entries are out of bounds\n");
476 return -1;
477 }
478
479 if ( (parms->p2m_base != UNSET_ADDR) &&
480 (parms->p2m_base >= parms->virt_kstart) &&
481 (parms->p2m_base < parms->virt_kend) )
482 {
483 elf_err(elf, "ERROR: P->M table base is out of bounds\n");
484 return -1;
485 }
486
487 return 0;
488 }
489
490 /* ------------------------------------------------------------------------ */
491 /* glue it all together ... */
492
elf_xen_parse(struct elf_binary * elf,struct elf_dom_parms * parms)493 elf_errorstatus elf_xen_parse(struct elf_binary *elf,
494 struct elf_dom_parms *parms)
495 {
496 ELF_HANDLE_DECL(elf_shdr) shdr;
497 ELF_HANDLE_DECL(elf_phdr) phdr;
498 unsigned xen_elfnotes = 0;
499 unsigned i, count, more_notes;
500 unsigned total_note_count = 0;
501
502 elf_memset_unchecked(parms, 0, sizeof(*parms));
503 parms->virt_base = UNSET_ADDR;
504 parms->virt_entry = UNSET_ADDR;
505 parms->virt_hypercall = UNSET_ADDR;
506 parms->virt_hv_start_low = UNSET_ADDR;
507 parms->p2m_base = UNSET_ADDR;
508 parms->elf_paddr_offset = UNSET_ADDR;
509 parms->phys_entry = UNSET_ADDR32;
510
511 /* Find and parse elf notes. */
512 count = elf_phdr_count(elf);
513 for ( i = 0; i < count; i++ )
514 {
515 phdr = elf_phdr_by_index(elf, i);
516 if ( !elf_access_ok(elf, ELF_HANDLE_PTRVAL(phdr), 1) )
517 /* input has an insane program header count field */
518 break;
519 if ( elf_uval(elf, phdr, p_type) != PT_NOTE )
520 continue;
521
522 /*
523 * Some versions of binutils do not correctly set p_offset for
524 * note segments.
525 */
526 if (elf_uval(elf, phdr, p_offset) == 0)
527 continue;
528
529 more_notes = elf_xen_parse_notes(elf, parms,
530 elf_segment_start(elf, phdr),
531 elf_segment_end(elf, phdr),
532 &total_note_count);
533 if ( more_notes == ELF_NOTE_INVALID )
534 return -1;
535
536 xen_elfnotes += more_notes;
537 }
538
539 /*
540 * Fall back to any SHT_NOTE sections if no valid note segments
541 * were found.
542 */
543 if ( xen_elfnotes == 0 )
544 {
545 count = elf_shdr_count(elf);
546 for ( i = 1; i < count; i++ )
547 {
548 shdr = elf_shdr_by_index(elf, i);
549 if ( !elf_access_ok(elf, ELF_HANDLE_PTRVAL(shdr), 1) )
550 /* input has an insane section header count field */
551 break;
552
553 if ( elf_uval(elf, shdr, sh_type) != SHT_NOTE )
554 continue;
555
556 more_notes = elf_xen_parse_notes(elf, parms,
557 elf_section_start(elf, shdr),
558 elf_section_end(elf, shdr),
559 &total_note_count);
560
561 if ( more_notes == ELF_NOTE_INVALID )
562 return -1;
563
564 if ( xen_elfnotes == 0 && more_notes > 0 )
565 elf_msg(elf, "ELF: using notes from SHT_NOTE section\n");
566
567 xen_elfnotes += more_notes;
568 }
569
570 }
571
572 /*
573 * Finally fall back to the __xen_guest section.
574 */
575 if ( xen_elfnotes == 0 )
576 {
577 shdr = elf_shdr_by_name(elf, "__xen_guest");
578 if ( ELF_HANDLE_VALID(shdr) )
579 {
580 parms->guest_info = elf_section_start(elf, shdr);
581 parms->elf_note_start = ELF_INVALID_PTRVAL;
582 parms->elf_note_end = ELF_INVALID_PTRVAL;
583 elf_msg(elf, "ELF: __xen_guest: \"%s\"\n",
584 elf_strfmt(elf, parms->guest_info));
585 elf_xen_parse_guest_info(elf, parms);
586 }
587 }
588
589 if ( elf_xen_note_check(elf, parms) != 0 )
590 return -1;
591 if ( elf_xen_addr_calc_check(elf, parms) != 0 )
592 return -1;
593 return 0;
594 }
595
596 /*
597 * Local variables:
598 * mode: C
599 * c-file-style: "BSD"
600 * c-basic-offset: 4
601 * tab-width: 4
602 * indent-tabs-mode: nil
603 * End:
604 */
605