1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 20:27:45 +00:00

passwd+LibCore: Make passwd replace /etc files atomically

Before this patch, we had a nasty race condition when changing a user's
password: there was a time window between truncating /etc/shadow and
writing out its new contents, where you could simply "su" to root
without using a password.

Instead of writing directly to /etc/passwd and /etc/shadow, we now
create temporary files in /etc and fill them with the new contents.
Those files are then atomically renamed to /etc/passwd and /etc/shadow.

Sadly, fixing this race requires giving the passwd program a lot more
privileges. This is something we can and should improve upon. :^)
This commit is contained in:
Andreas Kling 2021-01-21 09:58:31 +01:00
parent c9a7f81dc3
commit 77e0598c6d
2 changed files with 54 additions and 52 deletions

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2020, Peter Elliott <pelliott@ualberta.ca>
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -39,22 +40,17 @@ int main(int argc, char** argv)
return 1;
}
if (pledge("stdio wpath rpath cpath tty id", nullptr) < 0) {
if (setegid(0) < 0) {
perror("setegid");
return 1;
}
if (pledge("stdio wpath rpath wpath cpath fattr tty", nullptr) < 0) {
perror("pledge");
return 1;
}
if (unveil("/etc/passwd", "rwc") < 0) {
perror("unveil");
return 1;
}
if (unveil("/etc/group", "rwc") < 0) {
perror("unveil");
return 1;
}
if (unveil("/etc/shadow", "rwc") < 0) {
if (unveil("/etc", "rwc") < 0) {
perror("unveil");
return 1;
}
@ -86,23 +82,9 @@ int main(int argc, char** argv)
return 1;
}
// Drop privileges after opening all the files through the Core::Account object.
auto gid = getgid();
if (setresgid(gid, gid, gid) < 0) {
perror("setresgid");
return 1;
}
auto uid = getuid();
if (setresuid(uid, uid, uid) < 0) {
perror("setresuid");
return 1;
}
// Make sure /etc/passwd is open and ready for reading, then we can drop a bunch of pledge promises.
setpwent();
if (pledge("stdio tty", nullptr) < 0) {
if (pledge("stdio rpath wpath cpath fattr tty", nullptr) < 0) {
perror("pledge");
return 1;
}
@ -131,7 +113,7 @@ int main(int argc, char** argv)
target_account.set_password(new_password.value().characters());
}
if (pledge("stdio", nullptr) < 0) {
if (pledge("stdio rpath wpath cpath fattr", nullptr) < 0) {
perror("pledge");
return 1;
}