x86: Fix XENPF_change_freq hypercall to not dereference a non-existent
authorKeir Fraser <keir.fraser@citrix.com>
Tue, 29 Jan 2008 11:19:04 +0000 (11:19 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Tue, 29 Jan 2008 11:19:04 +0000 (11:19 +0000)
stack variable. Also sanity check (slightly) the frequency argument to
cpu_frequency_change().
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
xen/arch/x86/platform_hypercall.c
xen/arch/x86/time.c

index 047a7c0a305bdf89d6dae910991e93f194ae31f0..3f4983aee64a9db372f276ef0e9d1a42fd31b0f9 100644 (file)
@@ -42,9 +42,11 @@ DEFINE_SPINLOCK(xenpf_lock);
 extern spinlock_t xenpf_lock;
 #endif
 
+static DEFINE_PER_CPU(uint64_t, freq);
+
 static long cpu_frequency_change_helper(void *data)
 {
-    return cpu_frequency_change(*(uint64_t *)data);
+    return cpu_frequency_change(this_cpu(freq));
 }
 
 ret_t do_platform_op(XEN_GUEST_HANDLE(xen_platform_op_t) u_xenpf_op)
@@ -284,11 +286,12 @@ ret_t do_platform_op(XEN_GUEST_HANDLE(xen_platform_op_t) u_xenpf_op)
         if ( cpufreq_controller != FREQCTL_dom0_kernel )
             break;
         ret = -EINVAL;
-        if ( op->u.change_freq.flags != 0 )
+        if ( op->u.change_freq.flags || !cpu_online(op->u.change_freq.cpu) )
             break;
+        per_cpu(freq, op->u.change_freq.cpu) = op->u.change_freq.freq;
         ret = continue_hypercall_on_cpu(op->u.change_freq.cpu,
                                         cpu_frequency_change_helper,
-                                        &op->u.change_freq.freq);
+                                        NULL);
         break;
 
     case XENPF_getidletime:
index e079138b239bce710c2454a13b6fd822cfd9f60a..57135940bf74d3bea3483e6c326500e4189b3ef5 100644 (file)
@@ -729,6 +729,14 @@ int cpu_frequency_change(u64 freq)
     struct cpu_time *t = &this_cpu(cpu_time);
     u64 curr_tsc;
 
+    /* Sanity check: CPU frequency allegedly dropping below 1MHz? */
+    if ( freq < 1000000u )
+    {
+        gdprintk(XENLOG_WARNING, "Rejecting CPU frequency change "
+                 "to %"PRIu64" Hz.\n", freq);
+        return -EINVAL;
+    }
+
     local_irq_disable();
     rdtscll(curr_tsc);
     t->local_tsc_stamp = curr_tsc;