eric
2012-Mar-07 14:07 UTC
[PATCH] XENPF_set_processor_pminfo XEN_PM_CX overflows states array
Calling XENPF_set_processor_pminfo with XEN_PM_CX could cause states array in "struct acpi_processor_power" to exceed its limit. The array used to be reset (by function cpuidle_init_cpu()) for each hypercall. The patch puts it back that way and adds an assertion to make it clear in case that happens again. Signed-off-by: Eric Chanudet <eric.chanudet@eu.citrix.com> diff --git a/xen/arch/x86/acpi/cpu_idle.c b/xen/arch/x86/acpi/cpu_idle.c --- a/xen/arch/x86/acpi/cpu_idle.c +++ b/xen/arch/x86/acpi/cpu_idle.c @@ -622,19 +622,19 @@ static int cpuidle_init_cpu(int cpu) for ( i = 0; i < ACPI_PROCESSOR_MAX_POWER; i++ ) acpi_power->states[i].idx = i; - - acpi_power->states[ACPI_STATE_C1].type = ACPI_STATE_C1; - acpi_power->states[ACPI_STATE_C1].entry_method = ACPI_CSTATE_EM_HALT; - - acpi_power->states[ACPI_STATE_C0].valid = 1; - acpi_power->states[ACPI_STATE_C1].valid = 1; - - acpi_power->count = 2; - acpi_power->safe_state = &acpi_power->states[ACPI_STATE_C1]; - acpi_power->cpu = cpu; processor_powers[cpu] = acpi_power; } + acpi_power->states[ACPI_STATE_C1].type = ACPI_STATE_C1; + acpi_power->states[ACPI_STATE_C1].entry_method = ACPI_CSTATE_EM_HALT; + + acpi_power->states[ACPI_STATE_C0].valid = 1; + acpi_power->states[ACPI_STATE_C1].valid = 1; + + acpi_power->count = 2; + acpi_power->safe_state = &acpi_power->states[ACPI_STATE_C1]; + acpi_power->cpu = cpu; + if ( cpu == 0 ) { if ( boot_cpu_has(X86_FEATURE_NONSTOP_TSC) ) @@ -870,11 +870,10 @@ static void set_cx( if ( xen_cx->type == ACPI_STATE_C1 ) cx = &acpi_power->states[1]; - else - cx = &acpi_power->states[acpi_power->count]; - - if ( !cx->valid ) - acpi_power->count++; + else { + ASSERT(acpi_power->count < ACPI_PROCESSOR_MAX_POWER); + cx = &acpi_power->states[acpi_power->count++]; + } cx->valid = 1; cx->type = xen_cx->type; -- Eric Chanudet
Jan Beulich
2012-Mar-07 15:07 UTC
Re: [PATCH] XENPF_set_processor_pminfo XEN_PM_CX overflows states array
>>> On 07.03.12 at 15:07, eric <eric.chanudet@citrix.com> wrote: > Calling XENPF_set_processor_pminfo with XEN_PM_CX could cause states > array in "struct acpi_processor_power" to exceed its limit. > > The array used to be reset (by function cpuidle_init_cpu()) for each > hypercall. The patch puts it back that way and adds an assertion to make > it clear in case that happens again. > > Signed-off-by: Eric Chanudet <eric.chanudet@eu.citrix.com> > > diff --git a/xen/arch/x86/acpi/cpu_idle.c b/xen/arch/x86/acpi/cpu_idle.c > --- a/xen/arch/x86/acpi/cpu_idle.c > +++ b/xen/arch/x86/acpi/cpu_idle.c > @@ -622,19 +622,19 @@ static int cpuidle_init_cpu(int cpu) > > for ( i = 0; i < ACPI_PROCESSOR_MAX_POWER; i++ ) > acpi_power->states[i].idx = i; > - > - acpi_power->states[ACPI_STATE_C1].type = ACPI_STATE_C1; > - acpi_power->states[ACPI_STATE_C1].entry_method = ACPI_CSTATE_EM_HALT; > - > - acpi_power->states[ACPI_STATE_C0].valid = 1; > - acpi_power->states[ACPI_STATE_C1].valid = 1; > - > - acpi_power->count = 2; > - acpi_power->safe_state = &acpi_power->states[ACPI_STATE_C1]; > - acpi_power->cpu = cpu; > processor_powers[cpu] = acpi_power; > } > > + acpi_power->states[ACPI_STATE_C1].type = ACPI_STATE_C1; > + acpi_power->states[ACPI_STATE_C1].entry_method = ACPI_CSTATE_EM_HALT; > + > + acpi_power->states[ACPI_STATE_C0].valid = 1; > + acpi_power->states[ACPI_STATE_C1].valid = 1; > + > + acpi_power->count = 2; > + acpi_power->safe_state = &acpi_power->states[ACPI_STATE_C1]; > + acpi_power->cpu = cpu;Is there any reason to move all of these assignments, rather than just the assignment of ->count and maybe ->states[ACPI_STATE_C1]? Everything else should not get modified anywhere else.> + > if ( cpu == 0 ) > { > if ( boot_cpu_has(X86_FEATURE_NONSTOP_TSC) ) > @@ -870,11 +870,10 @@ static void set_cx( > > if ( xen_cx->type == ACPI_STATE_C1 ) > cx = &acpi_power->states[1]; > - else > - cx = &acpi_power->states[acpi_power->count]; > - > - if ( !cx->valid ) > - acpi_power->count++; > + else {Please put the brace on a new line.> + ASSERT(acpi_power->count < ACPI_PROCESSOR_MAX_POWER); > + cx = &acpi_power->states[acpi_power->count++]; > + }To be on the safe side, you should probably also check for ACPI_STATE_C0 (and ignore its data), otherwise (other than before your patch) ->count would get incremented for this too. So I''d suggest converting the if() here to a switch(). Jan> > cx->valid = 1; > cx->type = xen_cx->type; > > -- > Eric Chanudet > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xen.org > http://lists.xen.org/xen-devel
Eric Chanudet
2012-Mar-07 17:46 UTC
Re: [PATCH] XENPF_set_processor_pminfo XEN_PM_CX overflows states array
On Wed, Mar 07, 2012 at 10:07:55AM -0500, Jan Beulich wrote:> Is there any reason to move all of these assignments, rather than > just the assignment of ->count and maybe ->states[ACPI_STATE_C1]? > Everything else should not get modified anywhere else.I see no reason indeed, this is how it was before everything went up in the if() statement.> To be on the safe side, you should probably also check for > ACPI_STATE_C0 (and ignore its data), otherwise (other than before > your patch) ->count would get incremented for this too. So I''d > suggest converting the if() here to a switch().Done. Here is the refreshed patch. diff -r 8964c223836c xen/arch/x86/acpi/cpu_idle.c --- a/xen/arch/x86/acpi/cpu_idle.c Tue Mar 06 15:51:33 2012 +0100 +++ b/xen/arch/x86/acpi/cpu_idle.c Wed Mar 07 17:39:34 2012 +0000 @@ -645,12 +645,12 @@ acpi_power->states[ACPI_STATE_C0].valid = 1; acpi_power->states[ACPI_STATE_C1].valid = 1; + acpi_power->cpu = cpu; + processor_powers[cpu] = acpi_power; + } acpi_power->count = 2; acpi_power->safe_state = &acpi_power->states[ACPI_STATE_C1]; - acpi_power->cpu = cpu; - processor_powers[cpu] = acpi_power; - } if ( cpu == 0 ) { @@ -885,16 +885,20 @@ if ( check_cx(acpi_power, xen_cx) != 0 ) return; - if ( xen_cx->type == ACPI_STATE_C1 ) + switch (xen_cx->type) + { + case ACPI_STATE_C0: + return; + case ACPI_STATE_C1: cx = &acpi_power->states[1]; - else - cx = &acpi_power->states[acpi_power->count]; + break; + default: + ASSERT(acpi_power->count < ACPI_PROCESSOR_MAX_POWER); + cx = &acpi_power->states[acpi_power->count++]; + cx->valid = 1; + cx->type = xen_cx->type; + } - if ( !cx->valid ) - acpi_power->count++; - - cx->valid = 1; - cx->type = xen_cx->type; cx->address = xen_cx->reg.address; switch ( xen_cx->reg.space_id ) -- Eric Chanudet
Zhang, Yang Z
2012-Mar-08 00:39 UTC
Re: [PATCH] XENPF_set_processor_pminfo XEN_PM_CX overflows states array
Sorry, can you give more descriptions about this issue? I doesn''t see any problem. best regards yang> -----Original Message----- > From: xen-devel-bounces@lists.xen.org > [mailto:xen-devel-bounces@lists.xen.org] On Behalf Of eric > Sent: Wednesday, March 07, 2012 10:07 PM > To: xen-devel@lists.xen.org > Cc: julian.pidancet@eu.citrix.com > Subject: [Xen-devel] [PATCH] XENPF_set_processor_pminfo XEN_PM_CX > overflows states array > > Calling XENPF_set_processor_pminfo with XEN_PM_CX could cause states array > in "struct acpi_processor_power" to exceed its limit. > > The array used to be reset (by function cpuidle_init_cpu()) for each hypercall. > The patch puts it back that way and adds an assertion to make it clear in case that > happens again. > > Signed-off-by: Eric Chanudet <eric.chanudet@eu.citrix.com> > > diff --git a/xen/arch/x86/acpi/cpu_idle.c b/xen/arch/x86/acpi/cpu_idle.c > --- a/xen/arch/x86/acpi/cpu_idle.c > +++ b/xen/arch/x86/acpi/cpu_idle.c > @@ -622,19 +622,19 @@ static int cpuidle_init_cpu(int cpu) > > for ( i = 0; i < ACPI_PROCESSOR_MAX_POWER; i++ ) > acpi_power->states[i].idx = i; > - > - acpi_power->states[ACPI_STATE_C1].type = ACPI_STATE_C1; > - acpi_power->states[ACPI_STATE_C1].entry_method > ACPI_CSTATE_EM_HALT; > - > - acpi_power->states[ACPI_STATE_C0].valid = 1; > - acpi_power->states[ACPI_STATE_C1].valid = 1; > - > - acpi_power->count = 2; > - acpi_power->safe_state = &acpi_power->states[ACPI_STATE_C1]; > - acpi_power->cpu = cpu; > processor_powers[cpu] = acpi_power; > } > > + acpi_power->states[ACPI_STATE_C1].type = ACPI_STATE_C1; > + acpi_power->states[ACPI_STATE_C1].entry_method > + ACPI_CSTATE_EM_HALT; > + > + acpi_power->states[ACPI_STATE_C0].valid = 1; > + acpi_power->states[ACPI_STATE_C1].valid = 1; > + > + acpi_power->count = 2; > + acpi_power->safe_state = &acpi_power->states[ACPI_STATE_C1]; > + acpi_power->cpu = cpu; > + > if ( cpu == 0 ) > { > if ( boot_cpu_has(X86_FEATURE_NONSTOP_TSC) ) @@ -870,11 > +870,10 @@ static void set_cx( > > if ( xen_cx->type == ACPI_STATE_C1 ) > cx = &acpi_power->states[1]; > - else > - cx = &acpi_power->states[acpi_power->count]; > - > - if ( !cx->valid ) > - acpi_power->count++; > + else { > + ASSERT(acpi_power->count < ACPI_PROCESSOR_MAX_POWER); > + cx = &acpi_power->states[acpi_power->count++]; > + } > > cx->valid = 1; > cx->type = xen_cx->type; > > -- > Eric Chanudet > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xen.org > http://lists.xen.org/xen-devel
Jan Beulich
2012-Mar-08 08:34 UTC
Re: [PATCH] XENPF_set_processor_pminfo XEN_PM_CX overflows states array
>>> On 07.03.12 at 18:46, Eric Chanudet <eric.chanudet@eu.citrix.com> wrote: > --- a/xen/arch/x86/acpi/cpu_idle.c Tue Mar 06 15:51:33 2012 +0100 > +++ b/xen/arch/x86/acpi/cpu_idle.c Wed Mar 07 17:39:34 2012 +0000 > @@ -645,12 +645,12 @@ > > acpi_power->states[ACPI_STATE_C0].valid = 1; > acpi_power->states[ACPI_STATE_C1].valid = 1; > + acpi_power->cpu = cpu; > + processor_powers[cpu] = acpi_power; > + } > > acpi_power->count = 2; > acpi_power->safe_state = &acpi_power->states[ACPI_STATE_C1];Please fix the indentation here. Further, I''d really like to see the two C1-related lines (setting .type and .entry_method) moved out of the if() as well - if we''re getting fresh data from Dom0, we shouldn''t make assumptions on the validity of the old data.> - acpi_power->cpu = cpu; > - processor_powers[cpu] = acpi_power; > - } > > if ( cpu == 0 ) > {Further, as you''re adjusting this anyway, I think this whole if() should move into the earlier if()''s body.> @@ -885,16 +885,20 @@ > if ( check_cx(acpi_power, xen_cx) != 0 ) > return; > > - if ( xen_cx->type == ACPI_STATE_C1 ) > + switch (xen_cx->type) > + { > + case ACPI_STATE_C0: > + return; > + case ACPI_STATE_C1: > cx = &acpi_power->states[1]; > - else > - cx = &acpi_power->states[acpi_power->count]; > + break; > + default: > + ASSERT(acpi_power->count < ACPI_PROCESSOR_MAX_POWER);After some more thinking about this, I don''t see ASSERT() as a proper action here. Rather than crashing the debug hypervisor and silently corrupting data on a non-debug one, print a warning here and bail out.> + cx = &acpi_power->states[acpi_power->count++]; > + cx->valid = 1; > + cx->type = xen_cx->type; > + } > > - if ( !cx->valid ) > - acpi_power->count++; > - > - cx->valid = 1; > - cx->type = xen_cx->type; > cx->address = xen_cx->reg.address; > > switch ( xen_cx->reg.space_id )As the patch is sufficiently different from the previous version, I think you ought to re-submit with a full patch description and s-o-b line. Or maybe I should just take your patch as a basis and do the adjustments myself... Jan
Jan Beulich
2012-Mar-08 10:53 UTC
Re: [PATCH] XENPF_set_processor_pminfo XEN_PM_CX overflows states array
>>> On 08.03.12 at 01:39, "Zhang, Yang Z" <yang.z.zhang@intel.com> wrote: > Sorry, can you give more descriptions about this issue? I doesn''t see any > problem.This is pretty obvious once you know what to look for: Just consider Dom0 issues the respective hypercall twice for each CPU. cpuidle_init_cpu() in its unpatched form won''t reset acpi_power->count back to 2, yet set_cx() will continue to happily pick fresh array slots and increment the count further (unless the ->valid flag happens to be set in this uninitialized chunk of memory). Iiuc this should be easily reproducible unloading and reloading processor.ko on a XenoLinux kernel. Jan>> -----Original Message----- >> From: xen-devel-bounces@lists.xen.org >> [mailto:xen-devel-bounces@lists.xen.org] On Behalf Of eric >> Sent: Wednesday, March 07, 2012 10:07 PM >> To: xen-devel@lists.xen.org >> Cc: julian.pidancet@eu.citrix.com >> Subject: [Xen-devel] [PATCH] XENPF_set_processor_pminfo XEN_PM_CX >> overflows states array >> >> Calling XENPF_set_processor_pminfo with XEN_PM_CX could cause states array >> in "struct acpi_processor_power" to exceed its limit. >> >> The array used to be reset (by function cpuidle_init_cpu()) for each > hypercall. >> The patch puts it back that way and adds an assertion to make it clear in > case that >> happens again. >> >> Signed-off-by: Eric Chanudet <eric.chanudet@eu.citrix.com> >> >> diff --git a/xen/arch/x86/acpi/cpu_idle.c b/xen/arch/x86/acpi/cpu_idle.c >> --- a/xen/arch/x86/acpi/cpu_idle.c >> +++ b/xen/arch/x86/acpi/cpu_idle.c >> @@ -622,19 +622,19 @@ static int cpuidle_init_cpu(int cpu) >> >> for ( i = 0; i < ACPI_PROCESSOR_MAX_POWER; i++ ) >> acpi_power->states[i].idx = i; >> - >> - acpi_power->states[ACPI_STATE_C1].type = ACPI_STATE_C1; >> - acpi_power->states[ACPI_STATE_C1].entry_method >> ACPI_CSTATE_EM_HALT; >> - >> - acpi_power->states[ACPI_STATE_C0].valid = 1; >> - acpi_power->states[ACPI_STATE_C1].valid = 1; >> - >> - acpi_power->count = 2; >> - acpi_power->safe_state = &acpi_power->states[ACPI_STATE_C1]; >> - acpi_power->cpu = cpu; >> processor_powers[cpu] = acpi_power; >> } >> >> + acpi_power->states[ACPI_STATE_C1].type = ACPI_STATE_C1; >> + acpi_power->states[ACPI_STATE_C1].entry_method >> + ACPI_CSTATE_EM_HALT; >> + >> + acpi_power->states[ACPI_STATE_C0].valid = 1; >> + acpi_power->states[ACPI_STATE_C1].valid = 1; >> + >> + acpi_power->count = 2; >> + acpi_power->safe_state = &acpi_power->states[ACPI_STATE_C1]; >> + acpi_power->cpu = cpu; >> + >> if ( cpu == 0 ) >> { >> if ( boot_cpu_has(X86_FEATURE_NONSTOP_TSC) ) @@ -870,11 >> +870,10 @@ static void set_cx( >> >> if ( xen_cx->type == ACPI_STATE_C1 ) >> cx = &acpi_power->states[1]; >> - else >> - cx = &acpi_power->states[acpi_power->count]; >> - >> - if ( !cx->valid ) >> - acpi_power->count++; >> + else { >> + ASSERT(acpi_power->count < ACPI_PROCESSOR_MAX_POWER); >> + cx = &acpi_power->states[acpi_power->count++]; >> + } >> >> cx->valid = 1; >> cx->type = xen_cx->type; >> >> -- >> Eric Chanudet >> >> _______________________________________________ >> Xen-devel mailing list >> Xen-devel@lists.xen.org >> http://lists.xen.org/xen-devel > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xen.org > http://lists.xen.org/xen-devel
Jan Beulich
2012-Mar-08 12:45 UTC
[PATCH] Re: XENPF_set_processor_pminfo XEN_PM_CX overflows states array
Calling XENPF_set_processor_pminfo with XEN_PM_CX could cause states array in "struct acpi_processor_power" to exceed its limit. The array used to be reset (by function cpuidle_init_cpu()) for each hypercall. The patch puts it back that way and adds an assertion to make it clear in case that happens again. Signed-off-by: Eric Chanudet <eric.chanudet@eu.citrix.com> - convert assertion to printk() & bail - eliminate struct acpi_processor_cx''s valid member (not read anymore) - further adjustments to one-time-only vs each-time operations in cpuidle_init_cpu() - don''t use ACPI_STATE_Cn as array index anymore Signed-off-by: Jan Beulich <jbeulich@suse.com> --- 2012-03-06.orig/xen/arch/x86/acpi/cpu_idle.c 2012-03-06 13:35:15.000000000 +0100 +++ 2012-03-06/xen/arch/x86/acpi/cpu_idle.c 2012-03-08 12:36:24.000000000 +0100 @@ -73,10 +73,8 @@ static void lapic_timer_nop(void) { } static void (*lapic_timer_off)(void); static void (*lapic_timer_on)(void); -static uint64_t (*get_tick)(void); -static uint64_t (*ticks_elapsed)(uint64_t t1, uint64_t t2); -static uint64_t (*tick_to_ns)(uint64_t ticks); -static uint64_t (*ns_to_tick)(uint64_t ticks); +static uint64_t (*__read_mostly tick_to_ns)(uint64_t) = acpi_pm_tick_to_ns; +static uint64_t (*__read_mostly ns_to_tick)(uint64_t) = ns_to_acpi_pm_tick; static void (*pm_idle_save) (void) __read_mostly; unsigned int max_cstate __read_mostly = ACPI_PROCESSOR_MAX_POWER - 1; @@ -234,6 +232,10 @@ static uint64_t acpi_pm_ticks_elapsed(ui return ((0xFFFFFFFF - t1) + t2 +1); } +static uint64_t (*__read_mostly get_tick)(void) = get_acpi_pm_tick; +static uint64_t (*__read_mostly ticks_elapsed)(uint64_t, uint64_t) + = acpi_pm_ticks_elapsed; + #define MWAIT_ECX_INTERRUPT_BREAK (0x1) /* @@ -632,43 +634,31 @@ static int cpuidle_init_cpu(int cpu) acpi_power = processor_powers[cpu]; if ( !acpi_power ) { - int i; + unsigned int i; + + if ( cpu == 0 && boot_cpu_has(X86_FEATURE_NONSTOP_TSC) ) + { + get_tick = get_stime_tick; + ticks_elapsed = stime_ticks_elapsed; + tick_to_ns = stime_tick_to_ns; + ns_to_tick = ns_to_stime_tick; + } + acpi_power = xzalloc(struct acpi_processor_power); if ( !acpi_power ) return -ENOMEM; for ( i = 0; i < ACPI_PROCESSOR_MAX_POWER; i++ ) acpi_power->states[i].idx = i; - - acpi_power->states[ACPI_STATE_C1].type = ACPI_STATE_C1; - acpi_power->states[ACPI_STATE_C1].entry_method = ACPI_CSTATE_EM_HALT; - - acpi_power->states[ACPI_STATE_C0].valid = 1; - acpi_power->states[ACPI_STATE_C1].valid = 1; - - acpi_power->count = 2; - acpi_power->safe_state = &acpi_power->states[ACPI_STATE_C1]; + acpi_power->cpu = cpu; processor_powers[cpu] = acpi_power; } - if ( cpu == 0 ) - { - if ( boot_cpu_has(X86_FEATURE_NONSTOP_TSC) ) - { - get_tick = get_stime_tick; - ticks_elapsed = stime_ticks_elapsed; - tick_to_ns = stime_tick_to_ns; - ns_to_tick = ns_to_stime_tick; - } - else - { - get_tick = get_acpi_pm_tick; - ticks_elapsed = acpi_pm_ticks_elapsed; - tick_to_ns = acpi_pm_tick_to_ns; - ns_to_tick = ns_to_acpi_pm_tick; - } - } + acpi_power->count = 2; + acpi_power->states[1].type = ACPI_STATE_C1; + acpi_power->states[1].entry_method = ACPI_CSTATE_EM_HALT; + acpi_power->safe_state = &acpi_power->states[1]; return 0; } @@ -885,17 +875,25 @@ static void set_cx( if ( check_cx(acpi_power, xen_cx) != 0 ) return; - if ( xen_cx->type == ACPI_STATE_C1 ) + switch ( xen_cx->type ) + { + case ACPI_STATE_C1: cx = &acpi_power->states[1]; - else - cx = &acpi_power->states[acpi_power->count]; - - if ( !cx->valid ) - acpi_power->count++; + break; + default: + if ( acpi_power->count >= ACPI_PROCESSOR_MAX_POWER ) + { + case ACPI_STATE_C0: + printk(XENLOG_WARNING "CPU%u: C%d data ignored\n", + acpi_power->cpu, xen_cx->type); + return; + } + cx = &acpi_power->states[acpi_power->count++]; + cx->type = xen_cx->type; + break; + } - cx->valid = 1; - cx->type = xen_cx->type; - cx->address = xen_cx->reg.address; + cx->address = xen_cx->reg.address; switch ( xen_cx->reg.space_id ) { --- 2012-03-06.orig/xen/include/xen/cpuidle.h 2011-06-16 09:21:02.000000000 +0200 +++ 2012-03-06/xen/include/xen/cpuidle.h 2012-03-08 12:34:26.000000000 +0100 @@ -40,7 +40,6 @@ struct acpi_processor_cx { u8 idx; - u8 valid; u8 type; u32 address; u8 entry_method; /* ACPI_CSTATE_EM_xxx */