Created
August 24, 2016 23:58
-
-
Save thejh/e163071dfe4c96a9f9b589b7a2c24fc6 to your computer and use it in GitHub Desktop.
some old tty hardening patches
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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