diff --git a/xen/arch/x86/pv/misc-hypercalls.c b/xen/arch/x86/pv/misc-hypercalls.c index 3a4e4aa460..afdcd8f5d8 100644 --- a/xen/arch/x86/pv/misc-hypercalls.c +++ b/xen/arch/x86/pv/misc-hypercalls.c @@ -68,7 +68,7 @@ long set_debugreg(struct vcpu *v, unsigned int reg, unsigned long value) switch ( reg ) { case 0 ... 3: - if ( !access_ok(value, sizeof(long)) ) + if ( !breakpoint_addr_ok(value) ) return -EPERM; v->arch.dr[reg] = value; diff --git a/xen/include/asm-x86/debugreg.h b/xen/include/asm-x86/debugreg.h index c57914efc6..cc29826524 100644 --- a/xen/include/asm-x86/debugreg.h +++ b/xen/include/asm-x86/debugreg.h @@ -77,6 +77,26 @@ asm volatile ( "mov %%db" #reg ",%0" : "=r" (__val) ); \ __val; \ }) + +/* + * Architecturally, %dr{0..3} can have any arbitrary value. However, Xen + * can't allow the guest to breakpoint the Xen address range, so we limit the + * guest to the lower canonical half, or above the Xen range in the higher + * canonical half. + * + * Breakpoint lengths are specified to mask the low order address bits, + * meaning all breakpoints are naturally aligned. With %dr7, the widest + * breakpoint is 8 bytes. With DBEXT, the widest breakpoint is 4G. Both of + * the Xen boundaries have >4G alignment. + * + * In principle we should account for HYPERVISOR_COMPAT_VIRT_START(d), but + * 64bit Xen has never enforced this for compat guests, and there's no problem + * (to Xen) if the guest breakpoints it's alias of the M2P. Skipping this + * aspect simplifies the logic, and causes us not to reject a migrating guest + * which operated fine on prior versions of Xen. + */ +#define breakpoint_addr_ok(a) __addr_ok(a) + long set_debugreg(struct vcpu *, unsigned int reg, unsigned long value); void activate_debugregs(const struct vcpu *);