From 2e28d38ae1d9ced6ac2deb4001aca3f267304cdb Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sat, 9 Jan 2016 22:55:33 -0800 Subject: [PATCH] tty: audit: Handle tty audit enable atomically The audit_tty and audit_tty_log_passwd fields are actually bool values, so merge into single memory location to access atomically. NB: audit log operations may still occur after tty audit is disabled which is consistent with the existing functionality Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_audit.c | 53 +++++++++++++++++------------------------ include/linux/audit.h | 4 ++++ include/linux/sched.h | 1 - kernel/audit.c | 25 ++++++++++--------- 4 files changed, 38 insertions(+), 45 deletions(-) diff --git a/drivers/tty/tty_audit.c b/drivers/tty/tty_audit.c index 50380d87061d..3d90f88c5ff9 100644 --- a/drivers/tty/tty_audit.c +++ b/drivers/tty/tty_audit.c @@ -131,7 +131,6 @@ void tty_audit_exit(void) void tty_audit_fork(struct signal_struct *sig) { sig->audit_tty = current->signal->audit_tty; - sig->audit_tty_log_passwd = current->signal->audit_tty_log_passwd; } /** @@ -141,11 +140,9 @@ void tty_audit_tiocsti(struct tty_struct *tty, char ch) { struct tty_audit_buf *buf; dev_t dev; - int should_audit; unsigned long flags; spin_lock_irqsave(¤t->sighand->siglock, flags); - should_audit = current->signal->audit_tty; buf = current->signal->tty_audit_buf; if (buf) atomic_inc(&buf->count); @@ -160,7 +157,7 @@ void tty_audit_tiocsti(struct tty_struct *tty, char ch) tty_audit_buf_put(buf); } - if (should_audit && audit_enabled) { + if (audit_enabled && (current->signal->audit_tty & AUDIT_TTY_ENABLE)) { kuid_t auid; unsigned int sessionid; @@ -177,29 +174,25 @@ void tty_audit_tiocsti(struct tty_struct *tty, char ch) */ int tty_audit_push(void) { - struct tty_audit_buf *buf = ERR_PTR(-EPERM); + struct tty_audit_buf *buf; unsigned long flags; + if (~current->signal->audit_tty & AUDIT_TTY_ENABLE) + return -EPERM; + spin_lock_irqsave(¤t->sighand->siglock, flags); - if (current->signal->audit_tty) { - buf = current->signal->tty_audit_buf; - if (buf) - atomic_inc(&buf->count); - } + buf = current->signal->tty_audit_buf; + if (buf) + atomic_inc(&buf->count); spin_unlock_irqrestore(¤t->sighand->siglock, flags); - /* - * Return 0 when signal->audit_tty set - * but current->signal->tty_audit_buf == NULL. - */ - if (!buf || IS_ERR(buf)) - return PTR_ERR(buf); + if (buf) { + mutex_lock(&buf->mutex); + tty_audit_buf_push(buf); + mutex_unlock(&buf->mutex); - mutex_lock(&buf->mutex); - tty_audit_buf_push(buf); - mutex_unlock(&buf->mutex); - - tty_audit_buf_put(buf); + tty_audit_buf_put(buf); + } return 0; } @@ -218,8 +211,6 @@ static struct tty_audit_buf *tty_audit_buf_get(void) buf = NULL; buf2 = NULL; spin_lock_irqsave(¤t->sighand->siglock, flags); - if (likely(!current->signal->audit_tty)) - goto out; buf = current->signal->tty_audit_buf; if (buf) { atomic_inc(&buf->count); @@ -233,9 +224,10 @@ static struct tty_audit_buf *tty_audit_buf_get(void) return NULL; } - spin_lock_irqsave(¤t->sighand->siglock, flags); - if (!current->signal->audit_tty) + if (~current->signal->audit_tty & AUDIT_TTY_ENABLE) goto out; + + spin_lock_irqsave(¤t->sighand->siglock, flags); buf = current->signal->tty_audit_buf; if (!buf) { current->signal->tty_audit_buf = buf2; @@ -259,9 +251,8 @@ static struct tty_audit_buf *tty_audit_buf_get(void) void tty_audit_add_data(struct tty_struct *tty, const void *data, size_t size) { struct tty_audit_buf *buf; - int audit_log_tty_passwd; - unsigned long flags; unsigned int icanon = !!L_ICANON(tty); + unsigned int audit_tty; dev_t dev; if (unlikely(size == 0)) @@ -271,10 +262,10 @@ void tty_audit_add_data(struct tty_struct *tty, const void *data, size_t size) && tty->driver->subtype == PTY_TYPE_MASTER) return; - spin_lock_irqsave(¤t->sighand->siglock, flags); - audit_log_tty_passwd = current->signal->audit_tty_log_passwd; - spin_unlock_irqrestore(¤t->sighand->siglock, flags); - if (!audit_log_tty_passwd && icanon && !L_ECHO(tty)) + audit_tty = READ_ONCE(current->signal->audit_tty); + if (~audit_tty & AUDIT_TTY_ENABLE) + return; + if ((~audit_tty & AUDIT_TTY_LOG_PASSWD) && icanon && !L_ECHO(tty)) return; buf = tty_audit_buf_get(); diff --git a/include/linux/audit.h b/include/linux/audit.h index b40ed5df5542..e38e3fc13ea8 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -109,6 +109,10 @@ extern int audit_classify_compat_syscall(int abi, unsigned syscall); /* maximized args number that audit_socketcall can process */ #define AUDITSC_ARGS 6 +/* bit values for ->signal->audit_tty */ +#define AUDIT_TTY_ENABLE BIT(0) +#define AUDIT_TTY_LOG_PASSWD BIT(1) + struct filename; extern void audit_log_session_info(struct audit_buffer *ab); diff --git a/include/linux/sched.h b/include/linux/sched.h index a10494a94cc3..a389222e9703 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -775,7 +775,6 @@ struct signal_struct { #endif #ifdef CONFIG_AUDIT unsigned audit_tty; - unsigned audit_tty_log_passwd; struct tty_audit_buf *tty_audit_buf; #endif diff --git a/kernel/audit.c b/kernel/audit.c index 610f221df069..2651e423b2dc 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -1030,20 +1030,19 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) break; case AUDIT_TTY_GET: { struct audit_tty_status s; - struct task_struct *tsk = current; + unsigned int t; - spin_lock(&tsk->sighand->siglock); - s.enabled = tsk->signal->audit_tty; - s.log_passwd = tsk->signal->audit_tty_log_passwd; - spin_unlock(&tsk->sighand->siglock); + t = READ_ONCE(current->signal->audit_tty); + s.enabled = t & AUDIT_TTY_ENABLE; + s.log_passwd = !!(t & AUDIT_TTY_LOG_PASSWD); audit_send_reply(skb, seq, AUDIT_TTY_GET, 0, 0, &s, sizeof(s)); break; } case AUDIT_TTY_SET: { struct audit_tty_status s, old; - struct task_struct *tsk = current; struct audit_buffer *ab; + unsigned int t; memset(&s, 0, sizeof(s)); /* guard against past and future API changes */ @@ -1053,14 +1052,14 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) (s.log_passwd != 0 && s.log_passwd != 1)) err = -EINVAL; - spin_lock(&tsk->sighand->siglock); - old.enabled = tsk->signal->audit_tty; - old.log_passwd = tsk->signal->audit_tty_log_passwd; - if (!err) { - tsk->signal->audit_tty = s.enabled; - tsk->signal->audit_tty_log_passwd = s.log_passwd; + if (err) + t = READ_ONCE(current->signal->audit_tty); + else { + t = s.enabled | (-s.log_passwd & AUDIT_TTY_LOG_PASSWD); + t = xchg(¤t->signal->audit_tty, t); } - spin_unlock(&tsk->sighand->siglock); + old.enabled = t & AUDIT_TTY_ENABLE; + old.log_passwd = !!(t & AUDIT_TTY_LOG_PASSWD); audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE); audit_log_format(ab, " op=tty_set old-enabled=%d new-enabled=%d"