aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2007-10-21 21:03:35 -0400
committerRusty Russell <rusty@rustcorp.com.au>2007-10-23 01:49:53 -0400
commitc18acd73ffc209def08003a1927473096f66c5ad (patch)
treedd8e292ac8ca90b061b7e37ad6947231ced566e3
parentee3db0f2b6053b65f3b70253f5f810d9a3d67b28 (diff)
Allow guest to specify syscall vector to use.
(Based on Ron Minnich's LGUEST_PLAN9_SYSCALL patch). This patch allows Guests to specify what system call vector they want, and we try to reserve it. We only allow one non-Linux system call vector, to try to avoid DoS on the Host. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
-rw-r--r--arch/x86/lguest/boot.c1
-rw-r--r--drivers/lguest/core.c30
-rw-r--r--drivers/lguest/interrupts_and_traps.c49
-rw-r--r--drivers/lguest/lg.h3
-rw-r--r--drivers/lguest/x86/core.c4
-rw-r--r--include/linux/lguest.h3
6 files changed, 79 insertions, 11 deletions
diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c
index 1040f9b2f99..3a06b51c98a 100644
--- a/arch/x86/lguest/boot.c
+++ b/arch/x86/lguest/boot.c
@@ -87,6 +87,7 @@ struct lguest_data lguest_data = {
87 .noirq_start = (u32)lguest_noirq_start, 87 .noirq_start = (u32)lguest_noirq_start,
88 .noirq_end = (u32)lguest_noirq_end, 88 .noirq_end = (u32)lguest_noirq_end,
89 .blocked_interrupts = { 1 }, /* Block timer interrupts */ 89 .blocked_interrupts = { 1 }, /* Block timer interrupts */
90 .syscall_vec = SYSCALL_VECTOR,
90}; 91};
91static cycle_t clock_base; 92static cycle_t clock_base;
92 93
diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c
index 02556bae9e9..41b26e592d3 100644
--- a/drivers/lguest/core.c
+++ b/drivers/lguest/core.c
@@ -281,37 +281,47 @@ static int __init init(void)
281 /* First we put the Switcher up in very high virtual memory. */ 281 /* First we put the Switcher up in very high virtual memory. */
282 err = map_switcher(); 282 err = map_switcher();
283 if (err) 283 if (err)
284 return err; 284 goto out;
285 285
286 /* Now we set up the pagetable implementation for the Guests. */ 286 /* Now we set up the pagetable implementation for the Guests. */
287 err = init_pagetables(switcher_page, SHARED_SWITCHER_PAGES); 287 err = init_pagetables(switcher_page, SHARED_SWITCHER_PAGES);
288 if (err) { 288 if (err)
289 unmap_switcher(); 289 goto unmap;
290 return err;
291 }
292 290
293 /* The I/O subsystem needs some things initialized. */ 291 /* The I/O subsystem needs some things initialized. */
294 lguest_io_init(); 292 lguest_io_init();
295 293
294 /* We might need to reserve an interrupt vector. */
295 err = init_interrupts();
296 if (err)
297 goto free_pgtables;
298
296 /* /dev/lguest needs to be registered. */ 299 /* /dev/lguest needs to be registered. */
297 err = lguest_device_init(); 300 err = lguest_device_init();
298 if (err) { 301 if (err)
299 free_pagetables(); 302 goto free_interrupts;
300 unmap_switcher();
301 return err;
302 }
303 303
304 /* Finally we do some architecture-specific setup. */ 304 /* Finally we do some architecture-specific setup. */
305 lguest_arch_host_init(); 305 lguest_arch_host_init();
306 306
307 /* All good! */ 307 /* All good! */
308 return 0; 308 return 0;
309
310free_interrupts:
311 free_interrupts();
312free_pgtables:
313 free_pagetables();
314unmap:
315 unmap_switcher();
316out:
317 return err;
309} 318}
310 319
311/* Cleaning up is just the same code, backwards. With a little French. */ 320/* Cleaning up is just the same code, backwards. With a little French. */
312static void __exit fini(void) 321static void __exit fini(void)
313{ 322{
314 lguest_device_remove(); 323 lguest_device_remove();
324 free_interrupts();
315 free_pagetables(); 325 free_pagetables();
316 unmap_switcher(); 326 unmap_switcher();
317 327
diff --git a/drivers/lguest/interrupts_and_traps.c b/drivers/lguest/interrupts_and_traps.c
index fdefc0afc38..a57d757eab6 100644
--- a/drivers/lguest/interrupts_and_traps.c
+++ b/drivers/lguest/interrupts_and_traps.c
@@ -12,8 +12,14 @@
12 * them first, so we also have a way of "reflecting" them into the Guest as if 12 * them first, so we also have a way of "reflecting" them into the Guest as if
13 * they had been delivered to it directly. :*/ 13 * they had been delivered to it directly. :*/
14#include <linux/uaccess.h> 14#include <linux/uaccess.h>
15#include <linux/interrupt.h>
16#include <linux/module.h>
15#include "lg.h" 17#include "lg.h"
16 18
19/* Allow Guests to use a non-128 (ie. non-Linux) syscall trap. */
20static unsigned int syscall_vector = SYSCALL_VECTOR;
21module_param(syscall_vector, uint, 0444);
22
17/* The address of the interrupt handler is split into two bits: */ 23/* The address of the interrupt handler is split into two bits: */
18static unsigned long idt_address(u32 lo, u32 hi) 24static unsigned long idt_address(u32 lo, u32 hi)
19{ 25{
@@ -183,6 +189,47 @@ void maybe_do_interrupt(struct lguest *lg)
183 * timer interrupt. */ 189 * timer interrupt. */
184 write_timestamp(lg); 190 write_timestamp(lg);
185} 191}
192/*:*/
193
194/* Linux uses trap 128 for system calls. Plan9 uses 64, and Ron Minnich sent
195 * me a patch, so we support that too. It'd be a big step for lguest if half
196 * the Plan 9 user base were to start using it.
197 *
198 * Actually now I think of it, it's possible that Ron *is* half the Plan 9
199 * userbase. Oh well. */
200static bool could_be_syscall(unsigned int num)
201{
202 /* Normal Linux SYSCALL_VECTOR or reserved vector? */
203 return num == SYSCALL_VECTOR || num == syscall_vector;
204}
205
206/* The syscall vector it wants must be unused by Host. */
207bool check_syscall_vector(struct lguest *lg)
208{
209 u32 vector;
210
211 if (get_user(vector, &lg->lguest_data->syscall_vec))
212 return false;
213
214 return could_be_syscall(vector);
215}
216
217int init_interrupts(void)
218{
219 /* If they want some strange system call vector, reserve it now */
220 if (syscall_vector != SYSCALL_VECTOR
221 && test_and_set_bit(syscall_vector, used_vectors)) {
222 printk("lg: couldn't reserve syscall %u\n", syscall_vector);
223 return -EBUSY;
224 }
225 return 0;
226}
227
228void free_interrupts(void)
229{
230 if (syscall_vector != SYSCALL_VECTOR)
231 clear_bit(syscall_vector, used_vectors);
232}
186 233
187/*H:220 Now we've got the routines to deliver interrupts, delivering traps 234/*H:220 Now we've got the routines to deliver interrupts, delivering traps
188 * like page fault is easy. The only trick is that Intel decided that some 235 * like page fault is easy. The only trick is that Intel decided that some
@@ -224,7 +271,7 @@ static int direct_trap(unsigned int num)
224{ 271{
225 /* Hardware interrupts don't go to the Guest at all (except system 272 /* Hardware interrupts don't go to the Guest at all (except system
226 * call). */ 273 * call). */
227 if (num >= FIRST_EXTERNAL_VECTOR && num != SYSCALL_VECTOR) 274 if (num >= FIRST_EXTERNAL_VECTOR && !could_be_syscall(num))
228 return 0; 275 return 0;
229 276
230 /* The Host needs to see page faults (for shadow paging and to save the 277 /* The Host needs to see page faults (for shadow paging and to save the
diff --git a/drivers/lguest/lg.h b/drivers/lguest/lg.h
index f921684dbe5..7408cebe995 100644
--- a/drivers/lguest/lg.h
+++ b/drivers/lguest/lg.h
@@ -141,6 +141,9 @@ void copy_traps(const struct lguest *lg, struct desc_struct *idt,
141 const unsigned long *def); 141 const unsigned long *def);
142void guest_set_clockevent(struct lguest *lg, unsigned long delta); 142void guest_set_clockevent(struct lguest *lg, unsigned long delta);
143void init_clockdev(struct lguest *lg); 143void init_clockdev(struct lguest *lg);
144bool check_syscall_vector(struct lguest *lg);
145int init_interrupts(void);
146void free_interrupts(void);
144 147
145/* segments.c: */ 148/* segments.c: */
146void setup_default_gdt_entries(struct lguest_ro_state *state); 149void setup_default_gdt_entries(struct lguest_ro_state *state);
diff --git a/drivers/lguest/x86/core.c b/drivers/lguest/x86/core.c
index 84c09082f27..a125109446d 100644
--- a/drivers/lguest/x86/core.c
+++ b/drivers/lguest/x86/core.c
@@ -530,6 +530,10 @@ int lguest_arch_init_hypercalls(struct lguest *lg)
530 if (put_user(tsc_speed, &lg->lguest_data->tsc_khz)) 530 if (put_user(tsc_speed, &lg->lguest_data->tsc_khz))
531 return -EFAULT; 531 return -EFAULT;
532 532
533 /* The interrupt code might not like the system call vector. */
534 if (!check_syscall_vector(lg))
535 kill_guest(lg, "bad syscall vector");
536
533 return 0; 537 return 0;
534} 538}
535/* Now we've examined the hypercall code; our Guest can make requests. There 539/* Now we've examined the hypercall code; our Guest can make requests. There
diff --git a/include/linux/lguest.h b/include/linux/lguest.h
index 9ddac2f0a97..083052236db 100644
--- a/include/linux/lguest.h
+++ b/include/linux/lguest.h
@@ -48,6 +48,9 @@ struct lguest_data
48/* Fields initialized by the Guest at boot: */ 48/* Fields initialized by the Guest at boot: */
49 /* Instruction range to suppress interrupts even if enabled */ 49 /* Instruction range to suppress interrupts even if enabled */
50 unsigned long noirq_start, noirq_end; 50 unsigned long noirq_start, noirq_end;
51
52 /* The vector to try to use for system calls (0x40 or 0x80). */
53 unsigned int syscall_vec;
51}; 54};
52extern struct lguest_data lguest_data; 55extern struct lguest_data lguest_data;
53#endif /* __ASSEMBLY__ */ 56#endif /* __ASSEMBLY__ */