Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thejh/e163071dfe4c96a9f9b589b7a2c24fc6 to your computer and use it in GitHub Desktop.
Save thejh/e163071dfe4c96a9f9b589b7a2c24fc6 to your computer and use it in GitHub Desktop.
some old tty hardening patches
From cd0bd8ae7e4afb8050657b73d65e3ddeccd44b9b Mon Sep 17 00:00:00 2001
From: Jann Horn <jann@thejh.net>
Date: Sat, 12 Dec 2015 02:59:28 +0100
Subject: [PATCH] drivers/tty: add protected_ttys sysctl
This new fs.protected_ttys sysctl can be set to 1 to require
CAP_SYS_ADMIN for the TIOCSTI ioctl (which lets the caller
push input back into the TTY and thereby fake input to other
processes that read from the same TTY).
This is a well-known security issue that hasn't been handled
particularly well in userland, e.g. allowing a user to whose
account root switches using "su" to write input to root's
shell, which is running with root privileges. Additionally,
it has increased the impact of other security issues and
requires care by LSMs to ensure that restricted processes
can't fiddle with the TTYs of more privileged processes
running under the same user.
TIOCSTI is relatively exotic, the only legitimate users I
found after a quick look are gpm and agetty. For most
users, turning this sysctl on should be no problem.
Signed-off-by: Jann Horn <jann@thejh.net>
---
drivers/tty/tty_io.c | 6 +++++-
include/linux/tty.h | 11 +++++++++++
kernel/sysctl.c | 10 ++++++++++
3 files changed, 26 insertions(+), 1 deletion(-)
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index bcc8e1e..1f4581d 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -126,6 +126,8 @@ struct ktermios tty_std_termios = { /* for the benefit of tty drivers */
.c_ospeed = 38400
};
+int sysctl_protected_ttys __read_mostly;
+
EXPORT_SYMBOL(tty_std_termios);
/* This list gets poked at by procfs and various bits of boot up code. This
@@ -2270,8 +2272,10 @@ static int tiocsti(struct tty_struct *tty, char __user *p)
{
char ch, mbz = 0;
struct tty_ldisc *ld;
+ bool needpriv = current->signal->tty != tty
+ || (sysctl_protected_ttys & PROT_TTY_NOFAKE) != 0;
- if ((current->signal->tty != tty) && !capable(CAP_SYS_ADMIN))
+ if (needpriv && !capable(CAP_SYS_ADMIN))
return -EPERM;
if (get_user(ch, p))
return -EFAULT;
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 5e31f1b..6033d6a 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -674,3 +674,14 @@ static inline void proc_tty_unregister_driver(struct tty_driver *d) {}
} while (0)
#endif
+
+
+/*
+ * There are many ways in which an attacker can get hold of a TTY's
+ * file descriptor, both through leaks from a privileged parent to
+ * a less privileged child and through other attacks. The system
+ * administrator can set this flag to reduce the impact of such
+ * attacks a lot.
+ */
+#define PROT_TTY_NOFAKE 1
+extern int sysctl_protected_ttys;
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index dc6858d..2e0fa3a 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -65,6 +65,7 @@
#include <linux/sched/sysctl.h>
#include <linux/kexec.h>
#include <linux/bpf.h>
+#include <linux/tty.h>
#include <asm/uaccess.h>
#include <asm/processor.h>
@@ -1712,6 +1713,15 @@ static struct ctl_table fs_table[] = {
.extra2 = &one,
},
{
+ .procname = "protected_ttys",
+ .data = &sysctl_protected_ttys,
+ .maxlen = sizeof(int),
+ .mode = 0600,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = &zero,
+ .extra2 = &one,
+ },
+ {
.procname = "suid_dumpable",
.data = &suid_dumpable,
.maxlen = sizeof(int),
--
2.1.4
From 31e838e969d229cb0db9c3edb4c2d1807691fcd1 Mon Sep 17 00:00:00 2001
From: Jann Horn <jann@thejh.net>
Date: Sat, 12 Dec 2015 04:37:59 +0100
Subject: [PATCH 2/2] tty: add paranoid mode to protected_ttys sysctl
With this commit, protected_ttys becomes a bitmask that can not
only be used to restrict TIOCSTI, but also to harden the system
against malicious programs that attempt to read from the terminal
from the background (across a privilege boundary).
Be careful with this option (PROT_TTY_EXCL_READ, value 2) - it
might cause false-positives and make your TTYs unusable.
Signed-off-by: Jann Horn <jann@thejh.net>
---
drivers/tty/n_tty.c | 19 ++++++++++++++-----
include/linux/tty.h | 12 ++++++++++++
kernel/sysctl.c | 3 ++-
3 files changed, 28 insertions(+), 6 deletions(-)
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index ed77614..577199a 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -2189,12 +2189,21 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
/*
* Internal serialization of reads.
*/
- if (file->f_flags & O_NONBLOCK) {
- if (!mutex_trylock(&ldata->atomic_read_lock))
- return -EAGAIN;
+ if ((sysctl_protected_ttys & PROT_TTY_EXCL_READ) != 0) {
+ if (!mutex_trylock(&ldata->atomic_read_lock)) {
+ set_bit(TTY_IO_ERROR, &tty->flags);
+ pr_warn("%s: killed to mitigate possible attack: simultaneous reads by two processes\n",
+ tty_name(tty));
+ return -EIO;
+ }
} else {
- if (mutex_lock_interruptible(&ldata->atomic_read_lock))
- return -ERESTARTSYS;
+ if (file->f_flags & O_NONBLOCK) {
+ if (!mutex_trylock(&ldata->atomic_read_lock))
+ return -EAGAIN;
+ } else {
+ if (mutex_lock_interruptible(&ldata->atomic_read_lock))
+ return -ERESTARTSYS;
+ }
}
down_read(&tty->termios_rwsem);
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 6033d6a..701a0e5 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -684,4 +684,16 @@ static inline void proc_tty_unregister_driver(struct tty_driver *d) {}
* attacks a lot.
*/
#define PROT_TTY_NOFAKE 1
+/*
+ * Normally, only one program at a time reads from a TTY - when
+ * multiple programs read from it, chaos will happen. However, if an
+ * attacker wants to steal keypresses or input lines from the user,
+ * the attacker usually has to perform a read while another program
+ * is legitimately attempting to read from the console.
+ * This flag disallows this behavior and kills the TTY if such an
+ * attempt is detected.
+ * Note that this only defends programs that read from the TTY
+ * with blocking. Polling is harder to get right and rarer.
+ */
+#define PROT_TTY_EXCL_READ 2
extern int sysctl_protected_ttys;
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 2e0fa3a..389133a 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -124,6 +124,7 @@ static int __maybe_unused neg_one = -1;
static int zero;
static int __maybe_unused one = 1;
static int __maybe_unused two = 2;
+static int __maybe_unused three = 3;
static int __maybe_unused four = 4;
static unsigned long one_ul = 1;
static int one_hundred = 100;
@@ -1719,7 +1720,7 @@ static struct ctl_table fs_table[] = {
.mode = 0600,
.proc_handler = proc_dointvec_minmax,
.extra1 = &zero,
- .extra2 = &one,
+ .extra2 = &three,
},
{
.procname = "suid_dumpable",
--
2.1.4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment