Skip to content

Commit

Permalink
hrtimer: Don't dereference the hrtimer pointer after the callback
Browse files Browse the repository at this point in the history
A hrtimer can be released in its callback, but lockdep_hrtimer_exit()
dereferences the pointer after the callback returns, i.e. a potential use
after free.

Retrieve the context in which the hrtimer expires before the callback is
invoked and use it in lockdep_hrtimer_exit().

Fixes: 40db173 ("lockdep: Add hrtimer context tracing bits")
Reported-by: syzbot+62c155c276e580cfb606@syzkaller.appspotmail.com
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lkml.kernel.org/r/20200331201849.fkp2siy3vcdqvqlz@linutronix.de
  • Loading branch information
Sebastian Andrzej Siewior authored and Thomas Gleixner committed Apr 1, 2020
1 parent 42595ce commit 73d2056
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 13 deletions.
27 changes: 16 additions & 11 deletions include/linux/irqflags.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,21 @@ do { \
} while (0)

# define lockdep_hrtimer_enter(__hrtimer) \
do { \
if (!__hrtimer->is_hard) \
current->irq_config = 1; \
} while (0)

# define lockdep_hrtimer_exit(__hrtimer) \
do { \
if (!__hrtimer->is_hard) \
({ \
bool __expires_hardirq = true; \
\
if (!__hrtimer->is_hard) { \
current->irq_config = 1; \
__expires_hardirq = false; \
} \
__expires_hardirq; \
})

# define lockdep_hrtimer_exit(__expires_hardirq) \
do { \
if (!__expires_hardirq) \
current->irq_config = 0; \
} while (0)
} while (0)

# define lockdep_posixtimer_enter() \
do { \
Expand Down Expand Up @@ -102,8 +107,8 @@ do { \
# define lockdep_hardirq_exit() do { } while (0)
# define lockdep_softirq_enter() do { } while (0)
# define lockdep_softirq_exit() do { } while (0)
# define lockdep_hrtimer_enter(__hrtimer) do { } while (0)
# define lockdep_hrtimer_exit(__hrtimer) do { } while (0)
# define lockdep_hrtimer_enter(__hrtimer) false
# define lockdep_hrtimer_exit(__context) do { } while (0)
# define lockdep_posixtimer_enter() do { } while (0)
# define lockdep_posixtimer_exit() do { } while (0)
# define lockdep_irq_work_enter(__work) do { } while (0)
Expand Down
5 changes: 3 additions & 2 deletions kernel/time/hrtimer.c
Original file line number Diff line number Diff line change
Expand Up @@ -1480,6 +1480,7 @@ static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base,
unsigned long flags) __must_hold(&cpu_base->lock)
{
enum hrtimer_restart (*fn)(struct hrtimer *);
bool expires_in_hardirq;
int restart;

lockdep_assert_held(&cpu_base->lock);
Expand Down Expand Up @@ -1514,11 +1515,11 @@ static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base,
*/
raw_spin_unlock_irqrestore(&cpu_base->lock, flags);
trace_hrtimer_expire_entry(timer, now);
lockdep_hrtimer_enter(timer);
expires_in_hardirq = lockdep_hrtimer_enter(timer);

restart = fn(timer);

lockdep_hrtimer_exit(timer);
lockdep_hrtimer_exit(expires_in_hardirq);
trace_hrtimer_expire_exit(timer);
raw_spin_lock_irq(&cpu_base->lock);

Expand Down

0 comments on commit 73d2056

Please sign in to comment.