All of lore.kernel.org
 help / color / mirror / Atom feed
* [patch 0/3] audit: Fixes and tasklist_lock -> RCU conversion
@ 2009-12-09 14:19 Thomas Gleixner
  2009-12-09 14:19 ` [patch 1/3] audit: Call tty_audit_push_task() outside preempt disabled Thomas Gleixner
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Thomas Gleixner @ 2009-12-09 14:19 UTC (permalink / raw)
  To: LKML; +Cc: Al Viro, Eric Paris, Ingo Molnar, Peter Zijlstra

Hi,

the following patches result from auditing read_lock(&tasklist_lock)
sites whether they can be converted to RCU.

Thanks,

	tglx


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [patch 1/3] audit: Call tty_audit_push_task() outside preempt disabled
  2009-12-09 14:19 [patch 0/3] audit: Fixes and tasklist_lock -> RCU conversion Thomas Gleixner
@ 2009-12-09 14:19 ` Thomas Gleixner
  2009-12-09 14:19 ` [patch 2/3] audit: Do not send uninitialized data for AUDIT_TTY_GET Thomas Gleixner
  2009-12-09 14:19 ` [patch 3/3] audit: Use rcu for task lookup protection Thomas Gleixner
  2 siblings, 0 replies; 8+ messages in thread
From: Thomas Gleixner @ 2009-12-09 14:19 UTC (permalink / raw)
  To: LKML; +Cc: Al Viro, Eric Paris, Ingo Molnar, Peter Zijlstra, Oleg Nesterov

[-- Attachment #1: audit-call-tty_audit_push_task-outside-preempt-disabled-region.patch region --]
[-- Type: text/plain, Size: 4519 bytes --]

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 <tglx@linutronix.de>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Eric Paris <eparis@redhat.com>
Cc: Oleg Nesterov <oleg@redhat.com>

---
 drivers/char/tty_audit.c |   38 ++++++++++++++++++++++++++++----------
 include/linux/tty.h      |    8 ++++----
 kernel/audit.c           |   25 +++++++++----------------
 3 files changed, 41 insertions(+), 30 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,43 @@ 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 = ERR_PTR(-EPERM);
+	unsigned long flags;
 
-	spin_lock_irq(&tsk->sighand->siglock);
-	buf = tsk->signal->tty_audit_buf;
-	if (buf)
-		atomic_inc(&buf->count);
-	spin_unlock_irq(&tsk->sighand->siglock);
-	if (!buf)
-		return;
+	if (!lock_task_sighand(tsk, &flags))
+		return -ESRCH;
+
+	if (tsk->signal->audit_tty) {
+		buf = tsk->signal->tty_audit_buf;
+		if (buf)
+			atomic_inc(&buf->count);
+	}
+	unlock_task_sighand(tsk, &flags);
+
+	/*
+	 * Return 0 when signal->audit_tty set
+	 * but tsk->signal->tty_audit_buf == NULL.
+	 */
+	if (!buf || IS_ERR(buf))
+		return PTR_ERR(buf);
 
 	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;
 }
 



^ permalink raw reply	[flat|nested] 8+ messages in thread

