From 7ded4359680d3fb593cbc5c90d84bb5e5083eda9 Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Thu, 10 Nov 2016 19:18:53 -0700 Subject: [PATCH] ANDROID: nf: IDLETIMER: Fix possible use before initialization in idletimer_resume idletimer_resume() assumes that the PM_SUSPEND_PREPARE notifier is sent before PM_POST_SUSPEND so that timer->last_suspend_time is initialized. However, it is possible for PM_POST_SUSPEND to be sent first if there is an error returned from another driver's PM_SUSPEND_PREPARE notifier. As a result, structures are accessed without initialization. The arguments to set_normalized_timespec are very large and unexpected. timer->last_suspend_time has the value of {.tv_sec = 0x6b6b6b6b6b6b6b6b, .tv_nsec=0x6b6b6b6b6b6b6b6b}. Since really large iterations are required, this operation takes more than a minute and causes the CPU to trigger a spinbug since the timestamp lock is held. Call stack - - set_normalized_timespec - timespec_sub - idletimer_resume - notifier_call_chain - __blocking_notifier_call_chain - pm_notifier_call_chain Add a flag indicating whether the current value of timer->last_suspend is valid. Detected with CONFIG_SLUB_DEBUG & CONFIG_DEBUG_SPINLOCK in arm64. Bug: 140404598 Fixes: f0c2df2b1228a ("ANDROID: netfilter: xt_IDLETIMER: Add new netlink msg type") Change-Id: I95328b0ac85dba819ff9cef751c3d07300c232f1 Signed-off-by: Subash Abhinov Kasiviswanathan Signed-off-by: Todd Kjos --- net/netfilter/xt_IDLETIMER.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/net/netfilter/xt_IDLETIMER.c b/net/netfilter/xt_IDLETIMER.c index 5f4a3229ed92..a7e0b7fc4aac 100644 --- a/net/netfilter/xt_IDLETIMER.c +++ b/net/netfilter/xt_IDLETIMER.c @@ -57,6 +57,7 @@ struct idletimer_tg { bool send_nl_msg; bool active; uid_t uid; + bool suspend_time_valid; }; static LIST_HEAD(idletimer_tg_list); @@ -226,8 +227,13 @@ static int idletimer_resume(struct notifier_block *notifier, case PM_SUSPEND_PREPARE: timer->last_suspend_time = ktime_to_timespec64(ktime_get_boottime()); + timer->suspend_time_valid = true; break; case PM_POST_SUSPEND: + if (!timer->suspend_time_valid) + break; + timer->suspend_time_valid = false; + spin_lock_bh(×tamp_lock); if (!timer->active) { spin_unlock_bh(×tamp_lock); @@ -278,7 +284,7 @@ static int idletimer_tg_create(struct idletimer_tg_info *info) { int ret; - info->timer = kmalloc(sizeof(*info->timer), GFP_KERNEL); + info->timer = kzalloc(sizeof(*info->timer), GFP_KERNEL); if (!info->timer) { ret = -ENOMEM; goto out;