[ofw] [PATCH] complib/timer: fix race accessing timer fields
Hefty, Sean
sean.hefty at intel.com
Tue Jun 22 10:54:15 PDT 2010
The timeout_time field of cl_timer_t is modified in the timer
callback function and also in calls to cl_timer_start, cl_timer_stop,
and cl_timer_trim. The user cannot protect against the changes
made in the timer callback function, so the timer must provide
this protection itself.
Signed-off-by: Sean Hefty <sean.hefty at intel.com>
---
I looked at the kernel code based on what Tzachi found for the user
space implementation. I can't say for certain that the lack of
synchronization causes an issue, but the timeout_time value
can definitely be modified outside of the user's control. The
potential issue is that cl_timer_trim reads timeout_time
twice and writes it once; the timeout_time value can change
between the two reads, which leaves open the possibility that
cl_timer_trim will not set the timer. The existing code may not
ever hit this, but it seems safer to provide the necessary
synchronization.
trunk/core/complib/kernel/cl_timer.c | 33 ++++++++++++++++++++++---------
trunk/inc/kernel/complib/cl_timer_osd.h | 3 ++-
2 files changed, 25 insertions(+), 11 deletions(-)
diff --git a/trunk/core/complib/kernel/cl_timer.c b/trunk/core/complib/kernel/cl_timer.c
index 34cae8e..ccbc794 100644
--- a/trunk/core/complib/kernel/cl_timer.c
+++ b/trunk/core/complib/kernel/cl_timer.c
@@ -45,7 +45,9 @@ __timer_callback(
UNUSED_PARAM( arg1 );
UNUSED_PARAM( arg2 );
+ cl_spinlock_acquire( &p_timer->spinlock );
p_timer->timeout_time = 0;
+ cl_spinlock_release( &p_timer->spinlock );
(p_timer->pfn_callback)( (void*)p_timer->context );
}
@@ -75,6 +77,7 @@ cl_timer_init(
KeInitializeTimer( &p_timer->timer );
KeInitializeDpc( &p_timer->dpc, __timer_callback, p_timer );
+ cl_spinlock_init( &p_timer->spinlock );
return( CL_SUCCESS );
}
@@ -108,6 +111,7 @@ cl_timer_start(
IN const uint32_t time_ms )
{
LARGE_INTEGER due_time;
+ uint64_t timeout_time;
CL_ASSERT( p_timer );
CL_ASSERT( p_timer->pfn_callback );
@@ -115,11 +119,13 @@ cl_timer_start(
/* Due time is in 100 ns increments. Negative for relative time. */
due_time.QuadPart = -(int64_t)(((uint64_t)time_ms) * 10000);
+ timeout_time = cl_get_time_stamp() + (((uint64_t)time_ms) * 1000);
- /* Store the timeout time in the timer object. */
- p_timer->timeout_time = cl_get_time_stamp() + (((uint64_t)time_ms) * 1000);
-
+ cl_spinlock_acquire( &p_timer->spinlock );
+ p_timer->timeout_time = timeout_time;
KeSetTimer( &p_timer->timer, due_time, &p_timer->dpc );
+ cl_spinlock_release( &p_timer->spinlock );
+
return( CL_SUCCESS );
}
@@ -129,19 +135,25 @@ cl_timer_trim(
IN cl_timer_t* const p_timer,
IN const uint32_t time_ms )
{
+ LARGE_INTEGER due_time;
uint64_t timeout_time;
CL_ASSERT( p_timer );
CL_ASSERT( p_timer->pfn_callback );
- /* Calculate the timeout time in the timer object. */
+ /* Due time is in 100 ns increments. Negative for relative time. */
+ due_time.QuadPart = -(int64_t)(((uint64_t)time_ms) * 10000);
timeout_time = cl_get_time_stamp() + (((uint64_t)time_ms) * 1000);
/* Only pull in the timeout time. */
- if( p_timer->timeout_time && p_timer->timeout_time < timeout_time )
- return( CL_SUCCESS );
-
- return cl_timer_start( p_timer, time_ms );
+ cl_spinlock_acquire( &p_timer->spinlock );
+ if( !p_timer->timeout_time || p_timer->timeout_time > timeout_time )
+ {
+ p_timer->timeout_time = timeout_time;
+ KeSetTimer( &p_timer->timer, due_time, &p_timer->dpc );
+ }
+ cl_spinlock_release( &p_timer->spinlock );
+ return( CL_SUCCESS );
}
@@ -154,7 +166,8 @@ cl_timer_stop(
CL_ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL );
/* Cancel the timer. This also cancels any queued DPCs for the timer. */
- KeCancelTimer( &p_timer->timer );
-
+ cl_spinlock_acquire( &p_timer->spinlock );
p_timer->timeout_time = 0;
+ KeCancelTimer( &p_timer->timer );
+ cl_spinlock_release( &p_timer->spinlock );
}
diff --git a/trunk/inc/kernel/complib/cl_timer_osd.h b/trunk/inc/kernel/complib/cl_timer_osd.h
index 4cb99b0..32fef83 100644
--- a/trunk/inc/kernel/complib/cl_timer_osd.h
+++ b/trunk/inc/kernel/complib/cl_timer_osd.h
@@ -38,7 +38,7 @@
#include "complib/cl_types.h"
-
+#include "complib/cl_spinlock.h"
/* Timer object definition. */
typedef struct _cl_timer
@@ -48,6 +48,7 @@ typedef struct _cl_timer
cl_pfn_timer_callback_t pfn_callback;
const void *context;
uint64_t timeout_time;
+ cl_spinlock_t spinlock;
} cl_timer_t;
More information about the ofw
mailing list