* [patch 2/3] audit: Do not send uninitialized data for AUDIT_TTY_GET
  2009-12-09 14:19 [patch 0/3] audit: Fixes and tasklist_lock -> RCU conversion Thomas Gleixner
  2009-12-09 14:19 ` [patch 1/3] audit: Call tty_audit_push_task() outside preempt disabled Thomas Gleixner
@ 2009-12-09 14:19 ` Thomas Gleixner
  2009-12-09 14:19 ` [patch 3/3] audit: Use rcu for task lookup protection Thomas Gleixner
  2 siblings, 0 replies; 8+ messages in thread
From: Thomas Gleixner @ 2009-12-09 14:19 UTC (permalink / raw)
  To: LKML; +Cc: Al Viro, Eric Paris, Ingo Molnar, Peter Zijlstra

[-- Attachment #1: audit-do-not-send-reply-when-esrch.patch --]
[-- Type: text/plain, Size: 894 bytes --]

audit_receive_msg() sends uninitialized data for AUDIT_TTY_GET when
the task was not found.

Send reply only when task was found.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Eric Paris <eparis@redhat.com>
---
 kernel/audit.c |    6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

Index: linux-2.6-tip/kernel/audit.c
===================================================================
--- linux-2.6-tip.orig/kernel/audit.c
+++ linux-2.6-tip/kernel/audit.c
@@ -884,8 +884,10 @@ static int audit_receive_msg(struct sk_b
 			spin_unlock_irq(&tsk->sighand->siglock);
 		}
 		read_unlock(&tasklist_lock);
-		audit_send_reply(NETLINK_CB(skb).pid, seq, AUDIT_TTY_GET, 0, 0,
-				 &s, sizeof(s));
+
+		if (!err)
+			audit_send_reply(NETLINK_CB(skb).pid, seq,
+					 AUDIT_TTY_GET, 0, 0, &s, sizeof(s));
 		break;
 	}
 	case AUDIT_TTY_SET: {



^ permalink raw reply	[flat|nested] 8+ messages in thread

* [patch 3/3] audit: Use rcu for task lookup protection
  2009-12-09 14:19 [patch 0/3] audit: Fixes and tasklist_lock -> RCU conversion Thomas Gleixner
  2009-12-09 14:19 ` [patch 1/3] audit: Call tty_audit_push_task() outside preempt disabled Thomas Gleixner
  2009-12-09 14:19 ` [patch 2/3] audit: Do not send uninitialized data for AUDIT_TTY_GET Thomas Gleixner
@ 2009-12-09 14:19 ` Thomas Gleixner
  2 siblings, 0 replies; 8+ messages in thread
From: Thomas Gleixner @ 2009-12-09 14:19 UTC (permalink / raw)
  To: LKML; +Cc: Al Viro, Eric Paris, Ingo Molnar, Peter Zijlstra, Oleg Nesterov

