The open_as_user() function in miscutils/crontab.c uses a child process to drop privileges and check that the file is readable by the specified user. If the child is successful then the (setuid) parent opens the file.
This is racy because the file can be changed on disk (e.g. modified symlink) between the child exiting and the parent re-opening the file. This could allow an non-privileged user to pass a file to crontab that it does not have read access to. In practice this race is probably easy to win since a schedule must occur before the parent re-opens the file. Fix the race by using saving the effective uid/gid, and then setting the effective uid/gid to the specified user. The file is opened as the specified user, and then the old privileges are restored. Signed-off-by: Ryan Mallon <[email protected]> --- miscutils/crontab.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/miscutils/crontab.c b/miscutils/crontab.c index 4731d8d..ec4ef68 100644 --- a/miscutils/crontab.c +++ b/miscutils/crontab.c @@ -57,24 +57,19 @@ static void edit_file(const struct passwd *pas, const char *file) static int open_as_user(const struct passwd *pas, const char *file) { - pid_t pid; - char c; + uid_t old_euid = getuid(); + gid_t old_egid = getgid(); + int fd; - pid = xvfork(); - if (pid) { /* PARENT */ - if (wait4pid(pid) == 0) { - /* exitcode 0: child says it can read */ - return open(file, O_RDONLY); - } - return -1; - } + xsetegid(pas->pw_gid); + xseteuid(pas->pw_uid); - /* CHILD */ - /* initgroups, setgid, setuid */ - change_identity(pas); - /* We just try to read one byte. If it works, file is readable - * under this user. We signal that by exiting with 0. */ - _exit(safe_read(xopen(file, O_RDONLY), &c, 1) < 0); + fd = open(file, O_RDONLY); + + xseteuid(old_euid); + xsetegid(old_egid); + + return fd; } int crontab_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -- 1.7.9.7 _______________________________________________ busybox mailing list [email protected] http://lists.busybox.net/mailman/listinfo/busybox
