diff options
Diffstat (limited to 'drivers/lguest')
-rw-r--r-- | drivers/lguest/core.c | 5 | ||||
-rw-r--r-- | drivers/lguest/interrupts_and_traps.c | 9 | ||||
-rw-r--r-- | drivers/lguest/lguest.c | 5 | ||||
-rw-r--r-- | drivers/lguest/segments.c | 62 | ||||
-rw-r--r-- | drivers/lguest/switcher.S | 15 |
5 files changed, 29 insertions, 67 deletions
diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c index 0a46e8837d9a..4a315f08a567 100644 --- a/drivers/lguest/core.c +++ b/drivers/lguest/core.c | |||
@@ -453,6 +453,11 @@ static void run_guest_once(struct lguest *lg, struct lguest_pages *pages) | |||
453 | * lguest_pages". */ | 453 | * lguest_pages". */ |
454 | copy_in_guest_info(lg, pages); | 454 | copy_in_guest_info(lg, pages); |
455 | 455 | ||
456 | /* Set the trap number to 256 (impossible value). If we fault while | ||
457 | * switching to the Guest (bad segment registers or bug), this will | ||
458 | * cause us to abort the Guest. */ | ||
459 | lg->regs->trapnum = 256; | ||
460 | |||
456 | /* Now: we push the "eflags" register on the stack, then do an "lcall". | 461 | /* Now: we push the "eflags" register on the stack, then do an "lcall". |
457 | * This is how we change from using the kernel code segment to using | 462 | * This is how we change from using the kernel code segment to using |
458 | * the dedicated lguest code segment, as well as jumping into the | 463 | * the dedicated lguest code segment, as well as jumping into the |
diff --git a/drivers/lguest/interrupts_and_traps.c b/drivers/lguest/interrupts_and_traps.c index 49787e964a0d..49aa55577d0d 100644 --- a/drivers/lguest/interrupts_and_traps.c +++ b/drivers/lguest/interrupts_and_traps.c | |||
@@ -195,13 +195,16 @@ static int has_err(unsigned int trap) | |||
195 | /* deliver_trap() returns true if it could deliver the trap. */ | 195 | /* deliver_trap() returns true if it could deliver the trap. */ |
196 | int deliver_trap(struct lguest *lg, unsigned int num) | 196 | int deliver_trap(struct lguest *lg, unsigned int num) |
197 | { | 197 | { |
198 | u32 lo = lg->idt[num].a, hi = lg->idt[num].b; | 198 | /* Trap numbers are always 8 bit, but we set an impossible trap number |
199 | * for traps inside the Switcher, so check that here. */ | ||
200 | if (num >= ARRAY_SIZE(lg->idt)) | ||
201 | return 0; | ||
199 | 202 | ||
200 | /* Early on the Guest hasn't set the IDT entries (or maybe it put a | 203 | /* Early on the Guest hasn't set the IDT entries (or maybe it put a |
201 | * bogus one in): if we fail here, the Guest will be killed. */ | 204 | * bogus one in): if we fail here, the Guest will be killed. */ |
202 | if (!idt_present(lo, hi)) | 205 | if (!idt_present(lg->idt[num].a, lg->idt[num].b)) |
203 | return 0; | 206 | return 0; |
204 | set_guest_interrupt(lg, lo, hi, has_err(num)); | 207 | set_guest_interrupt(lg, lg->idt[num].a, lg->idt[num].b, has_err(num)); |
205 | return 1; | 208 | return 1; |
206 | } | 209 | } |
207 | 210 | ||
diff --git a/drivers/lguest/lguest.c b/drivers/lguest/lguest.c index fb17d2757be9..524beea7fb19 100644 --- a/drivers/lguest/lguest.c +++ b/drivers/lguest/lguest.c | |||
@@ -323,9 +323,12 @@ static void lguest_write_gdt_entry(struct desc_struct *dt, | |||
323 | * __thread variables). So we have a hypercall specifically for this case. */ | 323 | * __thread variables). So we have a hypercall specifically for this case. */ |
324 | static void lguest_load_tls(struct thread_struct *t, unsigned int cpu) | 324 | static void lguest_load_tls(struct thread_struct *t, unsigned int cpu) |
325 | { | 325 | { |
326 | /* There's one problem which normal hardware doesn't have: the Host | ||
327 | * can't handle us removing entries we're currently using. So we clear | ||
328 | * the GS register here: if it's needed it'll be reloaded anyway. */ | ||
329 | loadsegment(gs, 0); | ||
326 | lazy_hcall(LHCALL_LOAD_TLS, __pa(&t->tls_array), cpu, 0); | 330 | lazy_hcall(LHCALL_LOAD_TLS, __pa(&t->tls_array), cpu, 0); |
327 | } | 331 | } |
328 | /*:*/ | ||
329 | 332 | ||
330 | /*G:038 That's enough excitement for now, back to ploughing through each of | 333 | /*G:038 That's enough excitement for now, back to ploughing through each of |
331 | * the paravirt_ops (we're about 1/3 of the way through). | 334 | * the paravirt_ops (we're about 1/3 of the way through). |
diff --git a/drivers/lguest/segments.c b/drivers/lguest/segments.c index f675a41a80da..9b81119f46e9 100644 --- a/drivers/lguest/segments.c +++ b/drivers/lguest/segments.c | |||
@@ -43,22 +43,6 @@ | |||
43 | * begin. | 43 | * begin. |
44 | */ | 44 | */ |
45 | 45 | ||
46 | /* Is the descriptor the Guest wants us to put in OK? | ||
47 | * | ||
48 | * The flag which Intel says must be zero: must be zero. The descriptor must | ||
49 | * be present, (this is actually checked earlier but is here for thorougness), | ||
50 | * and the descriptor type must be 1 (a memory segment). */ | ||
51 | static int desc_ok(const struct desc_struct *gdt) | ||
52 | { | ||
53 | return ((gdt->b & 0x00209000) == 0x00009000); | ||
54 | } | ||
55 | |||
56 | /* Is the segment present? (Otherwise it can't be used by the Guest). */ | ||
57 | static int segment_present(const struct desc_struct *gdt) | ||
58 | { | ||
59 | return gdt->b & 0x8000; | ||
60 | } | ||
61 | |||
62 | /* There are several entries we don't let the Guest set. The TSS entry is the | 46 | /* There are several entries we don't let the Guest set. The TSS entry is the |
63 | * "Task State Segment" which controls all kinds of delicate things. The | 47 | * "Task State Segment" which controls all kinds of delicate things. The |
64 | * LGUEST_CS and LGUEST_DS entries are reserved for the Switcher, and the | 48 | * LGUEST_CS and LGUEST_DS entries are reserved for the Switcher, and the |
@@ -71,37 +55,11 @@ static int ignored_gdt(unsigned int num) | |||
71 | || num == GDT_ENTRY_DOUBLEFAULT_TSS); | 55 | || num == GDT_ENTRY_DOUBLEFAULT_TSS); |
72 | } | 56 | } |
73 | 57 | ||
74 | /* If the Guest asks us to remove an entry from the GDT, we have to be careful. | 58 | /*H:610 Once the GDT has been changed, we fix the new entries up a little. We |
75 | * If one of the segment registers is pointing at that entry the Switcher will | 59 | * don't care if they're invalid: the worst that can happen is a General |
76 | * crash when it tries to reload the segment registers for the Guest. | 60 | * Protection Fault in the Switcher when it restores a Guest segment register |
77 | * | 61 | * which tries to use that entry. Then we kill the Guest for causing such a |
78 | * It doesn't make much sense for the Guest to try to remove its own code, data | 62 | * mess: the message will be "unhandled trap 256". */ |
79 | * or stack segments while they're in use: assume that's a Guest bug. If it's | ||
80 | * one of the lesser segment registers using the removed entry, we simply set | ||
81 | * that register to 0 (unusable). */ | ||
82 | static void check_segment_use(struct lguest *lg, unsigned int desc) | ||
83 | { | ||
84 | /* GDT entries are 8 bytes long, so we divide to get the index and | ||
85 | * ignore the bottom bits. */ | ||
86 | if (lg->regs->gs / 8 == desc) | ||
87 | lg->regs->gs = 0; | ||
88 | if (lg->regs->fs / 8 == desc) | ||
89 | lg->regs->fs = 0; | ||
90 | if (lg->regs->es / 8 == desc) | ||
91 | lg->regs->es = 0; | ||
92 | if (lg->regs->ds / 8 == desc | ||
93 | || lg->regs->cs / 8 == desc | ||
94 | || lg->regs->ss / 8 == desc) | ||
95 | kill_guest(lg, "Removed live GDT entry %u", desc); | ||
96 | } | ||
97 | /*:*/ | ||
98 | /*M:009 We wouldn't need to check for removal of in-use segments if we handled | ||
99 | * faults in the Switcher. However, it's probably not a worthwhile | ||
100 | * optimization. :*/ | ||
101 | |||
102 | /*H:610 Once the GDT has been changed, we look through the changed entries and | ||
103 | * see if they're OK. If not, we'll call kill_guest() and the Guest will never | ||
104 | * get to use the invalid entries. */ | ||
105 | static void fixup_gdt_table(struct lguest *lg, unsigned start, unsigned end) | 63 | static void fixup_gdt_table(struct lguest *lg, unsigned start, unsigned end) |
106 | { | 64 | { |
107 | unsigned int i; | 65 | unsigned int i; |
@@ -112,16 +70,6 @@ static void fixup_gdt_table(struct lguest *lg, unsigned start, unsigned end) | |||
112 | if (ignored_gdt(i)) | 70 | if (ignored_gdt(i)) |
113 | continue; | 71 | continue; |
114 | 72 | ||
115 | /* We could fault in switch_to_guest if they are using | ||
116 | * a removed segment. */ | ||
117 | if (!segment_present(&lg->gdt[i])) { | ||
118 | check_segment_use(lg, i); | ||
119 | continue; | ||
120 | } | ||
121 | |||
122 | if (!desc_ok(&lg->gdt[i])) | ||
123 | kill_guest(lg, "Bad GDT descriptor %i", i); | ||
124 | |||
125 | /* Segment descriptors contain a privilege level: the Guest is | 73 | /* Segment descriptors contain a privilege level: the Guest is |
126 | * sometimes careless and leaves this as 0, even though it's | 74 | * sometimes careless and leaves this as 0, even though it's |
127 | * running at privilege level 1. If so, we fix it here. */ | 75 | * running at privilege level 1. If so, we fix it here. */ |
diff --git a/drivers/lguest/switcher.S b/drivers/lguest/switcher.S index d418179ea6b5..7c9c230cc845 100644 --- a/drivers/lguest/switcher.S +++ b/drivers/lguest/switcher.S | |||
@@ -47,6 +47,7 @@ | |||
47 | // Down here in the depths of assembler code. | 47 | // Down here in the depths of assembler code. |
48 | #include <linux/linkage.h> | 48 | #include <linux/linkage.h> |
49 | #include <asm/asm-offsets.h> | 49 | #include <asm/asm-offsets.h> |
50 | #include <asm/page.h> | ||
50 | #include "lg.h" | 51 | #include "lg.h" |
51 | 52 | ||
52 | // We mark the start of the code to copy | 53 | // We mark the start of the code to copy |
@@ -182,13 +183,15 @@ ENTRY(switch_to_guest) | |||
182 | movl $(LGUEST_DS), %eax; \ | 183 | movl $(LGUEST_DS), %eax; \ |
183 | movl %eax, %ds; \ | 184 | movl %eax, %ds; \ |
184 | /* So where are we? Which CPU, which struct? \ | 185 | /* So where are we? Which CPU, which struct? \ |
185 | * The stack is our clue: our TSS sets \ | 186 | * The stack is our clue: our TSS starts \ |
186 | * It at the end of "struct lguest_pages" \ | 187 | * It at the end of "struct lguest_pages". \ |
187 | * And we then pushed and pushed and pushed Guest regs: \ | 188 | * Or we may have stumbled while restoring \ |
188 | * Now stack points atop the "struct lguest_regs". \ | 189 | * Our Guest segment regs while in switch_to_guest, \ |
189 | * Subtract that offset, and we find our struct. */ \ | 190 | * The fault pushed atop that part-unwound stack. \ |
191 | * If we round the stack down to the page start \ | ||
192 | * We're at the start of "struct lguest_pages". */ \ | ||
190 | movl %esp, %eax; \ | 193 | movl %esp, %eax; \ |
191 | subl $LGUEST_PAGES_regs, %eax; \ | 194 | andl $(~(1 << PAGE_SHIFT - 1)), %eax; \ |
192 | /* Save our trap number: the switch will obscure it \ | 195 | /* Save our trap number: the switch will obscure it \ |
193 | * (The Guest regs are not mapped here in the Host) \ | 196 | * (The Guest regs are not mapped here in the Host) \ |
194 | * %ebx holds it safe for deliver_to_host */ \ | 197 | * %ebx holds it safe for deliver_to_host */ \ |