[-- Attachment #1: audit-use-rcu-for-lookup.patch --]
[-- Type: text/plain, Size: 2049 bytes --]

Protect the task lookups in audit_receive_msg() with rcu_read_lock()
instead of tasklist_lock and use lock/unlock_sighand to protect
against the exit race.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Eric Paris <eparis@redhat.com>
Cc: Oleg Nesterov <oleg@redhat.com>
---
 kernel/audit.c |   30 ++++++++++++++----------------
 1 file changed, 14 insertions(+), 16 deletions(-)

Index: linux-2.6-tip/kernel/audit.c
===================================================================
--- linux-2.6-tip.orig/kernel/audit.c
+++ linux-2.6-tip/kernel/audit.c
@@ -873,17 +873,16 @@ static int audit_receive_msg(struct sk_b
 	case AUDIT_TTY_GET: {
 		struct audit_tty_status s;
 		struct task_struct *tsk;
+		unsigned long flags;
 
-		read_lock(&tasklist_lock);
+		rcu_read_lock();
 		tsk = find_task_by_vpid(pid);
-		if (!tsk)
-			err = -ESRCH;
-		else {
-			spin_lock_irq(&tsk->sighand->siglock);
+		if (tsk && lock_task_sighand(tsk, &flags)) {
 			s.enabled = tsk->signal->audit_tty != 0;
-			spin_unlock_irq(&tsk->sighand->siglock);
-		}
-		read_unlock(&tasklist_lock);
+			unlock_task_sighand(tsk, &flags);
+		} else
+			err = -ESRCH;
+		rcu_read_unlock();
 
 		if (!err)
 			audit_send_reply(NETLINK_CB(skb).pid, seq,
@@ -893,22 +892,21 @@ static int audit_receive_msg(struct sk_b
 	case AUDIT_TTY_SET: {
 		struct audit_tty_status *s;
 		struct task_struct *tsk;
+		unsigned long flags;
 
 		if (nlh->nlmsg_len < sizeof(struct audit_tty_status))
 			return -EINVAL;
 		s = data;
 		if (s->enabled != 0 && s->enabled != 1)
 			return -EINVAL;
-		read_lock(&tasklist_lock);
+		rcu_read_lock();
 		tsk = find_task_by_vpid(pid);
-		if (!tsk)
-			err = -ESRCH;
-		else {
-			spin_lock_irq(&tsk->sighand->siglock);
+		if (tsk && lock_task_sighand(tsk, &flags)) {
 			tsk->signal->audit_tty = s->enabled != 0;
-			spin_unlock_irq(&tsk->sighand->siglock);
-		}
-		read_unlock(&tasklist_lock);
+			unlock_task_sighand(tsk, &flags);
+		} else
+			err = -ESRCH;
+		rcu_read_unlock();
 		break;
 	}
 	default:



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [patch 3/3] audit: Use rcu for task lookup protection
  2010-09-07 20:25     ` Thomas Gleixner
@ 2010-09-08 12:44       ` Oleg Nesterov
  0 siblings, 0 replies; 8+ messages in thread
From: Oleg Nesterov @ 2010-09-08 12:44 UTC (permalink / raw)
  To: Thomas Gleixner; +Cc: LKML, Al Viro, Peter Zijlstra, Andrew Morton, Eric Paris

On 09/07, Thomas Gleixner wrote:
>
> On Tue, 7 Sep 2010, Oleg Nesterov wrote:
>
> > But, sorry, can't resists ;) off-topic nit.
> >
> > > @@ -873,17 +873,16 @@ static int audit_receive_msg(struct sk_b
> > >  	case AUDIT_TTY_GET: {
> > >  		struct audit_tty_status s;
> > >  		struct task_struct *tsk;
> > > +		unsigned long flags;
> > >
> > > -		read_lock(&tasklist_lock);
> > > +		rcu_read_lock();
> > >  		tsk = find_task_by_vpid(pid);
> > > -		if (!tsk)
> > > -			err = -ESRCH;
> > > -		else {
> > > -			spin_lock_irq(&tsk->sighand->siglock);
> > > +		if (tsk && lock_task_sighand(tsk, &flags)) {
> > >  			s.enabled = tsk->signal->audit_tty != 0;
> >
> > Yes, this is what original code does, it takes ->siglock every time
> > around read/write of ->audit_tty. And this looks absolutely bogus.
> > Say, tty_audit_fork(). Why does it take ->siglock ?

Yes, I still think ->audit_tty doesn't need the locking.

> > As for ->tty_audit_buf, I am not sure ->siglock is the best choice,
> > perhaps task_lock() would be better.

OOPS, I misread the code. ->tty_audit_buf is per-process (of course!).
Well, unless I missed something again, tty_audit_push() and
tty_audit_tiocsti() can access ->tty_audit_buf lockless.

> > Once again, I think the patch is fine. Just it seems to me this code
> > needs more cleanups.
>
> Yeah, thought about that, but that's not in the scope of what I was
> working on. I leave that to the audit folks. :)

Yes, yes, sure.

Oleg.


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [patch 3/3] audit: Use rcu for task lookup protection
  2010-09-07 18:25   ` Oleg Nesterov
@ 2010-09-07 20:25     ` Thomas Gleixner
  2010-09-08 12:44       ` Oleg Nesterov
  0 siblings, 1 reply; 8+ messages in thread
From: Thomas Gleixner @ 2010-09-07 20:25 UTC (permalink / raw)
  To: Oleg Nesterov; +Cc: LKML, Al Viro, Peter Zijlstra, Andrew Morton, Eric Paris



On Tue, 7 Sep 2010, Oleg Nesterov wrote:

> On 09/07, Thomas Gleixner wrote:
> >
> > Protect the task lookups in audit_receive_msg() with rcu_read_lock()
> > instead of tasklist_lock and use lock/unlock_sighand to protect
> > against the exit race.
> 
> I do not understand audit, but I belive both 1/3 and 3/3 patches are
> fine (I didn't get 2/3).
> 
> 
> 
> But, sorry, can't resists ;) off-topic nit.
> 
> > @@ -873,17 +873,16 @@ static int audit_receive_msg(struct sk_b
> >  	case AUDIT_TTY_GET: {
> >  		struct audit_tty_status s;
> >  		struct task_struct *tsk;
> > +		unsigned long flags;
> >
> > -		read_lock(&tasklist_lock);
> > +		rcu_read_lock();
> >  		tsk = find_task_by_vpid(pid);
> > -		if (!tsk)
> > -			err = -ESRCH;
> > -		else {
> > -			spin_lock_irq(&tsk->sighand->siglock);
> > +		if (tsk && lock_task_sighand(tsk, &flags)) {
> >  			s.enabled = tsk->signal->audit_tty != 0;
> 
> Yes, this is what original code does, it takes ->siglock every time
> around read/write of ->audit_tty. And this looks absolutely bogus.
> Say, tty_audit_fork(). Why does it take ->siglock ?
> 
> As for ->tty_audit_buf, I am not sure ->siglock is the best choice,
> perhaps task_lock() would be better.
>
> Once again, I think the patch is fine. Just it seems to me this code
> needs more cleanups.

Yeah, thought about that, but that's not in the scope of what I was
working on. I leave that to the audit folks. :)
 
Thanks,

	tglx

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [patch 3/3] audit: Use rcu for task lookup protection
  2010-09-07 14:00 ` [patch 3/3] audit: Use rcu for task lookup protection Thomas Gleixner
@ 2010-09-07 18:25   ` Oleg Nesterov
  2010-09-07 20:25     ` Thomas Gleixner
  0 siblings, 1 reply; 8+ messages in thread
From: Oleg Nesterov @ 2010-09-07 18:25 UTC (permalink / raw)
  To: Thomas Gleixner; +Cc: LKML, Al Viro, Peter Zijlstra, Andrew Morton, Eric Paris

On 09/07, Thomas Gleixner wrote:
>
> Protect the task lookups in audit_receive_msg() with rcu_read_lock()
> instead of tasklist_lock and use lock/unlock_sighand to protect
> against the exit race.

I do not understand audit, but I belive both 1/3 and 3/3 patches are
fine (I didn't get 2/3).



But, sorry, can't resists ;) off-topic nit.

> @@ -873,17 +873,16 @@ static int audit_receive_msg(struct sk_b
>  	case AUDIT_TTY_GET: {
>  		struct audit_tty_status s;
>  		struct task_struct *tsk;
> +		unsigned long flags;
>
> -		read_lock(&tasklist_lock);
> +		rcu_read_lock();
>  		tsk = find_task_by_vpid(pid);
> -		if (!tsk)
> -			err = -ESRCH;
> -		else {
> -			spin_lock_irq(&tsk->sighand->siglock);
> +		if (tsk && lock_task_sighand(tsk, &flags)) {
>  			s.enabled = tsk->signal->audit_tty != 0;

Yes, this is what original code does, it takes ->siglock every time
around read/write of ->audit_tty. And this looks absolutely bogus.
Say, tty_audit_fork(). Why does it take ->siglock ?

As for ->tty_audit_buf, I am not sure ->siglock is the best choice,
perhaps task_lock() would be better.


Once again, I think the patch is fine. Just it seems to me this code
needs more cleanups.

Oleg.


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [patch 3/3] audit: Use rcu for task lookup protection
  2010-09-07 13:59 [patch 0/3] audit: Fixes and tasklist_lock -> RCU conversion - Resend Thomas Gleixner
@ 2010-09-07 14:00 ` Thomas Gleixner
  2010-09-07 18:25   ` Oleg Nesterov
  0 siblings, 1 reply; 8+ messages in thread
From: Thomas Gleixner @ 2010-09-07 14:00 UTC (permalink / raw)
  To: LKML; +Cc: Al Viro, Peter Zijlstra, Andrew Morton, Eric Paris, Oleg Nesterov

[-- Attachment #1: audit-use-rcu-for-task-lookup-protection.patch --]
[-- Type: text/plain, Size: 2132 bytes --]

Protect the task lookups in audit_receive_msg() with rcu_read_lock()
instead of tasklist_lock and use lock/unlock_sighand to protect
against the exit race.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Eric Paris <eparis@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Oleg Nesterov <oleg@redhat.com>

---
kernel/audit.c |   30 ++++++++++++++----------------
 kernel/audit.c |   30 ++++++++++++++----------------
 1 file changed, 14 insertions(+), 16 deletions(-)
Index: linux-2.6/kernel/audit.c
===================================================================
--- linux-2.6.orig/kernel/audit.c
+++ linux-2.6/kernel/audit.c
@@ -873,17 +873,16 @@ static int audit_receive_msg(struct sk_b
 	case AUDIT_TTY_GET: {
 		struct audit_tty_status s;
 		struct task_struct *tsk;
+		unsigned long flags;
 
-		read_lock(&tasklist_lock);
+		rcu_read_lock();
 		tsk = find_task_by_vpid(pid);
-		if (!tsk)
-			err = -ESRCH;
-		else {
-			spin_lock_irq(&tsk->sighand->siglock);
+		if (tsk && lock_task_sighand(tsk, &flags)) {
 			s.enabled = tsk->signal->audit_tty != 0;
-			spin_unlock_irq(&tsk->sighand->siglock);
-		}
-		read_unlock(&tasklist_lock);
+			unlock_task_sighand(tsk, &flags);
+		} else
+			err = -ESRCH;
+		rcu_read_unlock();
 
 		if (!err)
 			audit_send_reply(NETLINK_CB(skb).pid, seq,
@@ -893,22 +892,21 @@ static int audit_receive_msg(struct sk_b
 	case AUDIT_TTY_SET: {
 		struct audit_tty_status *s;
 		struct task_struct *tsk;
+		unsigned long flags;
 
 		if (nlh->nlmsg_len < sizeof(struct audit_tty_status))
 			return -EINVAL;
 		s = data;
 		if (s->enabled != 0 && s->enabled != 1)
 			return -EINVAL;
-		read_lock(&tasklist_lock);
+		rcu_read_lock();
 		tsk = find_task_by_vpid(pid);
-		if (!tsk)
-			err = -ESRCH;
-		else {
-			spin_lock_irq(&tsk->sighand->siglock);
+		if (tsk && lock_task_sighand(tsk, &flags)) {
 			tsk->signal->audit_tty = s->enabled != 0;
-			spin_unlock_irq(&tsk->sighand->siglock);
-		}
-		read_unlock(&tasklist_lock);
+			unlock_task_sighand(tsk, &flags);
+		} else
+			err = -ESRCH;
+		rcu_read_unlock();
 		break;
 	}
 	default:



^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2010-09-08 12:47 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-12-09 14:19 [patch 0/3] audit: Fixes and tasklist_lock -> RCU conversion Thomas Gleixner
2009-12-09 14:19 ` [patch 1/3] audit: Call tty_audit_push_task() outside preempt disabled Thomas Gleixner
2009-12-09 14:19 ` [patch 2/3] audit: Do not send uninitialized data for AUDIT_TTY_GET Thomas Gleixner
2009-12-09 14:19 ` [patch 3/3] audit: Use rcu for task lookup protection Thomas Gleixner
2010-09-07 13:59 [patch 0/3] audit: Fixes and tasklist_lock -> RCU conversion - Resend Thomas Gleixner
2010-09-07 14:00 ` [patch 3/3] audit: Use rcu for task lookup protection Thomas Gleixner
2010-09-07 18:25   ` Oleg Nesterov
2010-09-07 20:25     ` Thomas Gleixner
2010-09-08 12:44       ` Oleg Nesterov

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.