From 77e0598c6d5ab732cf43297f629867f01da08833 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Thu, 21 Jan 2021 09:58:31 +0100 Subject: 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. :^) --- Userland/Utilities/passwd.cpp | 34 ++++++++-------------------------- 1 file changed, 8 insertions(+), 26 deletions(-) (limited to 'Userland/Utilities') diff --git a/Userland/Utilities/passwd.cpp b/Userland/Utilities/passwd.cpp index b0a36e437a..62c8b321a4 100644 --- a/Userland/Utilities/passwd.cpp +++ b/Userland/Utilities/passwd.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2020, Peter Elliott + * Copyright (c) 2021, Andreas Kling * 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) { - perror("pledge"); + if (setegid(0) < 0) { + perror("setegid"); return 1; } - if (unveil("/etc/passwd", "rwc") < 0) { - perror("unveil"); - return 1; - } - - if (unveil("/etc/group", "rwc") < 0) { - perror("unveil"); + if (pledge("stdio wpath rpath wpath cpath fattr tty", nullptr) < 0) { + perror("pledge"); 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; } -- cgit v1.2.3