Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756650AbcCBA5Z (ORCPT ); Tue, 1 Mar 2016 19:57:25 -0500 Received: from mail333.us4.mandrillapp.com ([205.201.137.77]:48096 "EHLO mail333.us4.mandrillapp.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755886AbcCAX4X (ORCPT ); Tue, 1 Mar 2016 18:56:23 -0500 DomainKey-Signature: a=rsa-sha1; c=nofws; q=dns; s=mandrill; d=linuxfoundation.org; b=igU0QGFPyNQ/rSmqUdVoNGnRoOLWvFIzKwJjkIj8o2BaB6PDArgwzzDNaXXLM4xFLoNEo+8/fPT0 LrOpZpuerMe/k0AbpWm3Lk/r2dywQ5LUUwWo6F19YQrzRNAKIWcHJDdNSBhvtoHW0ec+1oDT9yDj GBy1auM90hR6cPnCWaE=; From: Greg Kroah-Hartman Subject: [PATCH 4.4 083/342] genirq: Validate action before dereferencing it in handle_irq_event_percpu() X-Mailer: git-send-email 2.7.2 To: Cc: Greg Kroah-Hartman , , , Thomas Gleixner , Huang Shijie , Jiang Liu , Peter Zijlstra Message-Id: <20160301234530.672617725@linuxfoundation.org> In-Reply-To: <20160301234527.990448862@linuxfoundation.org> References: <20160301234527.990448862@linuxfoundation.org> X-Report-Abuse: Please forward a copy of this message, including all headers, to abuse@mandrill.com X-Report-Abuse: You can also report abuse here: http://mandrillapp.com/contact/abuse?id=30481620.bcb9b83302774f998c90277f11e96fa3 X-Mandrill-User: md_30481620 Date: Tue, 01 Mar 2016 23:54:26 +0000 MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 3547 Lines: 97 4.4-stable review patch. If anyone has any objections, please let me know. ------------------ From: Thomas Gleixner commit 570540d50710ed192e98e2f7f74578c9486b6b05 upstream. commit 71f64340fc0e changed the handling of irq_desc->action from CPU 0 CPU 1 free_irq() lock(desc) lock(desc) handle_edge_irq() if (desc->action) { handle_irq_event() action = desc->action unlock(desc) desc->action = NULL handle_irq_event_percpu(desc, action) action->xxx to CPU 0 CPU 1 free_irq() lock(desc) lock(desc) handle_edge_irq() if (desc->action) { handle_irq_event() unlock(desc) desc->action = NULL handle_irq_event_percpu(desc, action) action = desc->action action->xxx So if free_irq manages to set the action to NULL between the unlock and before the readout, we happily dereference a null pointer. We could simply revert 71f64340fc0e, but we want to preserve the better code generation. A simple solution is to change the action loop from a do {} while to a while {} loop. This is safe because we either see a valid desc->action or NULL. If the action is about to be removed it is still valid as free_irq() is blocked on synchronize_irq(). CPU 0 CPU 1 free_irq() lock(desc) lock(desc) handle_edge_irq() handle_irq_event(desc) set(INPROGRESS) unlock(desc) handle_irq_event_percpu(desc) action = desc->action desc->action = NULL while (action) { action->xxx ... action = action->next; sychronize_irq() while(INPROGRESS); lock(desc) clr(INPROGRESS) free(action) That's basically the same mechanism as we have for shared interrupts. action->next can become NULL while handle_irq_event_percpu() runs. Either it sees the action or NULL. It does not matter, because action itself cannot go away before the interrupt in progress flag has been cleared. Fixes: commit 71f64340fc0e "genirq: Remove the second parameter from handle_irq_event_percpu()" Reported-by: zyjzyj2000@gmail.com Signed-off-by: Thomas Gleixner Cc: Huang Shijie Cc: Jiang Liu Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/alpine.DEB.2.11.1601131224190.3575@nanos Signed-off-by: Greg Kroah-Hartman --- kernel/irq/handle.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c @@ -138,7 +138,8 @@ irqreturn_t handle_irq_event_percpu(stru unsigned int flags = 0, irq = desc->irq_data.irq; struct irqaction *action = desc->action; - do { + /* action might have become NULL since we dropped the lock */ + while (action) { irqreturn_t res; trace_irq_handler_entry(irq, action); @@ -173,7 +174,7 @@ irqreturn_t handle_irq_event_percpu(stru retval |= res; action = action->next; - } while (action); + } add_interrupt_randomness(irq, flags);