--- ./src/programs/pkexec.c.orig 2010-03-10 11:46:19.000000000 -0600 +++ ./src/programs/pkexec.c 2011-04-19 23:14:40.505000017 -0500 @@ -38,6 +38,10 @@ #include #include +#ifdef __linux__ +#include +#endif + #include static gchar *original_user_name = NULL; @@ -410,7 +414,6 @@ GPtrArray *saved_env; gchar *opt_user; pid_t pid_of_caller; - uid_t uid_of_caller; ret = 127; authority = NULL; @@ -578,40 +581,49 @@ */ g_type_init (); - /* now check if the program that invoked us is authorized */ + /* make sure we are nuked if the parent process dies */ +#ifdef __linux__ + if (prctl (PR_SET_PDEATHSIG, SIGTERM) != 0) + { + g_printerr ("prctl(PR_SET_PDEATHSIG, SIGTERM) failed: %s\n", g_strerror (errno)); + goto out; + } +#else +#warning "Please add OS specific code to catch when the parent dies" +#endif + + /* Figure out the parent process */ pid_of_caller = getppid (); if (pid_of_caller == 1) { /* getppid() can return 1 if the parent died (meaning that we are reaped - * by /sbin/init); get process group leader instead - for example, this - * happens when launching via gnome-panel (alt+f2, then 'pkexec gedit'). + * by /sbin/init); In that case we simpy bail. */ - pid_of_caller = getpgrp (); - } - - subject = polkit_unix_process_new (pid_of_caller); - if (subject == NULL) - { - g_printerr ("No such process for pid %d: %s\n", (gint) pid_of_caller, error->message); - g_error_free (error); + g_printerr ("Refusing to render service to dead parents.\n"); goto out; } - /* paranoia: check that the uid of pid_of_caller matches getuid() */ - error = NULL; - uid_of_caller = polkit_unix_process_get_owner (POLKIT_UNIX_PROCESS (subject), - &error); - if (error != NULL) - { - g_printerr ("Error determing pid of caller (pid %d): %s\n", (gint) pid_of_caller, error->message); - g_error_free (error); - goto out; - } - if (uid_of_caller != getuid ()) - { - g_printerr ("User of caller (%d) does not match our uid (%d)\n", uid_of_caller, getuid ()); - goto out; - } + /* This process we want to check an authorization for is the process + * that launched us - our parent process. + * + * At the time the parent process fork()'ed and exec()'ed us, the + * process had the same real-uid that we have now. So we use this + * real-uid instead of of looking it up to avoid TOCTTOU issues + * (consider the parent process exec()'ing a setuid helper). + * + * On the other hand, the monotonic process start-time is guaranteed + * to never change so it's safe to look that up given only the PID + * since we are guaranteed to be nuked if the parent goes away + * (cf. the prctl(2) call above). + */ + subject = polkit_unix_process_new_for_owner (pid_of_caller, + 0, /* 0 means "look up start-time in /proc" */ + getuid ()); + /* really double-check the invariants guaranteed by the PolkitUnixProcess class */ + g_assert (subject != NULL); + g_assert (polkit_unix_process_get_pid (POLKIT_UNIX_PROCESS (subject)) == pid_of_caller); + g_assert (polkit_unix_process_get_uid (POLKIT_UNIX_PROCESS (subject)) >= 0); + g_assert (polkit_unix_process_get_start_time (POLKIT_UNIX_PROCESS (subject)) > 0); authority = polkit_authority_get ();