aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/lguest
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/lguest')
-rw-r--r--drivers/lguest/core.c5
-rw-r--r--drivers/lguest/interrupts_and_traps.c9
-rw-r--r--drivers/lguest/lguest.c5
-rw-r--r--drivers/lguest/segments.c62
-rw-r--r--drivers/lguest/switcher.S15
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. */
196int deliver_trap(struct lguest *lg, unsigned int num) 196int 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. */
324static void lguest_load_tls(struct thread_struct *t, unsigned int cpu) 324static 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). */
51static 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). */
57static 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). */
82static 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. */
105static void fixup_gdt_table(struct lguest *lg, unsigned start, unsigned end) 63static 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 */ \