aboutsummaryrefslogtreecommitdiff
path: root/swaylock
diff options
context:
space:
mode:
authoremersion <contact@emersion.fr>2018-10-06 18:47:34 +0200
committerGitHub <noreply@github.com>2018-10-06 18:47:34 +0200
commit176832fe30576ccfbb7dee3d9e600e56abf21da1 (patch)
treea4ccf0cb0afafc0c8db6cbded85a3b156945b12b /swaylock
parent85961f63bfe922831011f75860b3acde3d890a9f (diff)
parentc89e00a97e6bb04c6b4b5c906befdb4767540dbe (diff)
Merge pull request #2776 from swaywm/swaylock-setuid
Fix swaylock w/shadow on glibc, improve security
Diffstat (limited to 'swaylock')
-rw-r--r--swaylock/meson.build3
-rw-r--r--swaylock/shadow.c27
2 files changed, 30 insertions, 0 deletions
diff --git a/swaylock/meson.build b/swaylock/meson.build
index 6605340b..f3321a78 100644
--- a/swaylock/meson.build
+++ b/swaylock/meson.build
@@ -26,6 +26,9 @@ else
warning('The swaylock binary must be setuid when compiled without libpam')
warning('You must do this manually post-install: chmod a+s /path/to/swaylock')
sources += ['shadow.c']
+ if crypt.found()
+ dependencies += [crypt]
+ endif
endif
executable('swaylock',
diff --git a/swaylock/shadow.c b/swaylock/shadow.c
index 1f10514c..f928eaa3 100644
--- a/swaylock/shadow.c
+++ b/swaylock/shadow.c
@@ -6,9 +6,21 @@
#include <unistd.h>
#include <wlr/util/log.h>
#include "swaylock/swaylock.h"
+#ifdef __GLIBC__
+// GNU, you damn slimy bastard
+#include <crypt.h>
+#endif
static int comm[2][2];
+static void clear_buffer(void *buf, size_t bytes) {
+ volatile char *buffer = buf;
+ volatile char zero = '\0';
+ for (size_t i = 0; i < bytes; ++i) {
+ buffer[i] = zero;
+ }
+}
+
void run_child(void) {
/* This code runs as root */
struct passwd *pwent = getpwuid(getuid());
@@ -25,6 +37,17 @@ void run_child(void) {
}
encpw = swent->sp_pwdp;
}
+
+ /* We don't need any additional logging here because the parent process will
+ * also fail here and will handle logging for us. */
+ if (setgid(getgid()) != 0) {
+ exit(EXIT_FAILURE);
+ }
+ if (setuid(getuid()) != 0) {
+ exit(EXIT_FAILURE);
+ }
+
+ /* This code does not run as root */
wlr_log(WLR_DEBUG, "prepared to authorize user %s", pwent->pw_name);
size_t size;
@@ -60,10 +83,14 @@ void run_child(void) {
result = strcmp(c, encpw) == 0;
if (write(comm[1][1], &result, sizeof(result)) != sizeof(result)) {
wlr_log_errno(WLR_ERROR, "failed to write pw check result");
+ clear_buffer(buf, size);
exit(EXIT_FAILURE);
}
+ clear_buffer(buf, size);
free(buf);
}
+
+ clear_buffer(encpw, strlen(encpw));
exit(EXIT_SUCCESS);
}