[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v2 5/5] x86/vPIC: check values loaded from state save record
Loading is_master from the state save record can lead to out-of-bounds accesses via at least the two container_of() uses by vpic_domain() and __vpic_lock(). Make sure the value is consistent with the instance being loaded. For ->int_output (which for whatever reason isn't a 1-bit bitfield), besides bounds checking also take ->init_state into account. For ELCR follow what vpic_intercept_elcr_io()'s write path and vpic_reset() do, i.e. don't insist on the internal view of the value to be saved. Adjust vpic_elcr_mask() to allow using it easily for the new case, but still also especially in the 2nd of the uses by vpic_intercept_elcr_io()). Move the instance range check as well, leaving just an assertion in the load handler. While there also correct vpic_domain() itself, to use its parameter in both places. Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx> --- v2: Introduce separate checking function; switch to refusing to load bogus values. Re-base. --- a/xen/arch/x86/hvm/vpic.c +++ b/xen/arch/x86/hvm/vpic.c @@ -35,13 +35,13 @@ #include <asm/hvm/save.h> #define vpic_domain(v) (container_of((v), struct domain, \ - arch.hvm.vpic[!vpic->is_master])) + arch.hvm.vpic[!(v)->is_master])) #define __vpic_lock(v) &container_of((v), struct hvm_domain, \ vpic[!(v)->is_master])->irq_lock #define vpic_lock(v) spin_lock(__vpic_lock(v)) #define vpic_unlock(v) spin_unlock(__vpic_lock(v)) #define vpic_is_locked(v) spin_is_locked(__vpic_lock(v)) -#define vpic_elcr_mask(v) ((v)->is_master ? 0xf8 : 0xde) +#define vpic_elcr_mask(v, mb2) ((v)->is_master ? 0xf8 | ((mb2) << 2) : 0xde) /* Return the highest priority found in mask. Return 8 if none. */ #define VPIC_PRIO_NONE 8 @@ -387,7 +387,7 @@ static int cf_check vpic_intercept_elcr_ if ( dir == IOREQ_WRITE ) { /* Some IRs are always edge trig. Slave IR is always level trig. */ - data = (*val >> shift) & vpic_elcr_mask(vpic); + data = (*val >> shift) & vpic_elcr_mask(vpic, 1); if ( vpic->is_master ) data |= 1 << 2; vpic->elcr = data; @@ -395,7 +395,7 @@ static int cf_check vpic_intercept_elcr_ else { /* Reader should not see hardcoded level-triggered slave IR. */ - data = vpic->elcr & vpic_elcr_mask(vpic); + data = vpic->elcr & vpic_elcr_mask(vpic, 0); if ( !shift ) *val = data; else @@ -429,6 +429,38 @@ static int cf_check vpic_save(struct vcp return 0; } +static int cf_check vpic_check(const struct domain *d, hvm_domain_context_t *h) +{ + unsigned int inst = hvm_load_instance(h); + const struct hvm_hw_vpic *s; + + if ( !has_vpic(d) ) + return -ENODEV; + + /* Which PIC is this? */ + if ( inst >= ARRAY_SIZE(d->arch.hvm.vpic) ) + return -ENOENT; + + s = hvm_point_entry(PIC, h); + if ( !s ) + return -ENODATA; + + /* + * Check to-be-loaded values are within valid range, for them to represent + * actually reachable state. Uses of some of the values elsewhere assume + * this is the case. + */ + if ( s->int_output > 1 ) + return -EDOM; + + if ( s->is_master != !inst || + (s->int_output && s->init_state) || + (s->elcr & ~vpic_elcr_mask(s, 1)) ) + return -EINVAL; + + return 0; +} + static int cf_check vpic_load(struct domain *d, hvm_domain_context_t *h) { struct hvm_hw_vpic *s; @@ -438,18 +470,21 @@ static int cf_check vpic_load(struct dom return -ENODEV; /* Which PIC is this? */ - if ( inst > 1 ) - return -ENOENT; + ASSERT(inst < ARRAY_SIZE(d->arch.hvm.vpic)); s = &d->arch.hvm.vpic[inst]; /* Load the state */ if ( hvm_load_entry(PIC, h, s) != 0 ) return -EINVAL; + if ( s->is_master ) + s->elcr |= 1 << 2; + return 0; } -HVM_REGISTER_SAVE_RESTORE(PIC, vpic_save, NULL, vpic_load, 2, HVMSR_PER_DOM); +HVM_REGISTER_SAVE_RESTORE(PIC, vpic_save, vpic_check, vpic_load, 2, + HVMSR_PER_DOM); void vpic_reset(struct domain *d) {
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |