diff options
author | Rusty Russell <rusty@rustcorp.com.au> | 2007-10-21 21:03:26 -0400 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2007-10-23 01:49:50 -0400 |
commit | 3c6b5bfa3cf3b4057788e08482a468cc3bc00780 (patch) | |
tree | f0d67890f6f8c9d0840c9b19a483ec06cbf822ef /drivers/lguest | |
parent | 6649bb7af6a819b675bfcf22ab704737e905645a (diff) |
Introduce guest mem offset, static link example launcher
In order to avoid problematic special linking of the Launcher, we give
the Host an offset: this means we can use any memory region in the
Launcher as Guest memory rather than insisting on mmap() at 0.
The result is quite pleasing: a number of casts are replaced with
simple additions.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'drivers/lguest')
-rw-r--r-- | drivers/lguest/core.c | 22 | ||||
-rw-r--r-- | drivers/lguest/hypercalls.c | 15 | ||||
-rw-r--r-- | drivers/lguest/io.c | 18 | ||||
-rw-r--r-- | drivers/lguest/lg.h | 3 | ||||
-rw-r--r-- | drivers/lguest/lguest_user.c | 23 | ||||
-rw-r--r-- | drivers/lguest/page_tables.c | 7 |
6 files changed, 50 insertions, 38 deletions
diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c index a0788c12b392..eb95860cf098 100644 --- a/drivers/lguest/core.c +++ b/drivers/lguest/core.c | |||
@@ -325,8 +325,8 @@ static int emulate_insn(struct lguest *lg) | |||
325 | * Dealing With Guest Memory. | 325 | * Dealing With Guest Memory. |
326 | * | 326 | * |
327 | * When the Guest gives us (what it thinks is) a physical address, we can use | 327 | * When the Guest gives us (what it thinks is) a physical address, we can use |
328 | * the normal copy_from_user() & copy_to_user() on that address: remember, | 328 | * the normal copy_from_user() & copy_to_user() on the corresponding place in |
329 | * Guest physical == Launcher virtual. | 329 | * the memory region allocated by the Launcher. |
330 | * | 330 | * |
331 | * But we can't trust the Guest: it might be trying to access the Launcher | 331 | * But we can't trust the Guest: it might be trying to access the Launcher |
332 | * code. We have to check that the range is below the pfn_limit the Launcher | 332 | * code. We have to check that the range is below the pfn_limit the Launcher |
@@ -348,8 +348,8 @@ u32 lgread_u32(struct lguest *lg, unsigned long addr) | |||
348 | 348 | ||
349 | /* Don't let them access lguest binary. */ | 349 | /* Don't let them access lguest binary. */ |
350 | if (!lguest_address_ok(lg, addr, sizeof(val)) | 350 | if (!lguest_address_ok(lg, addr, sizeof(val)) |
351 | || get_user(val, (u32 __user *)addr) != 0) | 351 | || get_user(val, (u32 *)(lg->mem_base + addr)) != 0) |
352 | kill_guest(lg, "bad read address %#lx", addr); | 352 | kill_guest(lg, "bad read address %#lx: pfn_limit=%u membase=%p", addr, lg->pfn_limit, lg->mem_base); |
353 | return val; | 353 | return val; |
354 | } | 354 | } |
355 | 355 | ||
@@ -357,7 +357,7 @@ u32 lgread_u32(struct lguest *lg, unsigned long addr) | |||
357 | void lgwrite_u32(struct lguest *lg, unsigned long addr, u32 val) | 357 | void lgwrite_u32(struct lguest *lg, unsigned long addr, u32 val) |
358 | { | 358 | { |
359 | if (!lguest_address_ok(lg, addr, sizeof(val)) | 359 | if (!lguest_address_ok(lg, addr, sizeof(val)) |
360 | || put_user(val, (u32 __user *)addr) != 0) | 360 | || put_user(val, (u32 *)(lg->mem_base + addr)) != 0) |
361 | kill_guest(lg, "bad write address %#lx", addr); | 361 | kill_guest(lg, "bad write address %#lx", addr); |
362 | } | 362 | } |
363 | 363 | ||
@@ -367,7 +367,7 @@ void lgwrite_u32(struct lguest *lg, unsigned long addr, u32 val) | |||
367 | void lgread(struct lguest *lg, void *b, unsigned long addr, unsigned bytes) | 367 | void lgread(struct lguest *lg, void *b, unsigned long addr, unsigned bytes) |
368 | { | 368 | { |
369 | if (!lguest_address_ok(lg, addr, bytes) | 369 | if (!lguest_address_ok(lg, addr, bytes) |
370 | || copy_from_user(b, (void __user *)addr, bytes) != 0) { | 370 | || copy_from_user(b, lg->mem_base + addr, bytes) != 0) { |
371 | /* copy_from_user should do this, but as we rely on it... */ | 371 | /* copy_from_user should do this, but as we rely on it... */ |
372 | memset(b, 0, bytes); | 372 | memset(b, 0, bytes); |
373 | kill_guest(lg, "bad read address %#lx len %u", addr, bytes); | 373 | kill_guest(lg, "bad read address %#lx len %u", addr, bytes); |
@@ -379,7 +379,7 @@ void lgwrite(struct lguest *lg, unsigned long addr, const void *b, | |||
379 | unsigned bytes) | 379 | unsigned bytes) |
380 | { | 380 | { |
381 | if (!lguest_address_ok(lg, addr, bytes) | 381 | if (!lguest_address_ok(lg, addr, bytes) |
382 | || copy_to_user((void __user *)addr, b, bytes) != 0) | 382 | || copy_to_user(lg->mem_base + addr, b, bytes) != 0) |
383 | kill_guest(lg, "bad write address %#lx len %u", addr, bytes); | 383 | kill_guest(lg, "bad write address %#lx len %u", addr, bytes); |
384 | } | 384 | } |
385 | /* (end of memory access helper routines) :*/ | 385 | /* (end of memory access helper routines) :*/ |
@@ -616,11 +616,9 @@ int run_guest(struct lguest *lg, unsigned long __user *user) | |||
616 | * | 616 | * |
617 | * Note that if the Guest were really messed up, this | 617 | * Note that if the Guest were really messed up, this |
618 | * could happen before it's done the INITIALIZE | 618 | * could happen before it's done the INITIALIZE |
619 | * hypercall, so lg->lguest_data will be NULL, so | 619 | * hypercall, so lg->lguest_data will be NULL */ |
620 | * &lg->lguest_data->cr2 will be address 8. Writing | 620 | if (lg->lguest_data |
621 | * into that address won't hurt the Host at all, | 621 | && put_user(cr2, &lg->lguest_data->cr2)) |
622 | * though. */ | ||
623 | if (put_user(cr2, &lg->lguest_data->cr2)) | ||
624 | kill_guest(lg, "Writing cr2"); | 622 | kill_guest(lg, "Writing cr2"); |
625 | break; | 623 | break; |
626 | case 7: /* We've intercepted a Device Not Available fault. */ | 624 | case 7: /* We've intercepted a Device Not Available fault. */ |
diff --git a/drivers/lguest/hypercalls.c b/drivers/lguest/hypercalls.c index 5ecd60b54201..02e67b49ea4f 100644 --- a/drivers/lguest/hypercalls.c +++ b/drivers/lguest/hypercalls.c | |||
@@ -205,16 +205,19 @@ static void initialize(struct lguest *lg) | |||
205 | tsc_speed = 0; | 205 | tsc_speed = 0; |
206 | 206 | ||
207 | /* The pointer to the Guest's "struct lguest_data" is the only | 207 | /* The pointer to the Guest's "struct lguest_data" is the only |
208 | * argument. */ | 208 | * argument. We check that address now. */ |
209 | lg->lguest_data = (struct lguest_data __user *)lg->regs->edx; | ||
210 | /* If we check the address they gave is OK now, we can simply | ||
211 | * copy_to_user/from_user from now on rather than using lgread/lgwrite. | ||
212 | * I put this in to show that I'm not immune to writing stupid | ||
213 | * optimizations. */ | ||
214 | if (!lguest_address_ok(lg, lg->regs->edx, sizeof(*lg->lguest_data))) { | 209 | if (!lguest_address_ok(lg, lg->regs->edx, sizeof(*lg->lguest_data))) { |
215 | kill_guest(lg, "bad guest page %p", lg->lguest_data); | 210 | kill_guest(lg, "bad guest page %p", lg->lguest_data); |
216 | return; | 211 | return; |
217 | } | 212 | } |
213 | |||
214 | /* Having checked it, we simply set lg->lguest_data to point straight | ||
215 | * into the Launcher's memory at the right place and then use | ||
216 | * copy_to_user/from_user from now on, instead of lgread/write. I put | ||
217 | * this in to show that I'm not immune to writing stupid | ||
218 | * optimizations. */ | ||
219 | lg->lguest_data = lg->mem_base + lg->regs->edx; | ||
220 | |||
218 | /* The Guest tells us where we're not to deliver interrupts by putting | 221 | /* The Guest tells us where we're not to deliver interrupts by putting |
219 | * the range of addresses into "struct lguest_data". */ | 222 | * the range of addresses into "struct lguest_data". */ |
220 | if (get_user(lg->noirq_start, &lg->lguest_data->noirq_start) | 223 | if (get_user(lg->noirq_start, &lg->lguest_data->noirq_start) |
diff --git a/drivers/lguest/io.c b/drivers/lguest/io.c index ea68613b43f6..3a845335fee8 100644 --- a/drivers/lguest/io.c +++ b/drivers/lguest/io.c | |||
@@ -186,7 +186,7 @@ int bind_dma(struct lguest *lg, | |||
186 | * we're doing this. */ | 186 | * we're doing this. */ |
187 | mutex_lock(&lguest_lock); | 187 | mutex_lock(&lguest_lock); |
188 | down_read(fshared); | 188 | down_read(fshared); |
189 | if (get_futex_key((u32 __user *)ukey, fshared, &key) != 0) { | 189 | if (get_futex_key(lg->mem_base + ukey, fshared, &key) != 0) { |
190 | kill_guest(lg, "bad dma key %#lx", ukey); | 190 | kill_guest(lg, "bad dma key %#lx", ukey); |
191 | goto unlock; | 191 | goto unlock; |
192 | } | 192 | } |
@@ -247,7 +247,8 @@ static int lgread_other(struct lguest *lg, | |||
247 | void *buf, u32 addr, unsigned bytes) | 247 | void *buf, u32 addr, unsigned bytes) |
248 | { | 248 | { |
249 | if (!lguest_address_ok(lg, addr, bytes) | 249 | if (!lguest_address_ok(lg, addr, bytes) |
250 | || access_process_vm(lg->tsk, addr, buf, bytes, 0) != bytes) { | 250 | || access_process_vm(lg->tsk, (unsigned long)lg->mem_base + addr, |
251 | buf, bytes, 0) != bytes) { | ||
251 | memset(buf, 0, bytes); | 252 | memset(buf, 0, bytes); |
252 | kill_guest(lg, "bad address in registered DMA struct"); | 253 | kill_guest(lg, "bad address in registered DMA struct"); |
253 | return 0; | 254 | return 0; |
@@ -261,8 +262,8 @@ static int lgwrite_other(struct lguest *lg, u32 addr, | |||
261 | const void *buf, unsigned bytes) | 262 | const void *buf, unsigned bytes) |
262 | { | 263 | { |
263 | if (!lguest_address_ok(lg, addr, bytes) | 264 | if (!lguest_address_ok(lg, addr, bytes) |
264 | || (access_process_vm(lg->tsk, addr, (void *)buf, bytes, 1) | 265 | || access_process_vm(lg->tsk, (unsigned long)lg->mem_base + addr, |
265 | != bytes)) { | 266 | (void *)buf, bytes, 1) != bytes) { |
266 | kill_guest(lg, "bad address writing to registered DMA"); | 267 | kill_guest(lg, "bad address writing to registered DMA"); |
267 | return 0; | 268 | return 0; |
268 | } | 269 | } |
@@ -318,7 +319,7 @@ static u32 copy_data(struct lguest *srclg, | |||
318 | * copy_to_user_page(), and some arch's seem to need special | 319 | * copy_to_user_page(), and some arch's seem to need special |
319 | * flushes. x86 is fine. */ | 320 | * flushes. x86 is fine. */ |
320 | if (copy_from_user(maddr + (dst->addr[di] + dstoff)%PAGE_SIZE, | 321 | if (copy_from_user(maddr + (dst->addr[di] + dstoff)%PAGE_SIZE, |
321 | (void __user *)src->addr[si], len) != 0) { | 322 | srclg->mem_base+src->addr[si], len) != 0) { |
322 | /* If a copy failed, it's the source's fault. */ | 323 | /* If a copy failed, it's the source's fault. */ |
323 | kill_guest(srclg, "bad address in sending DMA"); | 324 | kill_guest(srclg, "bad address in sending DMA"); |
324 | totlen = 0; | 325 | totlen = 0; |
@@ -377,7 +378,8 @@ static u32 do_dma(struct lguest *srclg, const struct lguest_dma *src, | |||
377 | * number of pages. Note that we're holding the destination's | 378 | * number of pages. Note that we're holding the destination's |
378 | * mmap_sem, as get_user_pages() requires. */ | 379 | * mmap_sem, as get_user_pages() requires. */ |
379 | if (get_user_pages(dstlg->tsk, dstlg->mm, | 380 | if (get_user_pages(dstlg->tsk, dstlg->mm, |
380 | dst->addr[i], 1, 1, 1, pages+i, NULL) | 381 | (unsigned long)dstlg->mem_base+dst->addr[i], |
382 | 1, 1, 1, pages+i, NULL) | ||
381 | != 1) { | 383 | != 1) { |
382 | /* This means the destination gave us a bogus buffer */ | 384 | /* This means the destination gave us a bogus buffer */ |
383 | kill_guest(dstlg, "Error mapping DMA pages"); | 385 | kill_guest(dstlg, "Error mapping DMA pages"); |
@@ -493,7 +495,7 @@ again: | |||
493 | mutex_lock(&lguest_lock); | 495 | mutex_lock(&lguest_lock); |
494 | down_read(fshared); | 496 | down_read(fshared); |
495 | /* Get the futex key for the key the Guest gave us */ | 497 | /* Get the futex key for the key the Guest gave us */ |
496 | if (get_futex_key((u32 __user *)ukey, fshared, &key) != 0) { | 498 | if (get_futex_key(lg->mem_base + ukey, fshared, &key) != 0) { |
497 | kill_guest(lg, "bad sending DMA key"); | 499 | kill_guest(lg, "bad sending DMA key"); |
498 | goto unlock; | 500 | goto unlock; |
499 | } | 501 | } |
@@ -584,7 +586,7 @@ unsigned long get_dma_buffer(struct lguest *lg, | |||
584 | 586 | ||
585 | /* This can fail if it's not a valid address, or if the address is not | 587 | /* This can fail if it's not a valid address, or if the address is not |
586 | * divisible by 4 (the futex code needs that, we don't really). */ | 588 | * divisible by 4 (the futex code needs that, we don't really). */ |
587 | if (get_futex_key((u32 __user *)ukey, fshared, &key) != 0) { | 589 | if (get_futex_key(lg->mem_base + ukey, fshared, &key) != 0) { |
588 | kill_guest(lg, "bad registered DMA buffer"); | 590 | kill_guest(lg, "bad registered DMA buffer"); |
589 | goto unlock; | 591 | goto unlock; |
590 | } | 592 | } |
diff --git a/drivers/lguest/lg.h b/drivers/lguest/lg.h index 399eab852ab5..54f2c2472bec 100644 --- a/drivers/lguest/lg.h +++ b/drivers/lguest/lg.h | |||
@@ -142,6 +142,9 @@ struct lguest | |||
142 | struct mm_struct *mm; /* == tsk->mm, but that becomes NULL on exit */ | 142 | struct mm_struct *mm; /* == tsk->mm, but that becomes NULL on exit */ |
143 | u16 guestid; | 143 | u16 guestid; |
144 | u32 pfn_limit; | 144 | u32 pfn_limit; |
145 | /* This provides the offset to the base of guest-physical | ||
146 | * memory in the Launcher. */ | ||
147 | void __user *mem_base; | ||
145 | u32 page_offset; | 148 | u32 page_offset; |
146 | u32 cr2; | 149 | u32 cr2; |
147 | int halted; | 150 | int halted; |
diff --git a/drivers/lguest/lguest_user.c b/drivers/lguest/lguest_user.c index 80d1b58c7698..816d4d12a801 100644 --- a/drivers/lguest/lguest_user.c +++ b/drivers/lguest/lguest_user.c | |||
@@ -1,9 +1,9 @@ | |||
1 | /*P:200 This contains all the /dev/lguest code, whereby the userspace launcher | 1 | /*P:200 This contains all the /dev/lguest code, whereby the userspace launcher |
2 | * controls and communicates with the Guest. For example, the first write will | 2 | * controls and communicates with the Guest. For example, the first write will |
3 | * tell us the memory size, pagetable, entry point and kernel address offset. | 3 | * tell us the Guest's memory layout, pagetable, entry point and kernel address |
4 | * A read will run the Guest until a signal is pending (-EINTR), or the Guest | 4 | * offset. A read will run the Guest until something happens, such as a signal |
5 | * does a DMA out to the Launcher. Writes are also used to get a DMA buffer | 5 | * or the Guest doing a DMA out to the Launcher. Writes are also used to get a |
6 | * registered by the Guest and to send the Guest an interrupt. :*/ | 6 | * DMA buffer registered by the Guest and to send the Guest an interrupt. :*/ |
7 | #include <linux/uaccess.h> | 7 | #include <linux/uaccess.h> |
8 | #include <linux/miscdevice.h> | 8 | #include <linux/miscdevice.h> |
9 | #include <linux/fs.h> | 9 | #include <linux/fs.h> |
@@ -142,9 +142,11 @@ static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o) | |||
142 | return run_guest(lg, (unsigned long __user *)user); | 142 | return run_guest(lg, (unsigned long __user *)user); |
143 | } | 143 | } |
144 | 144 | ||
145 | /*L:020 The initialization write supplies 4 32-bit values (in addition to the | 145 | /*L:020 The initialization write supplies 5 32-bit values (in addition to the |
146 | * 32-bit LHREQ_INITIALIZE value). These are: | 146 | * 32-bit LHREQ_INITIALIZE value). These are: |
147 | * | 147 | * |
148 | * base: The start of the Guest-physical memory inside the Launcher memory. | ||
149 | * | ||
148 | * pfnlimit: The highest (Guest-physical) page number the Guest should be | 150 | * pfnlimit: The highest (Guest-physical) page number the Guest should be |
149 | * allowed to access. The Launcher has to live in Guest memory, so it sets | 151 | * allowed to access. The Launcher has to live in Guest memory, so it sets |
150 | * this to ensure the Guest can't reach it. | 152 | * this to ensure the Guest can't reach it. |
@@ -166,7 +168,7 @@ static int initialize(struct file *file, const u32 __user *input) | |||
166 | * Guest. */ | 168 | * Guest. */ |
167 | struct lguest *lg; | 169 | struct lguest *lg; |
168 | int err, i; | 170 | int err, i; |
169 | u32 args[4]; | 171 | u32 args[5]; |
170 | 172 | ||
171 | /* We grab the Big Lguest lock, which protects the global array | 173 | /* We grab the Big Lguest lock, which protects the global array |
172 | * "lguests" and multiple simultaneous initializations. */ | 174 | * "lguests" and multiple simultaneous initializations. */ |
@@ -194,8 +196,9 @@ static int initialize(struct file *file, const u32 __user *input) | |||
194 | 196 | ||
195 | /* Populate the easy fields of our "struct lguest" */ | 197 | /* Populate the easy fields of our "struct lguest" */ |
196 | lg->guestid = i; | 198 | lg->guestid = i; |
197 | lg->pfn_limit = args[0]; | 199 | lg->mem_base = (void __user *)(long)args[0]; |
198 | lg->page_offset = args[3]; | 200 | lg->pfn_limit = args[1]; |
201 | lg->page_offset = args[4]; | ||
199 | 202 | ||
200 | /* We need a complete page for the Guest registers: they are accessible | 203 | /* We need a complete page for the Guest registers: they are accessible |
201 | * to the Guest and we can only grant it access to whole pages. */ | 204 | * to the Guest and we can only grant it access to whole pages. */ |
@@ -210,13 +213,13 @@ static int initialize(struct file *file, const u32 __user *input) | |||
210 | /* Initialize the Guest's shadow page tables, using the toplevel | 213 | /* Initialize the Guest's shadow page tables, using the toplevel |
211 | * address the Launcher gave us. This allocates memory, so can | 214 | * address the Launcher gave us. This allocates memory, so can |
212 | * fail. */ | 215 | * fail. */ |
213 | err = init_guest_pagetable(lg, args[1]); | 216 | err = init_guest_pagetable(lg, args[2]); |
214 | if (err) | 217 | if (err) |
215 | goto free_regs; | 218 | goto free_regs; |
216 | 219 | ||
217 | /* Now we initialize the Guest's registers, handing it the start | 220 | /* Now we initialize the Guest's registers, handing it the start |
218 | * address. */ | 221 | * address. */ |
219 | setup_regs(lg->regs, args[2]); | 222 | setup_regs(lg->regs, args[3]); |
220 | 223 | ||
221 | /* There are a couple of GDT entries the Guest expects when first | 224 | /* There are a couple of GDT entries the Guest expects when first |
222 | * booting. */ | 225 | * booting. */ |
diff --git a/drivers/lguest/page_tables.c b/drivers/lguest/page_tables.c index b7a924ace684..9cd2faceb87c 100644 --- a/drivers/lguest/page_tables.c +++ b/drivers/lguest/page_tables.c | |||
@@ -152,7 +152,7 @@ static unsigned long get_pfn(unsigned long virtpfn, int write) | |||
152 | static spte_t gpte_to_spte(struct lguest *lg, gpte_t gpte, int write) | 152 | static spte_t gpte_to_spte(struct lguest *lg, gpte_t gpte, int write) |
153 | { | 153 | { |
154 | spte_t spte; | 154 | spte_t spte; |
155 | unsigned long pfn; | 155 | unsigned long pfn, base; |
156 | 156 | ||
157 | /* The Guest sets the global flag, because it thinks that it is using | 157 | /* The Guest sets the global flag, because it thinks that it is using |
158 | * PGE. We only told it to use PGE so it would tell us whether it was | 158 | * PGE. We only told it to use PGE so it would tell us whether it was |
@@ -160,11 +160,14 @@ static spte_t gpte_to_spte(struct lguest *lg, gpte_t gpte, int write) | |||
160 | * use the global bit, so throw it away. */ | 160 | * use the global bit, so throw it away. */ |
161 | spte.flags = (gpte.flags & ~_PAGE_GLOBAL); | 161 | spte.flags = (gpte.flags & ~_PAGE_GLOBAL); |
162 | 162 | ||
163 | /* The Guest's pages are offset inside the Launcher. */ | ||
164 | base = (unsigned long)lg->mem_base / PAGE_SIZE; | ||
165 | |||
163 | /* We need a temporary "unsigned long" variable to hold the answer from | 166 | /* We need a temporary "unsigned long" variable to hold the answer from |
164 | * get_pfn(), because it returns 0xFFFFFFFF on failure, which wouldn't | 167 | * get_pfn(), because it returns 0xFFFFFFFF on failure, which wouldn't |
165 | * fit in spte.pfn. get_pfn() finds the real physical number of the | 168 | * fit in spte.pfn. get_pfn() finds the real physical number of the |
166 | * page, given the virtual number. */ | 169 | * page, given the virtual number. */ |
167 | pfn = get_pfn(gpte.pfn, write); | 170 | pfn = get_pfn(base + gpte.pfn, write); |
168 | if (pfn == -1UL) { | 171 | if (pfn == -1UL) { |
169 | kill_guest(lg, "failed to get page %u", gpte.pfn); | 172 | kill_guest(lg, "failed to get page %u", gpte.pfn); |
170 | /* When we destroy the Guest, we'll go through the shadow page | 173 | /* When we destroy the Guest, we'll go through the shadow page |