summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Kobel2018-11-07 00:16:50 +0100
committerAlexander Kobel2018-11-07 00:16:50 +0100
commit6368dfe8d45a62bebbfb08a40032a95fba9768bd (patch)
treeaf96ac57e570fdbdd3c2e945a34999f1278a117d
downloadaur-6368dfe8d45a62bebbfb08a40032a95fba9768bd.tar.gz
xscreensaver OOM protection and systemd user service
-rw-r--r--.SRCINFO16
-rw-r--r--LICENSE14
-rw-r--r--PKGBUILD23
-rw-r--r--oom_score_adj.c61
-rw-r--r--xscreensaver-oom-protect.c114
-rw-r--r--xscreensaver.service16
6 files changed, 244 insertions, 0 deletions
diff --git a/.SRCINFO b/.SRCINFO
new file mode 100644
index 000000000000..d88b8c753559
--- /dev/null
+++ b/.SRCINFO
@@ -0,0 +1,16 @@
+pkgbase = xscreensaver-oom-protect
+ pkgdesc = Protect xscreensaver from the out-of-memory killer
+ pkgver = 1.0.0
+ pkgrel = 1
+ arch = x86_64
+ license = custom:WTFPL
+ depends = xscreensaver
+ source = xscreensaver-oom-protect.c
+ source = LICENSE
+ source = xscreensaver.service
+ md5sums = 43175fd1d4dc75bf02311b1cc6de467e
+ md5sums = 8365d07beeb5f39d87e846dca3ae7b64
+ md5sums = bb945c067ae57367ddc6f041fd33dfa4
+
+pkgname = xscreensaver-oom-protect
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 000000000000..ee7d6a54e914
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,14 @@
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+ Version 2, December 2004
+
+ Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
+
+ Everyone is permitted to copy and distribute verbatim or modified
+ copies of this license document, and changing it is allowed as long
+ as the name is changed.
+
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. You just DO WHAT THE FUCK YOU WANT TO.
+
diff --git a/PKGBUILD b/PKGBUILD
new file mode 100644
index 000000000000..a588be22285b
--- /dev/null
+++ b/PKGBUILD
@@ -0,0 +1,23 @@
+# Maintainer: Alexander Kobel <a-kobel@a-kobel.de>
+
+pkgname=xscreensaver-oom-protect
+pkgver=1.0.0
+pkgrel=1
+pkgdesc="Protect xscreensaver from the out-of-memory killer"
+arch=('x86_64')
+license=('custom:WTFPL')
+depends=('xscreensaver')
+source=(${pkgname}.c
+ LICENSE
+ xscreensaver.service)
+md5sums=('43175fd1d4dc75bf02311b1cc6de467e'
+ '8365d07beeb5f39d87e846dca3ae7b64'
+ 'bb945c067ae57367ddc6f041fd33dfa4')
+
+package() {
+ cd ${srcdir}
+ ${CC:-gcc} ${CFLAGS} ${LDFLAGS} -o ${pkgname} ${pkgname}.c
+ install -D -m4755 -t ${pkgdir}/usr/bin ${pkgname}
+ install -D -m644 -t ${pkgdir}/usr/lib/systemd/user xscreensaver.service
+ install -D -m644 -t ${pkgdir}/usr/share/licenses/${pkgname} LICENSE
+}
diff --git a/oom_score_adj.c b/oom_score_adj.c
new file mode 100644
index 000000000000..3fc91dd06a5d
--- /dev/null
+++ b/oom_score_adj.c
@@ -0,0 +1,61 @@
+/* OOM killer adjustment, meant to protect running processes via a small
+ * setuid-ed "wrapper". */
+
+/* (c) 2018 Alexander Kobel <a-kobel@a-kobel.de> */
+/* Published under the WTFPL; see LICENSE. */
+
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <linux/oom.h>
+
+int usage (char **argv) {
+ fprintf (stderr,
+ "Adjust the out-of-memory killer score for a process; "
+ "see man proc(5).\n"
+ "\n"
+ "Usage:\t%s <pid> <oom_score_adj>\n"
+ "\n"
+ " <pid>\n"
+ "\tprocess id\n"
+ " <oom_score_adj>\n"
+ "\tinteger between %d and %d inclusive.\n"
+ "\t(oom_score_adj = %d disables oom killing for this process)\n",
+ argv[0], OOM_SCORE_ADJ_MIN, OOM_SCORE_ADJ_MAX, OOM_SCORE_ADJ_MIN);
+ return EINVAL;
+}
+
+int main (int argc, char **argv) {
+ char *endptr;
+ long pid;
+ long oom_score_adj;
+ char fn[PATH_MAX];
+ int n;
+ FILE *f;
+
+ if (argc != 3)
+ return usage (argv);
+
+ pid = strtol (argv[1], &endptr, 10);
+ if (errno == ERANGE || *endptr != 0 || pid < 1)
+ return usage (argv);
+
+ oom_score_adj = strtol (argv[2], &endptr, 10);
+ if (errno == ERANGE || *endptr != 0
+ || oom_score_adj < OOM_SCORE_ADJ_MIN
+ || oom_score_adj > OOM_SCORE_ADJ_MAX)
+ return usage (argv);
+
+ n = snprintf (fn, PATH_MAX, "/proc/%ld/oom_score_adj", pid);
+ if (n < 0 && n > PATH_MAX)
+ return ENAMETOOLONG;
+ f = fopen (fn, "w");
+ if (f == NULL)
+ return EPERM;
+ fprintf (f, "%ld", oom_score_adj);
+ fclose (f);
+
+ return 0;
+}
diff --git a/xscreensaver-oom-protect.c b/xscreensaver-oom-protect.c
new file mode 100644
index 000000000000..389b09012288
--- /dev/null
+++ b/xscreensaver-oom-protect.c
@@ -0,0 +1,114 @@
+/* protect xscreensaver from the OOM killer via a small
+ * setuid-ed "wrapper".
+ *
+ * An attempt to patch the security hole described in
+ * https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=562884
+ * without globally disabling the magic SysRq functionality
+ * and/or OOM killer, without patching xscreensaver directly.
+ *
+ * Hardcoded to check whether the given pid actually is a process for
+ * /usr/bin/xscreensaver to avoid malicious users protecting arbitrary
+ * other processes.
+ *
+ * If you think you want to consider other screensavers, read
+ * https://www.jwz.org/xscreensaver/faq.html
+ * - in particular, #20 and #28 -
+ * https://www.jwz.org/xscreensaver/faq.html#no-ctl-alt-bs
+ * https://www.jwz.org/xscreensaver/faq.html#gnome-screensaver
+ * and
+ * https://www.jwz.org/xscreensaver/toolkits.html
+ * and think again. */
+
+/* (c) 2018 Alexander Kobel <a-kobel@a-kobel.de> */
+/* Published under the WTFPL; see LICENSE. */
+
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <linux/oom.h>
+
+int usage (char **argv) {
+ fprintf (stderr,
+ "Protect process <pid> from the OOM killer by setting its "
+ "oom_score_adj to %d.\n"
+ "(TL;DR: try to avoid that an attacker types Alt+SysRq+F "
+ "repeatedly and ends up\n"
+ "with your logged-in session without the xscreensaver lock.)\n"
+ "Will fail with error code %d if the process does not run "
+ "/usr/bin/xscreensaver.\n"
+ "For more information and background, see\n"
+ "\tman xscreensaver(1) \"Magic Backdoor Keystrokes\"\n"
+ "\tman proc(5)\n"
+ "\thttps://bugs.debian.org/cgi-bin/bugreport.cgi?bug=562884\n"
+ "\n"
+ "(c) 2018 Alexander Kobel <a-kobel@a-kobel.de>\n"
+ "\n"
+ "Usage:\t%s <pid>\n"
+ "\n"
+ " <pid>\n"
+ "\tprocess id of a /usr/bin/xscreensaver instance\n"
+ "\n"
+ "Example:\n"
+ "\tfor pid in $(pgrep xscreensaver); do\n"
+ "\t\t%s $pid\n"
+ "\tdone\n"
+ "\n"
+ "Preferably called from a supervisor like systemd.\n"
+ "\n"
+ "WARNING: The OOM adjustment is not locked, and may be changed or "
+ "reset again.\n"
+ "As far as the author is aware, the necessary permissions are those "
+ "of the\n"
+ "xscreensaver process itself; and with the same permissions, the "
+ "OOM score\n"
+ "adjustment can be lowered again. Thus, for additional security "
+ "against\n"
+ "*non-malicious* resets, call the equivalent of\n"
+ "\techo %d > /proc/<pid>/oom_score_adj\n"
+ "on each activation of the screensaver (which should be possible "
+ "as non-root).\n"
+ "All bets are off against an attacker that already aquired the "
+ "rights of the\n"
+ "owner of the original xscreensaver process (and, most probably, "
+ "there's no need\n"
+ "to work around that).\n",
+ OOM_SCORE_ADJ_MIN, EINVAL, argv[0], argv[0], OOM_SCORE_ADJ_MIN);
+ return EINVAL;
+}
+
+int main (int argc, char **argv) {
+ char *endptr;
+ long pid;
+ char fn[PATH_MAX];
+ char xscreensaver_exe[PATH_MAX];
+ int n;
+ FILE *f;
+
+ if (argc != 2)
+ return usage (argv);
+
+ pid = strtol (argv[1], &endptr, 10);
+ if (errno == ERANGE || *endptr != 0 || pid < 1)
+ return usage (argv);
+
+ n = snprintf (fn, PATH_MAX, "/proc/%ld/exe", pid);
+ if (n < 0 && n > PATH_MAX)
+ return ENAMETOOLONG;
+ if (realpath (fn, xscreensaver_exe) == NULL)
+ return errno;
+ if (strcmp (xscreensaver_exe, "/usr/bin/xscreensaver") != 0)
+ return EINVAL;
+
+ n = snprintf (fn, PATH_MAX, "/proc/%ld/oom_score_adj", pid);
+ if (n < 0 && n > PATH_MAX)
+ return ENAMETOOLONG;
+ f = fopen (fn, "w");
+ if (f == NULL)
+ return EPERM;
+ fprintf (f, "%d", OOM_SCORE_ADJ_MIN);
+ fclose (f);
+
+ return 0;
+}
diff --git a/xscreensaver.service b/xscreensaver.service
new file mode 100644
index 000000000000..c85317a8e9e5
--- /dev/null
+++ b/xscreensaver.service
@@ -0,0 +1,16 @@
+[Unit]
+Description=xscreensaver with OOM killer protection
+Documentation=man:xscreensaver man:xscreensaver-command man:xscreensaver-demo
+
+[Service]
+Type=simple
+ExecStartPre=/usr/bin/xscreensaver-command -exit
+ExecStart=/usr/bin/xscreensaver -nosplash -no-capture-stderr
+ExecStartPost=/usr/bin/xscreensaver-oom-protect $MAINPID
+ExecReload=/usr/bin/xscreensaver-command -restart
+ExecStop=/usr/bin/xscreensaver-command -exit
+Restart=always
+
+[Install]
+WantedBy=default.target
+Alias=screensaver.service