From: kaf24@firebug.cl.cam.ac.uk Date: Mon, 14 Mar 2005 19:24:43 +0000 (+0000) Subject: bitkeeper revision 1.1236.25.22 (4235e4fbkgMjr8FNbH_NCE7pnfV92g) X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~17857^2~50^2~14 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=c245daead7dd9c9aaa9ffa33b009e23ad600ee0e;p=xen.git bitkeeper revision 1.1236.25.22 (4235e4fbkgMjr8FNbH_NCE7pnfV92g) Inform guest kernel whether it interrupts kernel or user context by using RPL of saved CS selector (0 == kernel context; 3 == user context). Add some security checking and enforcement to switch_to_user hypercall. --- diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index 44638b8543..5f0a0b8ece 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -655,11 +655,10 @@ static void switch_segments( (unsigned long *)regs->rsp : (unsigned long *)n->arch.kernel_sp; - /* Set the kernel-mode indicator byte at the top of RFLAGS. */ - ((char *)regs->rflags)[7] = !!(n->arch.flags & TF_kernel_mode); - if ( !(n->arch.flags & TF_kernel_mode) ) toggle_guest_mode(n); + else + regs->cs &= ~3; if ( put_user(regs->ss, rsp- 1) | put_user(regs->rsp, rsp- 2) | @@ -699,10 +698,10 @@ long do_switch_to_user(void) toggle_guest_mode(ed); regs->rip = stu.rip; - regs->cs = stu.cs; + regs->cs = stu.cs | 3; /* force guest privilege */ regs->rflags = stu.rflags; regs->rsp = stu.rsp; - regs->ss = stu.ss; + regs->ss = stu.ss | 3; /* force guest privilege */ if ( !(stu.flags & ECF_IN_SYSCALL) ) { diff --git a/xen/arch/x86/x86_32/mm.c b/xen/arch/x86/x86_32/mm.c index db77bbe8c0..2f3ce50c5c 100644 --- a/xen/arch/x86/x86_32/mm.c +++ b/xen/arch/x86/x86_32/mm.c @@ -202,8 +202,7 @@ long do_stack_switch(unsigned long ss, unsigned long esp) int nr = smp_processor_id(); struct tss_struct *t = &init_tss[nr]; - /* We need to do this check as we load and use SS on guest's behalf. */ - if ( (ss & 3) == 0 ) + if ( (ss & 3) != 1 ) return -EPERM; current->arch.kernel_ss = ss; @@ -275,21 +274,9 @@ int check_descriptor(struct desc_struct *d) if ( (b & _SEGMENT_G) ) limit <<= 12; - if ( (b & (_SEGMENT_CODE | _SEGMENT_EC)) == _SEGMENT_EC ) - { - /* - * Grows-down limit check. - * NB. limit == 0xFFFFF provides no access (if G=1). - * limit == 0x00000 provides 4GB-4kB access (if G=1). - */ - if ( (base + limit) > base ) - { - limit = -(base & PAGE_MASK); - goto truncate; - } - } - else + switch ( b & (_SEGMENT_CODE | _SEGMENT_EC) ) { + case 0: /* Data segment, grows-up */ /* * Grows-up limit check. * NB. limit == 0xFFFFF provides 4GB access (if G=1). @@ -306,6 +293,23 @@ int check_descriptor(struct desc_struct *d) d->a &= ~0x0ffff; d->a |= limit & 0x0ffff; d->b &= ~0xf0000; d->b |= limit & 0xf0000; } + goto good; + case _SEGMENT_EC: /* Data segment, grows-down */ + /* + * Grows-down limit check. + * NB. limit == 0xFFFFF provides no access (if G=1). + * limit == 0x00000 provides 4GB-4kB access (if G=1). + */ + if ( (base + limit) > base ) + { + limit = -(base & PAGE_MASK); + goto truncate; + } + goto good; + case _SEGMENT_CODE: /* Code segment, non-conforming */ + goto good; + case _SEGMENT_CODE|_SEGMENT_EC: /* Code segment, conforming */ + goto bad; } good: diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S index 912ed7b0d1..16b5850d60 100644 --- a/xen/arch/x86/x86_64/entry.S +++ b/xen/arch/x86/x86_64/entry.S @@ -162,20 +162,19 @@ process_softirqs: /* %rdx: trap_bounce, %rbx: struct exec_domain */ /* On return only %rbx is guaranteed non-clobbered. */ create_bounce_frame: - /* Push new frame at existing %rsp if already in guest-OS mode. */ - movq XREGS_rsp+8(%rsp),%rsi testb $TF_kernel_mode,EDOMAIN_thread_flags(%rbx) - /* Set kernel-mode indicator byte (RFLAGS[63:56]). */ - setnz XREGS_eflags+15(%rsp) jnz 1f /* Push new frame at registered guest-OS stack base. */ - /* Then call to C: toggle_guest_mode(current) */ movq EDOMAIN_kernel_sp(%rbx),%rsi - movq %rbx,%rdi pushq %rdx + movq %rbx,%rdi call SYMBOL_NAME(toggle_guest_mode) popq %rdx -1: movq $HYPERVISOR_VIRT_START,%rax + jmp 2f +1: /* In kernel context already: push new frame at existing %rsp. */ + movq XREGS_rsp+8(%rsp),%rsi + andb $0xfc,XREGS_cs+8(%rsp) # Indicate kernel context to guest. +2: movq $HYPERVISOR_VIRT_START,%rax cmpq %rax,%rsi jb 1f # In +ve address space? Then okay. movq $HYPERVISOR_VIRT_END+60,%rax diff --git a/xen/arch/x86/x86_64/mm.c b/xen/arch/x86/x86_64/mm.c index b0de7df329..aeee7fc0ba 100644 --- a/xen/arch/x86/x86_64/mm.c +++ b/xen/arch/x86/x86_64/mm.c @@ -287,9 +287,14 @@ int check_descriptor(struct desc_struct *d) if ( (b & _SEGMENT_DPL) != 3 ) goto bad; - /* Any code or data segment is okay. No base/limit checking. */ + /* Most code and data segments are okay. No base/limit checking. */ if ( (b & _SEGMENT_S) ) + { + /* Disallow conforming code segments. I'm not sure they're safe. */ + if ( (b & (_SEGMENT_CODE|_SEGMENT_EC)) == (_SEGMENT_CODE|_SEGMENT_EC) ) + goto bad; goto good; + } /* Invalid type 0 is harmless. It is used for 2nd half of a call gate. */ if ( (b & _SEGMENT_TYPE) == 0x000 ) diff --git a/xen/include/asm-x86/desc.h b/xen/include/asm-x86/desc.h index 39732982a0..a05bb752e9 100644 --- a/xen/include/asm-x86/desc.h +++ b/xen/include/asm-x86/desc.h @@ -6,18 +6,23 @@ #define load_TR(n) __asm__ __volatile__ ("ltr %%ax" : : "a" (__TSS(n)<<3) ) +#if defined(__x86_64__) +#define GUEST_KERNEL_RPL 3 +#elif defined(__i386__) +#define GUEST_KERNEL_RPL 1 +#endif + /* - * Guest OS must provide its own code selectors, or use the one we provide. The - * RPL must be 1, as we only create bounce frames to ring 1. Any LDT selector - * value is okay. Note that checking only the RPL is insufficient: if the - * selector is poked into an interrupt, trap or call gate then the RPL is - * ignored when the gate is accessed. + * Guest OS must provide its own code selectors, or use the one we provide. Any + * LDT selector value is okay. Note that checking only the RPL is insufficient: + * if the selector is poked into an interrupt, trap or call gate then the RPL + * is ignored when the gate is accessed. */ #define VALID_SEL(_s) \ (((((_s)>>3) < FIRST_RESERVED_GDT_ENTRY) || \ (((_s)>>3) > LAST_RESERVED_GDT_ENTRY) || \ ((_s)&4)) && \ - (((_s)&3) == 1)) + (((_s)&3) == GUEST_KERNEL_RPL)) #define VALID_CODESEL(_s) ((_s) == FLAT_KERNEL_CS || VALID_SEL(_s)) /* These are bitmasks for the high 32 bits of a descriptor table entry. */