summaryrefslogtreecommitdiffstats
path: root/patches/source/polkit/CVE-2011-1485/0004-pkexec-Avoid-TOCTTOU-problems-with-parent-process.patch
blob: e17947a9fecea6208c4bdf05269d5a368d2ea148 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
--- ./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 <syslog.h>
 #include <stdarg.h>
 
+#ifdef __linux__
+#include <sys/prctl.h>
+#endif
+
 #include <polkit/polkit.h>
 
 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 ();