aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjoern B. Brandenburg <bbb@cs.unc.edu>2009-05-03 01:09:28 -0400
committerBjoern B. Brandenburg <bbb@cs.unc.edu>2009-05-03 01:09:28 -0400
commit490bfb44bf7f75bba7ad7a8dea89cb2eb2865fb7 (patch)
tree74e359fd16e3e326c6ca91ece0b5460357081915
parent812251a109b77301a7d4376dc42ffc04c20f315c (diff)
rt domain: avoid use-after-free and re-init-while-in-use bugs
Don't just blindly overwrite the timers if they could be still in use. The the use-after-free bug was observed under Qemu.
-rw-r--r--litmus/litmus.c17
-rw-r--r--litmus/rt_domain.c36
2 files changed, 34 insertions, 19 deletions
diff --git a/litmus/litmus.c b/litmus/litmus.c
index 60e7507ba0..b286f8f013 100644
--- a/litmus/litmus.c
+++ b/litmus/litmus.c
@@ -36,7 +36,7 @@ static LIST_HEAD(sched_sig_list);
36static DEFINE_SPINLOCK(sched_sig_list_lock); 36static DEFINE_SPINLOCK(sched_sig_list_lock);
37 37
38static struct kmem_cache * heap_node_cache; 38static struct kmem_cache * heap_node_cache;
39static struct kmem_cache * release_heap_cache; 39extern struct kmem_cache * release_heap_cache;
40 40
41struct heap_node* heap_node_alloc(int gfp_flags) 41struct heap_node* heap_node_alloc(int gfp_flags)
42{ 42{
@@ -48,15 +48,8 @@ void heap_node_free(struct heap_node* hn)
48 kmem_cache_free(heap_node_cache, hn); 48 kmem_cache_free(heap_node_cache, hn);
49} 49}
50 50
51struct release_heap* release_heap_alloc(int gfp_flags) 51struct release_heap* release_heap_alloc(int gfp_flags);
52{ 52void release_heap_free(struct release_heap* rh);
53 return kmem_cache_alloc(release_heap_cache, gfp_flags);
54}
55
56void release_heap_free(struct release_heap* rh)
57{
58 kmem_cache_free(release_heap_cache, rh);
59}
60 53
61/* 54/*
62 * sys_set_task_rt_param 55 * sys_set_task_rt_param
@@ -578,8 +571,8 @@ long litmus_admit_task(struct task_struct* tsk)
578 retval = -ENOMEM; 571 retval = -ENOMEM;
579 heap_node_free(tsk_rt(tsk)->heap_node); 572 heap_node_free(tsk_rt(tsk)->heap_node);
580 release_heap_free(tsk_rt(tsk)->rel_heap); 573 release_heap_free(tsk_rt(tsk)->rel_heap);
581 } else 574 } else
582 heap_node_init(&tsk_rt(tsk)->heap_node, tsk); 575 heap_node_init(&tsk_rt(tsk)->heap_node, tsk);
583 576
584 if (!retval) 577 if (!retval)
585 retval = litmus->admit_task(tsk); 578 retval = litmus->admit_task(tsk);
diff --git a/litmus/rt_domain.c b/litmus/rt_domain.c
index e02ec03ca1..0357df5f93 100644
--- a/litmus/rt_domain.c
+++ b/litmus/rt_domain.c
@@ -9,6 +9,7 @@
9#include <linux/percpu.h> 9#include <linux/percpu.h>
10#include <linux/sched.h> 10#include <linux/sched.h>
11#include <linux/list.h> 11#include <linux/list.h>
12#include <linux/slab.h>
12 13
13#include <litmus/litmus.h> 14#include <litmus/litmus.h>
14#include <litmus/sched_plugin.h> 15#include <litmus/sched_plugin.h>
@@ -57,12 +58,39 @@ static enum hrtimer_restart on_release_timer(struct hrtimer *timer)
57 58
58 /* call release callback */ 59 /* call release callback */
59 rh->dom->release_jobs(rh->dom, &rh->heap); 60 rh->dom->release_jobs(rh->dom, &rh->heap);
61 /* WARNING: rh can be referenced from other CPUs from now on. */
60 62
61 TS_RELEASE_END; 63 TS_RELEASE_END;
62 64
63 return HRTIMER_NORESTART; 65 return HRTIMER_NORESTART;
64} 66}
65 67
68/* allocated in litmus.c */
69struct kmem_cache * release_heap_cache;
70
71struct release_heap* release_heap_alloc(int gfp_flags)
72{
73 struct release_heap* rh;
74 rh= kmem_cache_alloc(release_heap_cache, gfp_flags);
75 if (rh) {
76 /* FIXME: could be a ctor */
77 /* initialize timer */
78 hrtimer_init(&rh->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
79 rh->timer.function = on_release_timer;
80#ifdef CONFIG_HIGH_RES_TIMERS
81 rh->timer.cb_mode = HRTIMER_CB_IRQSAFE_NO_RESTART;
82#endif
83 }
84 return rh;
85}
86
87void release_heap_free(struct release_heap* rh)
88{
89 /* make sure timer is no longer in use */
90 hrtimer_cancel(&rh->timer);
91 kmem_cache_free(release_heap_cache, rh);
92}
93
66/* Caller most hold release lock. 94/* Caller most hold release lock.
67 * Will return heap for given time. If no such heap exists prior to the invocation 95 * Will return heap for given time. If no such heap exists prior to the invocation
68 * it will be created. 96 * it will be created.
@@ -101,14 +129,8 @@ static struct release_heap* get_release_heap(rt_domain_t *rt, struct task_struct
101 rh->dom = rt; 129 rh->dom = rt;
102 heap_init(&rh->heap); 130 heap_init(&rh->heap);
103 131
104 /* initialize timer */
105 hrtimer_init(&rh->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
106 rh->timer.function = on_release_timer;
107#ifdef CONFIG_HIGH_RES_TIMERS
108 rh->timer.cb_mode = HRTIMER_CB_IRQSAFE;
109#endif
110
111 atomic_set(&rh->info.state, HRTIMER_START_ON_INACTIVE); 132 atomic_set(&rh->info.state, HRTIMER_START_ON_INACTIVE);
133
112 /* add to release queue */ 134 /* add to release queue */
113 list_add(&rh->list, pos->prev); 135 list_add(&rh->list, pos->prev);
114 heap = rh; 136 heap = rh;