Hi,
just my 2 cents:

On Wednesday 02 October 2013 00:22:31 Ryan Mallon wrote:
> 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 <rmal...@gmail.com>
> ---
> 
> diff --git a/miscutils/crontab.c b/miscutils/crontab.c
> index 4731d8d..b506935 100644
> --- a/miscutils/crontab.c
> +++ b/miscutils/crontab.c
> @@ -57,24 +57,32 @@ 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;
> -
> -     pid = xvfork();
> -     if (pid) { /* PARENT */
> -             if (wait4pid(pid) == 0) {
> -                     /* exitcode 0: child says it can read */
> -                     return open(file, O_RDONLY);
> -             }
> -             return -1;
> -     }
> -
> -     /* 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);
> +     uid_t old_euid;
> +     gid_t old_egid;
> +     int fd, err;
> +
> +     /* Save and drop privileges */
> +     old_euid = geteuid();
> +     old_egid = getegid();

Making this a function could eventually reduce size.

change_privileges(uid_t uid, gid_t gid)
{
        if ( setegid(gid) < 0 || seteuid(uid) < 0)
                bb_perror_msg_and_die("failed to set egid=%d  euid=%d ", gid, 
uid);
}

> +     err = setegid(pas->pw_gid);
> +     if (err)
> +             bb_perror_msg_and_die("failed to drop privileges");
> +     err = seteuid(pas->pw_uid);
> +     if (err)
> +             bb_perror_msg_and_die("failed to drop privileges");
> +
> +     /* Open the file as the specified user */
> +     fd = xopen(file, O_RDONLY);
> +
> +     /* Restore privileges */
> +     err = setegid(old_egid);
> +     if (err)
> +             bb_perror_msg_and_die("failed to restore privileges");
> +     err = seteuid(old_euid);
> +     if (err)
> +             bb_perror_msg_and_die("failed to restore privileges");
> +
> +     return fd;
>  }
>  
>  int crontab_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
> 

Ciao,
Tito
_______________________________________________
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to