diff --git a/xen/drivers/acpi/pmstat.c b/xen/drivers/acpi/pmstat.c index f607bc110f..1b18ee378d 100644 --- a/xen/drivers/acpi/pmstat.c +++ b/xen/drivers/acpi/pmstat.c @@ -103,8 +103,14 @@ int do_get_pm_info(struct xen_sysctl_get_pmstat *op) cpufreq_residency_update(op->cpuid, pxpt->u.cur); + /* + * Avoid partial copying of 2-D array, whereas partial copying of a + * simple vector (further down) is deemed okay. + */ ct = pmpt->perf.state_count; - if ( copy_to_guest(op->u.getpx.trans_pt, pxpt->u.trans_pt, ct*ct) ) + if ( ct > op->u.getpx.total ) + ct = op->u.getpx.total; + else if ( copy_to_guest(op->u.getpx.trans_pt, pxpt->u.trans_pt, ct * ct) ) { spin_unlock(cpufreq_statistic_lock); ret = -EFAULT; diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h index 3a6e7d48f0..a0ddd1dbf5 100644 --- a/xen/include/public/sysctl.h +++ b/xen/include/public/sysctl.h @@ -205,11 +205,22 @@ typedef struct pm_px_val pm_px_val_t; DEFINE_XEN_GUEST_HANDLE(pm_px_val_t); struct pm_px_stat { - uint8_t total; /* total Px states */ + /* + * IN: Number of elements in pt, number of rows/columns in trans_pt + * (PMSTAT_get_pxstat) + * OUT: total Px states (PMSTAT_get_max_px, PMSTAT_get_pxstat) + */ + uint8_t total; uint8_t usable; /* usable Px states */ uint8_t last; /* last Px state */ uint8_t cur; /* current Px state */ - XEN_GUEST_HANDLE_64(uint64) trans_pt; /* Px transition table */ + /* + * OUT: Px transition table. This should have total * total elements. + * As it is a 2-D array, this will not be copied if input total is + * less than output total. (PMSTAT_get_pxstat) + */ + XEN_GUEST_HANDLE_64(uint64) trans_pt; + /* OUT: This should have total elements (PMSTAT_get_pxstat) */ XEN_GUEST_HANDLE_64(pm_px_val_t) pt; };