diff options
-rw-r--r-- | drivers/char/tty_audit.c | 38 | ||||
-rw-r--r-- | include/linux/tty.h | 9 | ||||
-rw-r--r-- | kernel/audit.c | 25 |
3 files changed, 42 insertions, 30 deletions
diff --git a/drivers/char/tty_audit.c b/drivers/char/tty_audit.c index 1b8ee590b4c..f64582b0f62 100644 --- a/drivers/char/tty_audit.c +++ b/drivers/char/tty_audit.c @@ -188,25 +188,43 @@ void tty_audit_tiocsti(struct tty_struct *tty, char ch) } /** - * 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; } /** diff --git a/include/linux/tty.h b/include/linux/tty.h index e500171c745..2a754748dd5 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -541,8 +541,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) @@ -560,9 +560,10 @@ static inline void tty_audit_fork(struct signal_struct *sig) 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) { + return 0; } #endif diff --git a/kernel/audit.c b/kernel/audit.c index a300931fc45..8429afea37b 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -467,23 +467,16 @@ static int audit_prepare_user_tty(pid_t pid, uid_t loginuid, u32 sessionid) 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; } |