debuggers.hg

view xen/common/kexec.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 cb756381087c
children
line source
1 /******************************************************************************
2 * kexec.c - Achitecture independent kexec code for Xen
3 *
4 * Xen port written by:
5 * - Simon 'Horms' Horman <horms@verge.net.au>
6 * - Magnus Damm <magnus@valinux.co.jp>
7 */
9 #include <xen/init.h>
10 #include <xen/lib.h>
11 #include <xen/acpi.h>
12 #include <xen/ctype.h>
13 #include <xen/errno.h>
14 #include <xen/guest_access.h>
15 #include <xen/sched.h>
16 #include <xen/types.h>
17 #include <xen/kexec.h>
18 #include <xen/keyhandler.h>
19 #include <public/kexec.h>
20 #include <xen/cpumask.h>
21 #include <asm/atomic.h>
22 #include <xen/spinlock.h>
23 #include <xen/version.h>
24 #include <xen/console.h>
25 #include <xen/kexec.h>
26 #include <public/elfnote.h>
27 #include <xsm/xsm.h>
28 #ifdef CONFIG_COMPAT
29 #include <compat/kexec.h>
30 #endif
32 static DEFINE_PER_CPU_READ_MOSTLY(void *, crash_notes);
34 static Elf_Note *xen_crash_note;
36 static cpumask_t crash_saved_cpus;
38 static xen_kexec_image_t kexec_image[KEXEC_IMAGE_NR];
40 #define KEXEC_FLAG_DEFAULT_POS (KEXEC_IMAGE_NR + 0)
41 #define KEXEC_FLAG_CRASH_POS (KEXEC_IMAGE_NR + 1)
42 #define KEXEC_FLAG_IN_PROGRESS (KEXEC_IMAGE_NR + 2)
44 static unsigned long kexec_flags = 0; /* the lowest bits are for KEXEC_IMAGE... */
46 static spinlock_t kexec_lock = SPIN_LOCK_UNLOCKED;
48 static unsigned char vmcoreinfo_data[VMCOREINFO_BYTES];
49 static size_t vmcoreinfo_size = 0;
51 xen_kexec_reserve_t kexec_crash_area;
52 static struct {
53 u64 start, end;
54 unsigned long size;
55 } ranges[16] __initdata;
57 /*
58 * Parse command lines in the format
59 *
60 * crashkernel=<ramsize-range>:<size>[,...][@<offset>]
61 *
62 * with <ramsize-range> being of form
63 *
64 * <start>-[<end>]
65 *
66 * as well as the legacy ones in the format
67 *
68 * crashkernel=<size>[@<offset>]
69 */
70 static void __init parse_crashkernel(const char *str)
71 {
72 const char *cur;
74 if ( strchr(str, ':' ) )
75 {
76 unsigned int idx = 0;
78 do {
79 if ( idx >= ARRAY_SIZE(ranges) )
80 {
81 printk(XENLOG_WARNING "crashkernel: too many ranges\n");
82 cur = NULL;
83 str = strchr(str, '@');
84 break;
85 }
87 ranges[idx].start = parse_size_and_unit(cur = str + !!idx, &str);
88 if ( cur == str )
89 break;
91 if ( *str != '-' )
92 {
93 printk(XENLOG_WARNING "crashkernel: '-' expected\n");
94 break;
95 }
97 if ( *++str != ':' )
98 {
99 ranges[idx].end = parse_size_and_unit(cur = str, &str);
100 if ( cur == str )
101 break;
102 if ( ranges[idx].end <= ranges[idx].start )
103 {
104 printk(XENLOG_WARNING "crashkernel: end <= start\n");
105 break;
106 }
107 }
108 else
109 ranges[idx].end = -1;
111 if ( *str != ':' )
112 {
113 printk(XENLOG_WARNING "crashkernel: ':' expected\n");
114 break;
115 }
117 ranges[idx].size = parse_size_and_unit(cur = str + 1, &str);
118 if ( cur == str )
119 break;
121 ++idx;
122 } while ( *str == ',' );
123 if ( idx < ARRAY_SIZE(ranges) )
124 ranges[idx].size = 0;
125 }
126 else
127 kexec_crash_area.size = parse_size_and_unit(cur = str, &str);
128 if ( cur != str && *str == '@' )
129 kexec_crash_area.start = parse_size_and_unit(cur = str + 1, &str);
130 if ( cur == str )
131 printk(XENLOG_WARNING "crashkernel: memory value expected\n");
132 }
133 custom_param("crashkernel", parse_crashkernel);
135 void __init set_kexec_crash_area_size(u64 system_ram)
136 {
137 unsigned int idx;
139 for ( idx = 0; idx < ARRAY_SIZE(ranges) && !kexec_crash_area.size; ++idx )
140 {
141 if ( !ranges[idx].size )
142 break;
144 if ( ranges[idx].size >= system_ram )
145 {
146 printk(XENLOG_WARNING "crashkernel: invalid size\n");
147 continue;
148 }
150 if ( ranges[idx].start <= system_ram && ranges[idx].end > system_ram )
151 kexec_crash_area.size = ranges[idx].size;
152 }
153 }
155 static void one_cpu_only(void)
156 {
157 /* Only allow the first cpu to continue - force other cpus to spin */
158 if ( test_and_set_bit(KEXEC_FLAG_IN_PROGRESS, &kexec_flags) )
159 for ( ; ; ) ;
160 }
162 /* Save the registers in the per-cpu crash note buffer. */
163 void kexec_crash_save_cpu(void)
164 {
165 int cpu = smp_processor_id();
166 Elf_Note *note = per_cpu(crash_notes, cpu);
167 ELF_Prstatus *prstatus;
168 crash_xen_core_t *xencore;
170 if ( cpu_test_and_set(cpu, crash_saved_cpus) )
171 return;
173 prstatus = (ELF_Prstatus *)ELFNOTE_DESC(note);
175 note = ELFNOTE_NEXT(note);
176 xencore = (crash_xen_core_t *)ELFNOTE_DESC(note);
178 elf_core_save_regs(&prstatus->pr_reg, xencore);
179 }
181 /* Set up the single Xen-specific-info crash note. */
182 crash_xen_info_t *kexec_crash_save_info(void)
183 {
184 int cpu = smp_processor_id();
185 crash_xen_info_t info;
186 crash_xen_info_t *out = (crash_xen_info_t *)ELFNOTE_DESC(xen_crash_note);
188 BUG_ON(!cpu_test_and_set(cpu, crash_saved_cpus));
190 memset(&info, 0, sizeof(info));
191 info.xen_major_version = xen_major_version();
192 info.xen_minor_version = xen_minor_version();
193 info.xen_extra_version = __pa(xen_extra_version());
194 info.xen_changeset = __pa(xen_changeset());
195 info.xen_compiler = __pa(xen_compiler());
196 info.xen_compile_date = __pa(xen_compile_date());
197 info.xen_compile_time = __pa(xen_compile_time());
198 info.tainted = tainted;
200 /* Copy from guaranteed-aligned local copy to possibly-unaligned dest. */
201 memcpy(out, &info, sizeof(info));
203 return out;
204 }
206 static void kexec_common_shutdown(void)
207 {
208 watchdog_disable();
209 console_start_sync();
210 spin_debug_disable();
211 one_cpu_only();
212 acpi_dmar_reinstate();
213 }
215 void kexec_crash(void)
216 {
217 int pos;
219 pos = (test_bit(KEXEC_FLAG_CRASH_POS, &kexec_flags) != 0);
220 if ( !test_bit(KEXEC_IMAGE_CRASH_BASE + pos, &kexec_flags) )
221 return;
223 kexec_common_shutdown();
224 kexec_crash_save_cpu();
225 machine_crash_shutdown();
226 machine_kexec(&kexec_image[KEXEC_IMAGE_CRASH_BASE + pos]);
228 BUG();
229 }
231 static long kexec_reboot(void *_image)
232 {
233 xen_kexec_image_t *image = _image;
235 kexec_common_shutdown();
236 machine_reboot_kexec(image);
238 BUG();
239 return 0;
240 }
242 static void do_crashdump_trigger(unsigned char key)
243 {
244 printk("'%c' pressed -> triggering crashdump\n", key);
245 kexec_crash();
246 printk(" * no crash kernel loaded!\n");
247 }
249 static struct keyhandler crashdump_trigger_keyhandler = {
250 .u.fn = do_crashdump_trigger,
251 .desc = "trigger a crashdump"
252 };
254 static __init int register_crashdump_trigger(void)
255 {
256 register_keyhandler('C', &crashdump_trigger_keyhandler);
257 return 0;
258 }
259 __initcall(register_crashdump_trigger);
261 static void setup_note(Elf_Note *n, const char *name, int type, int descsz)
262 {
263 int l = strlen(name) + 1;
264 strlcpy(ELFNOTE_NAME(n), name, l);
265 n->namesz = l;
266 n->descsz = descsz;
267 n->type = type;
268 }
270 static int sizeof_note(const char *name, int descsz)
271 {
272 return (sizeof(Elf_Note) +
273 ELFNOTE_ALIGN(strlen(name)+1) +
274 ELFNOTE_ALIGN(descsz));
275 }
277 static int kexec_get_reserve(xen_kexec_range_t *range)
278 {
279 if ( kexec_crash_area.size > 0 && kexec_crash_area.start > 0) {
280 range->start = kexec_crash_area.start;
281 range->size = kexec_crash_area.size;
282 }
283 else
284 range->start = range->size = 0;
285 return 0;
286 }
288 static int kexec_get_cpu(xen_kexec_range_t *range)
289 {
290 int nr = range->nr;
291 int nr_bytes = 0;
293 if ( nr < 0 || nr >= NR_CPUS || !cpu_online(nr) )
294 return -EINVAL;
296 nr_bytes += sizeof_note("CORE", sizeof(ELF_Prstatus));
297 nr_bytes += sizeof_note("Xen", sizeof(crash_xen_core_t));
299 /* The Xen info note is included in CPU0's range. */
300 if ( nr == 0 )
301 nr_bytes += sizeof_note("Xen", sizeof(crash_xen_info_t));
303 if ( per_cpu(crash_notes, nr) == NULL )
304 {
305 Elf_Note *note;
307 note = per_cpu(crash_notes, nr) = xmalloc_bytes(nr_bytes);
309 if ( note == NULL )
310 return -ENOMEM;
312 /* Setup CORE note. */
313 setup_note(note, "CORE", NT_PRSTATUS, sizeof(ELF_Prstatus));
315 /* Setup Xen CORE note. */
316 note = ELFNOTE_NEXT(note);
317 setup_note(note, "Xen", XEN_ELFNOTE_CRASH_REGS, sizeof(crash_xen_core_t));
319 if (nr == 0)
320 {
321 /* Setup system wide Xen info note. */
322 xen_crash_note = note = ELFNOTE_NEXT(note);
323 setup_note(note, "Xen", XEN_ELFNOTE_CRASH_INFO, sizeof(crash_xen_info_t));
324 }
325 }
327 range->start = __pa((unsigned long)per_cpu(crash_notes, nr));
328 range->size = nr_bytes;
329 return 0;
330 }
332 static int kexec_get_vmcoreinfo(xen_kexec_range_t *range)
333 {
334 range->start = __pa((unsigned long)vmcoreinfo_data);
335 range->size = VMCOREINFO_BYTES;
336 return 0;
337 }
339 static int kexec_get_range_internal(xen_kexec_range_t *range)
340 {
341 int ret = -EINVAL;
343 switch ( range->range )
344 {
345 case KEXEC_RANGE_MA_CRASH:
346 ret = kexec_get_reserve(range);
347 break;
348 case KEXEC_RANGE_MA_CPU:
349 ret = kexec_get_cpu(range);
350 break;
351 case KEXEC_RANGE_MA_VMCOREINFO:
352 ret = kexec_get_vmcoreinfo(range);
353 break;
354 default:
355 ret = machine_kexec_get(range);
356 break;
357 }
359 return ret;
360 }
362 static int kexec_get_range(XEN_GUEST_HANDLE(void) uarg)
363 {
364 xen_kexec_range_t range;
365 int ret = -EINVAL;
367 if ( unlikely(copy_from_guest(&range, uarg, 1)) )
368 return -EFAULT;
370 ret = kexec_get_range_internal(&range);
372 if ( ret == 0 && unlikely(copy_to_guest(uarg, &range, 1)) )
373 return -EFAULT;
375 return ret;
376 }
378 static int kexec_get_range_compat(XEN_GUEST_HANDLE(void) uarg)
379 {
380 #ifdef CONFIG_COMPAT
381 xen_kexec_range_t range;
382 compat_kexec_range_t compat_range;
383 int ret = -EINVAL;
385 if ( unlikely(copy_from_guest(&compat_range, uarg, 1)) )
386 return -EFAULT;
388 XLAT_kexec_range(&range, &compat_range);
390 ret = kexec_get_range_internal(&range);
392 if ( ret == 0 ) {
393 XLAT_kexec_range(&compat_range, &range);
394 if ( unlikely(copy_to_guest(uarg, &compat_range, 1)) )
395 return -EFAULT;
396 }
398 return ret;
399 #else /* CONFIG_COMPAT */
400 return 0;
401 #endif /* CONFIG_COMPAT */
402 }
404 static int kexec_load_get_bits(int type, int *base, int *bit)
405 {
406 switch ( type )
407 {
408 case KEXEC_TYPE_DEFAULT:
409 *base = KEXEC_IMAGE_DEFAULT_BASE;
410 *bit = KEXEC_FLAG_DEFAULT_POS;
411 break;
412 case KEXEC_TYPE_CRASH:
413 *base = KEXEC_IMAGE_CRASH_BASE;
414 *bit = KEXEC_FLAG_CRASH_POS;
415 break;
416 default:
417 return -1;
418 }
419 return 0;
420 }
422 void vmcoreinfo_append_str(const char *fmt, ...)
423 {
424 va_list args;
425 char buf[0x50];
426 int r;
427 size_t note_size = sizeof(Elf_Note) + ELFNOTE_ALIGN(strlen(VMCOREINFO_NOTE_NAME) + 1);
429 if (vmcoreinfo_size + note_size + sizeof(buf) > VMCOREINFO_BYTES)
430 return;
432 va_start(args, fmt);
433 r = vsnprintf(buf, sizeof(buf), fmt, args);
434 va_end(args);
436 memcpy(&vmcoreinfo_data[note_size + vmcoreinfo_size], buf, r);
438 vmcoreinfo_size += r;
439 }
441 static void crash_save_vmcoreinfo(void)
442 {
443 size_t data_size;
445 if (vmcoreinfo_size > 0) /* already saved */
446 return;
448 data_size = VMCOREINFO_BYTES - (sizeof(Elf_Note) + ELFNOTE_ALIGN(strlen(VMCOREINFO_NOTE_NAME) + 1));
449 setup_note((Elf_Note *)vmcoreinfo_data, VMCOREINFO_NOTE_NAME, 0, data_size);
451 VMCOREINFO_PAGESIZE(PAGE_SIZE);
453 VMCOREINFO_SYMBOL(domain_list);
454 #ifndef frame_table
455 VMCOREINFO_SYMBOL(frame_table);
456 #else
457 {
458 static const void *const _frame_table = frame_table;
459 VMCOREINFO_SYMBOL_ALIAS(frame_table, _frame_table);
460 }
461 #endif
462 VMCOREINFO_SYMBOL(max_page);
464 VMCOREINFO_STRUCT_SIZE(page_info);
465 VMCOREINFO_STRUCT_SIZE(domain);
467 VMCOREINFO_OFFSET(page_info, count_info);
468 #ifdef __ia64__
469 VMCOREINFO_OFFSET_SUB(page_info, u.inuse, _domain);
470 #else
471 VMCOREINFO_OFFSET_SUB(page_info, v.inuse, _domain);
472 #endif
473 VMCOREINFO_OFFSET(domain, domain_id);
474 VMCOREINFO_OFFSET(domain, next_in_list);
476 #ifdef ARCH_CRASH_SAVE_VMCOREINFO
477 arch_crash_save_vmcoreinfo();
478 #endif
479 }
481 static int kexec_load_unload_internal(unsigned long op, xen_kexec_load_t *load)
482 {
483 xen_kexec_image_t *image;
484 int base, bit, pos;
485 int ret = 0;
487 if ( kexec_load_get_bits(load->type, &base, &bit) )
488 return -EINVAL;
490 pos = (test_bit(bit, &kexec_flags) != 0);
492 /* Load the user data into an unused image */
493 if ( op == KEXEC_CMD_kexec_load )
494 {
495 image = &kexec_image[base + !pos];
497 BUG_ON(test_bit((base + !pos), &kexec_flags)); /* must be free */
499 memcpy(image, &load->image, sizeof(*image));
501 if ( !(ret = machine_kexec_load(load->type, base + !pos, image)) )
502 {
503 /* Set image present bit */
504 set_bit((base + !pos), &kexec_flags);
506 /* Make new image the active one */
507 change_bit(bit, &kexec_flags);
508 }
510 crash_save_vmcoreinfo();
511 }
513 /* Unload the old image if present and load successful */
514 if ( ret == 0 && !test_bit(KEXEC_FLAG_IN_PROGRESS, &kexec_flags) )
515 {
516 if ( test_and_clear_bit((base + pos), &kexec_flags) )
517 {
518 image = &kexec_image[base + pos];
519 machine_kexec_unload(load->type, base + pos, image);
520 }
521 }
523 return ret;
524 }
526 static int kexec_load_unload(unsigned long op, XEN_GUEST_HANDLE(void) uarg)
527 {
528 xen_kexec_load_t load;
530 if ( unlikely(copy_from_guest(&load, uarg, 1)) )
531 return -EFAULT;
533 return kexec_load_unload_internal(op, &load);
534 }
536 static int kexec_load_unload_compat(unsigned long op,
537 XEN_GUEST_HANDLE(void) uarg)
538 {
539 #ifdef CONFIG_COMPAT
540 compat_kexec_load_t compat_load;
541 xen_kexec_load_t load;
543 if ( unlikely(copy_from_guest(&compat_load, uarg, 1)) )
544 return -EFAULT;
546 /* This is a bit dodgy, load.image is inside load,
547 * but XLAT_kexec_load (which is automatically generated)
548 * doesn't translate load.image (correctly)
549 * Just copy load->type, the only other member, manually instead.
550 *
551 * XLAT_kexec_load(&load, &compat_load);
552 */
553 load.type = compat_load.type;
554 XLAT_kexec_image(&load.image, &compat_load.image);
556 return kexec_load_unload_internal(op, &load);
557 #else /* CONFIG_COMPAT */
558 return 0;
559 #endif /* CONFIG_COMPAT */
560 }
562 static int kexec_exec(XEN_GUEST_HANDLE(void) uarg)
563 {
564 xen_kexec_exec_t exec;
565 xen_kexec_image_t *image;
566 int base, bit, pos, ret = -EINVAL;
568 if ( unlikely(copy_from_guest(&exec, uarg, 1)) )
569 return -EFAULT;
571 if ( kexec_load_get_bits(exec.type, &base, &bit) )
572 return -EINVAL;
574 pos = (test_bit(bit, &kexec_flags) != 0);
576 /* Only allow kexec/kdump into loaded images */
577 if ( !test_bit(base + pos, &kexec_flags) )
578 return -ENOENT;
580 switch (exec.type)
581 {
582 case KEXEC_TYPE_DEFAULT:
583 image = &kexec_image[base + pos];
584 ret = continue_hypercall_on_cpu(0, kexec_reboot, image);
585 break;
586 case KEXEC_TYPE_CRASH:
587 kexec_crash(); /* Does not return */
588 break;
589 }
591 return -EINVAL; /* never reached */
592 }
594 int do_kexec_op_internal(unsigned long op, XEN_GUEST_HANDLE(void) uarg,
595 int compat)
596 {
597 unsigned long flags;
598 int ret = -EINVAL;
600 if ( !IS_PRIV(current->domain) )
601 return -EPERM;
603 ret = xsm_kexec();
604 if ( ret )
605 return ret;
607 switch ( op )
608 {
609 case KEXEC_CMD_kexec_get_range:
610 if (compat)
611 ret = kexec_get_range_compat(uarg);
612 else
613 ret = kexec_get_range(uarg);
614 break;
615 case KEXEC_CMD_kexec_load:
616 case KEXEC_CMD_kexec_unload:
617 spin_lock_irqsave(&kexec_lock, flags);
618 if (!test_bit(KEXEC_FLAG_IN_PROGRESS, &kexec_flags))
619 {
620 if (compat)
621 ret = kexec_load_unload_compat(op, uarg);
622 else
623 ret = kexec_load_unload(op, uarg);
624 }
625 spin_unlock_irqrestore(&kexec_lock, flags);
626 break;
627 case KEXEC_CMD_kexec:
628 ret = kexec_exec(uarg);
629 break;
630 }
632 return ret;
633 }
635 long do_kexec_op(unsigned long op, XEN_GUEST_HANDLE(void) uarg)
636 {
637 return do_kexec_op_internal(op, uarg, 0);
638 }
640 #ifdef CONFIG_COMPAT
641 int compat_kexec_op(unsigned long op, XEN_GUEST_HANDLE(void) uarg)
642 {
643 return do_kexec_op_internal(op, uarg, 1);
644 }
645 #endif
647 /*
648 * Local variables:
649 * mode: C
650 * c-set-style: "BSD"
651 * c-basic-offset: 4
652 * tab-width: 4
653 * indent-tabs-mode: nil
654 * End:
655 */