Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(16)

Side by Side Diff: util/mach/task_for_pid.cc

Issue 728973002: Add TaskForPID() (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@process_info
Patch Set: Rebase Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « util/mach/task_for_pid.h ('k') | util/util.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2014 The Crashpad Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "util/mach/task_for_pid.h"
16
17 #include <sys/sysctl.h>
18 #include <unistd.h>
19
20 #include <algorithm>
21 #include <iterator>
22 #include <set>
23
24 #include "base/basictypes.h"
25 #include "base/mac/mach_logging.h"
26 #include "base/mac/scoped_mach_port.h"
27 #include "util/posix/process_info.h"
28
29 namespace crashpad {
30
31 namespace {
32
33 //! \brief Determines whether the groups that \a process_reader belongs to are
34 //! a subset of the groups that the current process belongs to.
35 //!
36 //! This function is similar to 10.9.5
37 //! `xnu-2422.115.4/bsd/kern/kern_credential.c` `kauth_cred_gid_subset()`.
38 bool TaskForPIDGroupCheck(const ProcessInfo& process_info) {
39 std::set<gid_t> groups = process_info.AllGroups();
40
41 ProcessInfo process_info_self;
42 if (!process_info_self.Initialize(getpid())) {
43 return false;
44 }
45
46 std::set<gid_t> groups_self = process_info_self.AllGroups();
47
48 // difference will only contain elements of groups not present in groups_self.
49 // It will not contain elements of groups_self not present in groups. (That
50 // would be std::set_symmetric_difference.)
51 std::set<gid_t> difference;
52 std::set_difference(groups.begin(),
53 groups.end(),
54 groups_self.begin(),
55 groups_self.end(),
56 std::inserter(difference, difference.begin()));
57 if (!difference.empty()) {
58 LOG(ERROR) << "permission denied (gid)";
59 return false;
60 }
61
62 return true;
63 }
64
65 //! \brief Determines whether the current process should have permission to
66 //! access the specified task port.
67 //!
68 //! This function is similar to 10.9.5
69 //! `xnu-2422.115.4/bsd/vm/vm_unix.c` `task_for_pid_posix_check()`.
70 //!
71 //! This function accepts a `task_t` argument instead of a `pid_t` argument,
72 //! implying that the task send right must be retrieved before it can be
73 //! checked. This is done because a `pid_t` argument may refer to a different
74 //! task in between the time that access is checked and its corresponding
75 //! `task_t` is obtained by `task_for_pid()`. When `task_for_pid()` is called
76 //! first, any operations requiring the process ID will call `pid_for_task()`
77 //! and be guaranteed to use the process ID corresponding to the correct task,
78 //! or to fail if that task is no longer running. If the task dies and the PID
79 //! is recycled, it is still possible to look up the wrong PID, but falsely
80 //! granting task access based on the new process’ characteristics is harmless
81 //! because the task will be a dead name at that point.
82 bool TaskForPIDCheck(task_t task) {
83 // If the effective user ID is not 0, then this code is not running as root at
84 // all, and the kernel’s own checks are sufficient to determine access. The
85 // point of this function is to simulate the kernel’s own checks when the
86 // effective user ID is 0 but the real user ID is anything else.
87 if (geteuid() != 0) {
88 return true;
89 }
90
91 // If the real user ID is 0, then this code is not running setuid root, it’s
92 // genuinely running as root, and it should be allowed maximum access.
93 uid_t uid = getuid();
94 if (uid == 0) {
95 return true;
96 }
97
98 // task_for_pid_posix_check() would permit access to the running process’ own
99 // task here, and would then check the kern.tfp.policy sysctl. If set to
100 // KERN_TFP_POLICY_DENY, it would deny access.
101 //
102 // This behavior is not duplicated here because the point of this function is
103 // to permit task_for_pid() access for setuid root programs. It is assumed
104 // that a setuid root program ought to be able to overcome any policy set in
105 // kern.tfp.policy.
106 //
107 // Access to the running process’ own task is not granted outright and is
108 // instead subjected to the same user/group ID checks as any other process.
109 // This has the effect of denying access to the running process’ own task when
110 // it is setuid root. This is intentional, because it prevents the same sort
111 // of cross-privilege disclosure discussed below at the DidChangePriveleges()
112 // check. The running process can still access its own task port via
113 // mach_task_self(), but a non-root user cannot coerce a setuid root tool to
114 // operate on itself by specifying its own process ID to this TaskForPID()
115 // interface.
116
117 ProcessInfo process_info;
118 if (!process_info.InitializeFromTask(task)) {
119 return false;
120 }
121
122 // The target process’ real user ID, effective user ID, and saved set-user ID
123 // must match this process’ own real user ID. task_for_pid_posix_check()
124 // checks against the current process’ effective user ID, but for the purposes
125 // of this function, when running setuid root, the real user ID is the correct
126 // choice.
127 if (process_info.RealUserID() != uid ||
128 process_info.EffectiveUserID() != uid ||
129 process_info.SavedUserID() != uid) {
130 LOG(ERROR) << "permission denied (uid)";
131 return false;
132 }
133
134 // The target process must not have changed privileges. The rationale for this
135 // check is explained in 10.9.5 xnu-2422.115.4/bsd/kern/kern_prot.c
136 // issetugid(): processes that have changed privileges may have loaded data
137 // using different credentials than they are currently operating with, and
138 // allowing other processes access to this data based solely on a check of the
139 // current credentials could violate confidentiality.
140 if (process_info.DidChangePrivileges()) {
141 LOG(ERROR) << "permission denied (P_SUGID)";
142 return false;
143 }
144
145 return TaskForPIDGroupCheck(process_info);
146 }
147
148 } // namespace
149
150 task_t TaskForPID(pid_t pid) {
151 task_t task;
152 kern_return_t kr = task_for_pid(mach_task_self(), pid, &task);
153 if (kr != KERN_SUCCESS) {
154 MACH_LOG(ERROR, kr) << "task_for_pid";
155 return TASK_NULL;
156 }
157
158 base::mac::ScopedMachSendRight task_owner(task);
159
160 if (!TaskForPIDCheck(task)) {
161 return TASK_NULL;
162 }
163
164 return task_owner.release();
165 }
166
167 } // namespace crashpad
OLDNEW
« no previous file with comments | « util/mach/task_for_pid.h ('k') | util/util.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698