From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754157AbZLARis (ORCPT ); Tue, 1 Dec 2009 12:38:48 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1752375AbZLARir (ORCPT ); Tue, 1 Dec 2009 12:38:47 -0500 Received: from www.tglx.de ([62.245.132.106]:50678 "EHLO www.tglx.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753707AbZLARiq (ORCPT ); Tue, 1 Dec 2009 12:38:46 -0500 Date: Tue, 1 Dec 2009 18:37:35 +0100 (CET) From: Thomas Gleixner To: Linus Torvalds cc: Peter Zijlstra , Ingo Molnar , Christoph Hellwig , Nick Piggin , Linux Kernel Mailing List , Al Viro , James Morris , Oleg Nesterov Subject: [PATCH] audit: Call tty_audit_push_task() outside preempt disabled region In-Reply-To: Message-ID: References: <20091123145409.GA29627@wotan.suse.de> <20091130100041.GA29610@infradead.org> <20091130174638.GA9782@elte.hu> <1259616429.26472.499.camel@laptop> User-Agent: Alpine 2.00 (LFD 1167 2008-08-23) MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org While auditing all tasklist_lock read_lock sites I stumbled over the following call chain: audit_prepare_user_tty() read_lock(&tasklist_lock); tty_audit_push_task(); mutex_lock(&buf->mutex); --> buf->mutex is locked with preemption disabled. Solve this by acquiring a reference to the task struct under rcu_read_lock and call tty_audit_push_task outside of the preempt disabled region. Move all code which needs to be protected by sighand lock into tty_audit_push_task() and use lock/unlock_sighand as we do not hold tasklist_lock. Signed-off-by: Thomas Gleixner --- drivers/char/tty_audit.c | 29 +++++++++++++++++++++-------- include/linux/tty.h | 8 ++++---- kernel/audit.c | 25 +++++++++---------------- 3 files changed, 34 insertions(+), 28 deletions(-) Index: linux-2.6-tip/drivers/char/tty_audit.c =================================================================== --- linux-2.6-tip.orig/drivers/char/tty_audit.c +++ linux-2.6-tip/drivers/char/tty_audit.c @@ -188,25 +188,38 @@ void tty_audit_tiocsti(struct tty_struct } /** - * tty_audit_push_task - Flush task's pending audit data + * tty_audit_push_task - Flush task's pending audit data + * @tsk: task pointer + * @loginuid: sender login uid + * @sessionid: sender session id + * + * Called with a ref on @tsk held. Try to lock sighand and get a + * reference to the tty audit buffer if available. + * Flush the buffer or return an appropriate error code. */ -void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid, u32 sessionid) +int tty_audit_push_task(struct task_struct *tsk, uid_t loginuid, u32 sessionid) { - struct tty_audit_buf *buf; + struct tty_audit_buf *buf = NULL; + unsigned long flags; - spin_lock_irq(&tsk->sighand->siglock); - buf = tsk->signal->tty_audit_buf; - if (buf) + if (!lock_task_sighand(tsk, &flags)) + return -ESRCH; + + if (tsk->signal->audit_tty && tsk->signal->tty_audit_buf) { + buf = tsk->signal->tty_audit_buf; atomic_inc(&buf->count); - spin_unlock_irq(&tsk->sighand->siglock); + } + unlock_task_sighand(tsk, &flags); + if (!buf) - return; + return -EPERM; mutex_lock(&buf->mutex); tty_audit_buf_push(tsk, loginuid, sessionid, buf); mutex_unlock(&buf->mutex); tty_audit_buf_put(buf); + return 0; } /** Index: linux-2.6-tip/include/linux/tty.h =================================================================== --- linux-2.6-tip.orig/include/linux/tty.h +++ linux-2.6-tip/include/linux/tty.h @@ -494,8 +494,8 @@ extern void tty_audit_exit(void); extern void tty_audit_fork(struct signal_struct *sig); extern void tty_audit_tiocsti(struct tty_struct *tty, char ch); extern void tty_audit_push(struct tty_struct *tty); -extern void tty_audit_push_task(struct task_struct *tsk, - uid_t loginuid, u32 sessionid); +extern int tty_audit_push_task(struct task_struct *tsk, + uid_t loginuid, u32 sessionid); #else static inline void tty_audit_add_data(struct tty_struct *tty, unsigned char *data, size_t size) @@ -513,8 +513,8 @@ static inline void tty_audit_fork(struct static inline void tty_audit_push(struct tty_struct *tty) { } -static inline void tty_audit_push_task(struct task_struct *tsk, - uid_t loginuid, u32 sessionid) +static inline int tty_audit_push_task(struct task_struct *tsk, + uid_t loginuid, u32 sessionid) { } #endif Index: linux-2.6-tip/kernel/audit.c =================================================================== --- linux-2.6-tip.orig/kernel/audit.c +++ linux-2.6-tip/kernel/audit.c @@ -467,23 +467,16 @@ static int audit_prepare_user_tty(pid_t struct task_struct *tsk; int err; - read_lock(&tasklist_lock); + rcu_read_lock(); tsk = find_task_by_vpid(pid); - err = -ESRCH; - if (!tsk) - goto out; - err = 0; - - spin_lock_irq(&tsk->sighand->siglock); - if (!tsk->signal->audit_tty) - err = -EPERM; - spin_unlock_irq(&tsk->sighand->siglock); - if (err) - goto out; - - tty_audit_push_task(tsk, loginuid, sessionid); -out: - read_unlock(&tasklist_lock); + if (!tsk) { + rcu_read_unlock(); + return -ESRCH; + } + get_task_struct(tsk); + rcu_read_unlock(); + err = tty_audit_push_task(tsk, loginuid, sessionid); + put_task_struct(tsk); return err; }