diff options
author | Drew DeVault <sir@cmpwn.com> | 2018-10-06 12:17:36 -0400 |
---|---|---|
committer | Drew DeVault <sir@cmpwn.com> | 2018-10-06 12:20:12 -0400 |
commit | c89e00a97e6bb04c6b4b5c906befdb4767540dbe (patch) | |
tree | a4ccf0cb0afafc0c8db6cbded85a3b156945b12b /swaylock | |
parent | Update CONTRIBUTING.md (diff) | |
download | sway-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
Diffstat (limited to 'swaylock')
-rw-r--r-- | swaylock/meson.build | 3 | ||||
-rw-r--r-- | swaylock/shadow.c | 27 |
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 | |||
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 | ||
29 | endif | 32 | endif |
30 | 33 | ||
31 | executable('swaylock', | 34 | 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 @@ | |||
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 | ||
10 | static int comm[2][2]; | 14 | static int comm[2][2]; |
11 | 15 | ||
16 | static 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 | |||
12 | void run_child(void) { | 24 | void 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 | ||