The Pedigree Project 0.1
PosixProcess-credentials.cc
1#include "pedigree/kernel/LockGuard.h"
2#include "pedigree/kernel/processor/Processor.h"
3
4#include "PosixProcess.h"
5#include "modules/system/users/Group.h"
6#include "modules/system/users/User.h"
8#include "user-namespace.h"
9
10namespace {
11TraceTaskRef credentialTaskToken(Thread& task) {
12 TraceTaskRef token;
13 auto* subsystem = static_cast<PosixSubsystem*>(task.getParent()->getSubsystem());
14 if (subsystem) {
15 subsystem->traceContext().taskToken(task, token);
16 }
17 return token;
18}
19} // namespace
20
21PosixProcess::CredentialSnapshot PosixProcess::snapshotCredentials() const {
22 LockGuard<Spinlock> guard(m_CredentialLock);
23 return m_Credentials;
24}
25
26FilesystemCredentials PosixProcess::realFilesystemCredentials() const {
27 Thread* task = Processor::information().getCurrentThread();
28 PosixTaskCredentials authority;
29 if (task && task->getParent() == this) {
30 authority = posix_task_credentials(*task);
31 }
32 LockGuard<Spinlock> guard(m_CredentialLock);
34 out.uid = m_Credentials.ruid;
35 out.gid = m_Credentials.rgid;
36 out.groupCount = m_Credentials.groupCount;
37 for (size_t i = 0; i < out.groupCount; ++i)
38 out.groups[i] = m_Credentials.groups[i];
39 out.valid = true;
40 out.enforceCapabilities = true;
41 if (!out.uid && !authority.userNamespace) {
42 out.capabilities = authority.permitted;
43 }
44 return out;
45}
46
47bool PosixProcess::snapshotFilesystemCredentials(const Thread* task,
48 FilesystemCredentials& out) const {
49 PosixTaskCredentials authority;
50 if (task && task->getParent() == this) {
51 authority = posix_task_credentials(*const_cast<Thread*>(task));
52 }
53 LockGuard<Spinlock> guard(m_CredentialLock);
55 if (task && task->getParent() != this)
56 return false;
57 out.uid = m_Credentials.euid;
58 out.gid = m_Credentials.egid;
59 if (task)
60 loadFilesystemIds(*task, out.uid, out.gid);
61 out.groupCount = m_Credentials.groupCount;
62 for (size_t i = 0; i < out.groupCount; ++i)
63 out.groups[i] = m_Credentials.groups[i];
64 out.valid = true;
65 out.enforceCapabilities = true;
66 if (!authority.userNamespace) {
67 out.capabilities = authority.effective;
68 }
69 return true;
70}
71
72PosixProcess::CredentialStatus PosixProcess::changeCredentials(Thread& task,
73 CredentialChange change,
74 uint32_t first, uint32_t second,
75 uint32_t third) {
77 const TraceTaskRef token = credentialTaskToken(task);
78 const bool group = change == CredentialChange::SetGid || change == CredentialChange::SetReGid ||
79 change == CredentialChange::SetResGid;
80 const bool privileged =
81 posix_capable(group ? PosixCapabilities::Setgid : PosixCapabilities::Setuid);
82 auto space = posix_user_namespace(task);
83 uint32_t root = 0;
84 if (space && !space->toGlobal(false, 0, root)) {
85 root = UINT32_MAX;
86 }
87 LockGuard<Spinlock> guard(m_CredentialLock);
88 if (task.getParent() != this)
89 return CredentialStatus::Invalid;
90 uint32_t fsuid = m_Credentials.euid, fsgid = m_Credentials.egid;
91 loadFilesystemIds(task, fsuid, fsgid);
92 CredentialSnapshot next;
93 uint32_t nextFs;
94 const auto status = PosixCredentials::prepare(m_Credentials, change, first, second, third,
95 group ? fsgid : fsuid, next, nextFs, privileged);
96 if (status != CredentialStatus::Success)
97 return status;
98 if (!group &&
99 !posix_capabilities_uid_change(task, m_Credentials.ruid, m_Credentials.euid,
100 m_Credentials.suid, next.ruid, next.euid, next.suid, root)) {
101 return CredentialStatus::NoMemory;
102 }
103 if (token && (m_Credentials.euid != next.euid || m_Credentials.egid != next.egid ||
104 (group ? fsgid : fsuid) != nextFs)) {
105 token->clearParentDeathSignal();
106 }
107 m_Credentials = next;
108 publishCredentialReadCache();
109 publishFilesystemIds(task, group ? fsuid : nextFs, group ? nextFs : fsgid);
110 return status;
111}
112
113PosixProcess::CredentialStatus PosixProcess::replaceGroups(Thread& task, const uint32_t* groups,
114 size_t count) {
115 if (count > FilesystemCredentials::MaximumGroups || (count && !groups))
116 return CredentialStatus::Invalid;
117 uint32_t ordered[FilesystemCredentials::MaximumGroups] = {};
118 for (size_t i = 0; i < count; ++i) {
119 if (groups[i] == UINT32_MAX)
120 return CredentialStatus::Invalid;
121 size_t position = i;
122 while (position && ordered[position - 1] > groups[i]) {
123 ordered[position] = ordered[position - 1];
124 --position;
125 }
126 ordered[position] = groups[i];
127 }
129 const bool privileged = posix_capable(PosixCapabilities::Setgid);
130 LockGuard<Spinlock> guard(m_CredentialLock);
131 if (task.getParent() != this)
132 return CredentialStatus::Invalid;
133 if (!privileged)
134 return CredentialStatus::Denied;
135 bool changed = count != m_Credentials.groupCount;
136 for (size_t i = 0; i < count; ++i) {
137 changed |= m_Credentials.groups[i] != ordered[i];
138 m_Credentials.groups[i] = ordered[i];
139 }
140 m_Credentials.groupCount = count;
141 if (changed)
142 ++m_Credentials.generation;
143 return CredentialStatus::Success;
144}
145
146uint32_t PosixProcess::changeFilesystemId(Thread& task, bool group, uint32_t requested) {
148 const TraceTaskRef token = credentialTaskToken(task);
149 const bool privileged =
150 posix_capable(group ? PosixCapabilities::Setgid : PosixCapabilities::Setuid);
151 auto space = posix_user_namespace(task);
152 uint32_t root = 0;
153 if (space && !space->toGlobal(false, 0, root))
154 root = UINT32_MAX;
155 LockGuard<Spinlock> guard(m_CredentialLock);
156 uint32_t uid = m_Credentials.euid, gid = m_Credentials.egid;
157 if (task.getParent() != this)
158 return group ? gid : uid;
159 loadFilesystemIds(task, uid, gid);
160 const uint32_t old = group ? gid : uid;
161 const uint32_t real = group ? m_Credentials.rgid : m_Credentials.ruid;
162 const uint32_t effective = group ? m_Credentials.egid : m_Credentials.euid;
163 const uint32_t saved = group ? m_Credentials.sgid : m_Credentials.suid;
164 if (requested != UINT32_MAX && requested != old &&
165 (privileged || requested == real || requested == effective || requested == saved)) {
166 if (!group && !posix_capabilities_fsuid_change(task, old, requested, root))
167 return old;
168 publishFilesystemIds(task, group ? uid : requested, group ? requested : gid);
169 if (token) {
170 token->clearParentDeathSignal();
171 }
172 m_Credentials.dumpable = false;
173 ++m_Credentials.generation;
174 }
175 return old;
176}
177
178void PosixProcess::setDumpable(bool dumpable) {
180 LockGuard<Spinlock> guard(m_CredentialLock);
181 if (m_Credentials.dumpable != dumpable) {
182 m_Credentials.dumpable = dumpable;
183 ++m_Credentials.generation;
184 }
185}
186
187void PosixProcess::commitExecCredentials(Thread& task, bool readable) {
189 const TraceTaskRef token = credentialTaskToken(task);
190 LockGuard<Spinlock> guard(m_CredentialLock);
191 uint32_t fsuid = m_Credentials.euid, fsgid = m_Credentials.egid;
192 loadFilesystemIds(task, fsuid, fsgid);
193 if (token && (fsuid != m_Credentials.euid || fsgid != m_Credentials.egid)) {
194 token->clearParentDeathSignal();
195 }
196 m_Credentials.suid = m_Credentials.euid;
197 m_Credentials.sgid = m_Credentials.egid;
198 publishFilesystemIds(task, m_Credentials.euid, m_Credentials.egid);
199 m_Credentials.dumpable = readable && m_Credentials.ruid == m_Credentials.euid &&
200 m_Credentials.rgid == m_Credentials.egid;
201 ++m_Credentials.generation;
202}
203
204bool PosixProcess::installUserIdentity(User* user, Group* group, const uint32_t* groups,
205 size_t count) {
206 if (!user || !group || user->getId() >= UINT32_MAX || group->getId() >= UINT32_MAX ||
207 count > FilesystemCredentials::MaximumGroups || (count && !groups))
208 return false;
209 for (size_t i = 0; i < count; ++i)
210 if (groups[i] == UINT32_MAX)
211 return false;
213 Thread* current = Processor::information().getCurrentThread();
214 LockGuard<Spinlock> guard(m_CredentialLock);
215 CredentialSnapshot next;
216 next.ruid = next.euid = next.suid = user->getId();
217 next.rgid = next.egid = next.sgid = group->getId();
218 next.groupCount = count;
219 for (size_t i = 0; i < count; ++i)
220 next.groups[i] = groups[i];
221 next.generation = m_Credentials.generation + 1;
222 next.dumpable = false;
223 if (current && current->getParent() == this &&
224 !posix_capabilities_uid_change(*current, m_Credentials.ruid, m_Credentials.euid,
225 m_Credentials.suid, next.ruid, next.euid, next.suid, 0)) {
226 return false;
227 }
228 m_Credentials = next;
229 publishCredentialReadCache();
230 publishAccountIdentity(user, group);
231 if (current && current->getParent() == this)
232 publishFilesystemIds(*current, next.euid, next.egid);
233 return true;
234}
235
236int64_t PosixProcess::getGroupId() const {
237 return snapshotCredentials().rgid;
238}
239int64_t PosixProcess::getEffectiveUserId() const {
240 return snapshotCredentials().euid;
241}
242int64_t PosixProcess::getEffectiveGroupId() const {
243 return snapshotCredentials().egid;
244}
245int64_t PosixProcess::getSavedUserId() const {
246 return snapshotCredentials().suid;
247}
248int64_t PosixProcess::getSavedGroupId() const {
249 return snapshotCredentials().sgid;
250}
251void PosixProcess::getSupplementalGroupIds(Vector<int64_t>& groups) const {
252 const auto snapshot = snapshotCredentials();
253 for (size_t i = 0; i < snapshot.groupCount; ++i)
254 groups.pushBack(snapshot.groups[i]);
255}
256
257// These legacy kernel setters remain for trusted setup and existing fixtures.
258// User syscalls must use the validated tuple transition above.
259void PosixProcess::setTrustedIdentity(uint32_t CredentialSnapshot::* field, int64_t id) {
260 if (id < 0 || static_cast<uint64_t>(id) >= UINT32_MAX)
261 return;
263 LockGuard<Spinlock> guard(m_CredentialLock);
264 m_Credentials.*field = static_cast<uint32_t>(id);
265 publishCredentialReadCache();
266 m_Credentials.dumpable = false;
267 ++m_Credentials.generation;
268 Thread* task = Processor::information().getCurrentThread();
269 if (task && task->getParent() == this)
270 publishFilesystemIds(*task, m_Credentials.euid, m_Credentials.egid);
271}
272void PosixProcess::setUserId(int64_t id) {
273 setTrustedIdentity(&CredentialSnapshot::ruid, id);
274}
275void PosixProcess::setGroupId(int64_t id) {
276 setTrustedIdentity(&CredentialSnapshot::rgid, id);
277}
278void PosixProcess::setEffectiveUserId(int64_t id) {
279 setTrustedIdentity(&CredentialSnapshot::euid, id);
280}
281void PosixProcess::setEffectiveGroupId(int64_t id) {
282 setTrustedIdentity(&CredentialSnapshot::egid, id);
283}
284void PosixProcess::setSavedUserId(int64_t id) {
285 setTrustedIdentity(&CredentialSnapshot::suid, id);
286}
287void PosixProcess::setSavedGroupId(int64_t id) {
288 setTrustedIdentity(&CredentialSnapshot::sgid, id);
289}
290
291void PosixProcess::setSupplementalGroupIds(const Vector<int64_t>& groups) {
292 if (groups.count() > FilesystemCredentials::MaximumGroups)
293 return;
294 for (int64_t id : groups)
295 if (id < 0 || static_cast<uint64_t>(id) >= UINT32_MAX)
296 return;
298 LockGuard<Spinlock> guard(m_CredentialLock);
299 m_Credentials.groupCount = groups.count();
300 for (size_t i = 0; i < groups.count(); ++i)
301 m_Credentials.groups[i] = groups[i];
302 ++m_Credentials.generation;
303}
Memory-mapped file interface.
Definition Group.h:32
size_t getId() const
Definition Group.h:50
static MemoryMapManager & instance()
static ProcessorInformation & information()
Process * getParent() const
Definition Thread.h:340
Definition User.h:32
size_t getId() const
Definition User.h:60
A vector / dynamic array.
Definition Vector.h:33
void pushBack(const T &value)
Definition Vector.h:275
size_t count() const
Definition Vector.h:270