summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Drew DeVault <sir@cmpwn.com>2018-10-06 12:17:36 -0400
committerLibravatar Drew DeVault <sir@cmpwn.com>2018-10-06 12:20:12 -0400
commitc89e00a97e6bb04c6b4b5c906befdb4767540dbe (patch)
treea4ccf0cb0afafc0c8db6cbded85a3b156945b12b
parentUpdate CONTRIBUTING.md (diff)
downloadsway-c89e00a97e6bb04c6b4b5c906befdb4767540dbe.tar.gz
sway-c89e00a97e6bb04c6b4b5c906befdb4767540dbe.tar.zst
sway-c89e00a97e6bb04c6b4b5c906befdb4767540dbe.zip
Fix swaylock w/shadow on glibc, improve security
Today I learned that GNU flaunts the POSIX standard in yet another creative way. Additionally, this adds some security improvements, namely: - Zeroing out password buffers in the privileged child process - setuid/setgid after reading /etc/shadow
-rw-r--r--meson.build1
-rw-r--r--swaylock/meson.build3
-rw-r--r--swaylock/shadow.c27
3 files changed, 31 insertions, 0 deletions
diff --git a/meson.build b/meson.build
index 1e7ce281..42386fbc 100644
--- a/meson.build
+++ b/meson.build
@@ -44,6 +44,7 @@ gdk_pixbuf = dependency('gdk-pixbuf-2.0', required: false)
44pixman = dependency('pixman-1') 44pixman = dependency('pixman-1')
45libinput = dependency('libinput', version: '>=1.6.0') 45libinput = dependency('libinput', version: '>=1.6.0')
46libpam = cc.find_library('pam', required: false) 46libpam = cc.find_library('pam', required: false)
47crypt = cc.find_library('crypt', required: false)
47systemd = dependency('libsystemd', required: false) 48systemd = dependency('libsystemd', required: false)
48elogind = dependency('libelogind', required: false) 49elogind = dependency('libelogind', required: false)
49math = cc.find_library('m') 50math = cc.find_library('m')
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
26 warning('The swaylock binary must be setuid when compiled without libpam') 26 warning('The swaylock binary must be setuid when compiled without libpam')
27 warning('You must do this manually post-install: chmod a+s /path/to/swaylock') 27 warning('You must do this manually post-install: chmod a+s /path/to/swaylock')
28 sources += ['shadow.c'] 28 sources += ['shadow.c']
29 if crypt.found()
30 dependencies += [crypt]
31 endif
29endif 32endif
30 33
31executable('swaylock', 34executable('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 @@
6#include <unistd.h> 6#include <unistd.h>
7#include <wlr/util/log.h> 7#include <wlr/util/log.h>
8#include "swaylock/swaylock.h" 8#include "swaylock/swaylock.h"
9#ifdef __GLIBC__
10// GNU, you damn slimy bastard
11#include <crypt.h>
12#endif
9 13
10static int comm[2][2]; 14static int comm[2][2];
11 15
16static void clear_buffer(void *buf, size_t bytes) {
17 volatile char *buffer = buf;
18 volatile char zero = '\0';
19 for (size_t i = 0; i < bytes; ++i) {
20 buffer[i] = zero;
21 }
22}
23
12void run_child(void) { 24void run_child(void) {
13 /* This code runs as root */ 25 /* This code runs as root */
14 struct passwd *pwent = getpwuid(getuid()); 26 struct passwd *pwent = getpwuid(getuid());
@@ -25,6 +37,17 @@ void run_child(void) {
25 } 37 }
26 encpw = swent->sp_pwdp; 38 encpw = swent->sp_pwdp;
27 } 39 }
40
41 /* We don't need any additional logging here because the parent process will
42 * also fail here and will handle logging for us. */
43 if (setgid(getgid()) != 0) {
44 exit(EXIT_FAILURE);
45 }
46 if (setuid(getuid()) != 0) {
47 exit(EXIT_FAILURE);
48 }
49
50 /* This code does not run as root */
28 wlr_log(WLR_DEBUG, "prepared to authorize user %s", pwent->pw_name); 51 wlr_log(WLR_DEBUG, "prepared to authorize user %s", pwent->pw_name);
29 52
30 size_t size; 53 size_t size;
@@ -60,10 +83,14 @@ void run_child(void) {
60 result = strcmp(c, encpw) == 0; 83 result = strcmp(c, encpw) == 0;
61 if (write(comm[1][1], &result, sizeof(result)) != sizeof(result)) { 84 if (write(comm[1][1], &result, sizeof(result)) != sizeof(result)) {
62 wlr_log_errno(WLR_ERROR, "failed to write pw check result"); 85 wlr_log_errno(WLR_ERROR, "failed to write pw check result");
86 clear_buffer(buf, size);
63 exit(EXIT_FAILURE); 87 exit(EXIT_FAILURE);
64 } 88 }
89 clear_buffer(buf, size);
65 free(buf); 90 free(buf);
66 } 91 }
92
93 clear_buffer(encpw, strlen(encpw));
67 exit(EXIT_SUCCESS); 94 exit(EXIT_SUCCESS);
68} 95}
69 96