The Pedigree Project 0.1
resource-syscalls.cc
1/*
2 * Copyright (c) 2026, Pedigree Developers
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted.
6 */
7
8#include "pedigree/kernel/process/Scheduler.h"
9#include "pedigree/kernel/process/Thread.h"
10#include "pedigree/kernel/processor/Processor.h"
11#include "pedigree/kernel/syscallError.h"
12
13#include "PosixProcess.h"
14#include "PosixSubsystem.h"
15#include "linux-resource-abi.h"
17#include "system-syscalls.h"
18#include "user-namespace.h"
19#include <sys/resource.h>
20
21namespace {
22bool getRlimitValue(int resource, struct rlimit& result) {
23 result = {};
24 switch (resource) {
25 case RLIMIT_CPU:
26 result.rlim_cur = result.rlim_max = RLIM_INFINITY;
27 break;
28 case RLIMIT_FSIZE:
29 result.rlim_cur = result.rlim_max = RLIM_INFINITY;
30 break;
31 case RLIMIT_DATA:
32 result.rlim_cur = result.rlim_max = RLIM_INFINITY;
33 break;
34 case RLIMIT_STACK:
35 result.rlim_cur = result.rlim_max = RLIM_INFINITY;
36 break;
37 case RLIMIT_CORE:
38 result.rlim_cur = 0;
39 result.rlim_max = RLIM_INFINITY;
40 break;
41 case RLIMIT_RSS:
42 result.rlim_cur = result.rlim_max = 1ULL << 48ULL;
43 break;
44 case RLIMIT_NPROC:
45 result.rlim_cur = result.rlim_max = RLIM_INFINITY;
46 break;
47 case RLIMIT_NOFILE:
48 result.rlim_cur = result.rlim_max = 16384;
49 break;
50 case RLIMIT_MEMLOCK: {
51 GRAB_POSIX_SUBSYSTEM(false);
53 const auto limit = pSubsystem->memoryLockAccount().limit();
54 result.rlim_cur = limit.current;
55 result.rlim_max = limit.maximum;
56 break;
57 }
58 case RLIMIT_AS:
59 result.rlim_cur = result.rlim_max = 1ULL << 48ULL;
60 break;
61 case RLIMIT_LOCKS:
62 result.rlim_cur = result.rlim_max = 1024;
63 break;
64 case RLIMIT_SIGPENDING:
65 result.rlim_cur = result.rlim_max = 16;
66 break;
67 case RLIMIT_MSGQUEUE:
68 result.rlim_cur = result.rlim_max = 0x100000;
69 break;
70 case RLIMIT_NICE:
71 result.rlim_cur = result.rlim_max = 1;
72 break;
73 case RLIMIT_RTPRIO:
74 result.rlim_cur = result.rlim_max = 0;
75 break;
76#ifdef RLIMIT_RTTIME
77 case RLIMIT_RTTIME:
78 result.rlim_cur = result.rlim_max = RLIM_INFINITY;
79 break;
80#endif
81 default:
82 SYSCALL_ERROR(InvalidArgument);
83 return false;
84 }
85
86 return true;
87}
88
89int changeMemoryLimit(const LinuxRlimit64& limit, LinuxRlimit64* previous) {
90 GRAB_POSIX_SUBSYSTEM(-1);
91 auto* thread = Processor::information().getCurrentThread();
93 auto& account = pSubsystem->memoryLockAccount();
94 const auto old = account.limit();
95 const auto status = account.setLimit(limit, posix_global_capable(PosixCapabilities::SysResource));
96 if (status == PosixMemoryLockAccount::LimitStatus::Invalid) {
97 SYSCALL_ERROR(InvalidArgument);
98 return -1;
99 }
100 if (status == PosixMemoryLockAccount::LimitStatus::PermissionDenied) {
101 SYSCALL_ERROR(NotEnoughPermissions);
102 return -1;
103 }
104 if (previous)
105 *previous = old;
106 return 0;
107}
108} // namespace
109
110int posix_getrlimit(int resource, struct rlimit* rlim) {
111 SC_NOTICE("getrlimit(" << Dec << resource << ")");
112
113 struct rlimit result = {};
114 if (!getRlimitValue(resource, result)) {
115 SC_NOTICE(" -> unsupported resource");
116 return -1;
117 }
118
119 if (!PosixSubsystem::copyToUser(rlim, &result, sizeof(result))) {
120 SYSCALL_ERROR(BadAddress);
121 return -1;
122 }
123
124 SC_NOTICE(" -> cur = " << result.rlim_cur);
125 SC_NOTICE(" -> max = " << result.rlim_max);
126 return 0;
127}
128
129int posix_setrlimit(int resource, const struct rlimit* rlim) {
130 SC_NOTICE("setrlimit(" << Dec << resource << ")");
131
132 if (resource == RLIMIT_MEMLOCK) {
133 struct rlimit limit;
134 if (!PosixSubsystem::copyFromUser(&limit, rlim, sizeof(limit))) {
135 SYSCALL_ERROR(BadAddress);
136 return -1;
137 }
138 return changeMemoryLimit(
139 {static_cast<uint64_t>(limit.rlim_cur), static_cast<uint64_t>(limit.rlim_max)}, nullptr);
140 }
141
142 struct rlimit current = {};
143 if (!getRlimitValue(resource, current)) {
144 return -1;
145 }
146
147 (void)rlim;
148 SYSCALL_ERROR(Unimplemented);
149 return -1;
150}
151
152int posix_prlimit64(int pid, int resource, const LinuxRlimit64* newLimit, LinuxRlimit64* oldLimit) {
153 SC_NOTICE("prlimit64(" << Dec << pid << ", " << resource << ")");
154
155 Process* current = Processor::information().getCurrentThread()->getParent();
156 Scheduler::ProcessLease targetLease;
157 if (pid < 0) {
158 SYSCALL_ERROR(NoSuchProcess);
159 return -1;
160 }
161 if (pid && static_cast<size_t>(pid) != current->getUserspaceId()) {
162 if (!Scheduler::instance().acquireProcessByUserspaceId(targetLease, static_cast<size_t>(pid)) ||
163 targetLease->getType() != Process::Posix) {
164 SYSCALL_ERROR(NoSuchProcess);
165 return -1;
166 }
167 // Cross-process access needs a coherent credential snapshot shared with
168 // credential mutation. Until then, only the caller's limits are exposed.
169 SYSCALL_ERROR(Unimplemented);
170 return -1;
171 }
172
173 struct rlimit currentLimit = {};
174 if (!getRlimitValue(resource, currentLimit)) {
175 return -1;
176 }
177
178 LinuxRlimit64 previous = {static_cast<uint64_t>(currentLimit.rlim_cur),
179 static_cast<uint64_t>(currentLimit.rlim_max)};
180 if (newLimit) {
181 if (resource != RLIMIT_MEMLOCK) {
182 SYSCALL_ERROR(Unimplemented);
183 return -1;
184 }
185 LinuxRlimit64 limit;
186 if (!PosixSubsystem::copyFromUser(&limit, newLimit, sizeof(limit))) {
187 SYSCALL_ERROR(BadAddress);
188 return -1;
189 }
190 if (changeMemoryLimit(limit, &previous))
191 return -1;
192 }
193
194 if (oldLimit) {
195 // Linux commits the new limit before copying the old one to userspace.
196 if (!PosixSubsystem::copyToUser(oldLimit, &previous, sizeof(previous))) {
197 SYSCALL_ERROR(BadAddress);
198 return -1;
199 }
200 }
201
202 return 0;
203}
Memory-mapped file interface.
static MemoryMapManager & instance()
static bool copyFromUser(void *destination, const void *source, size_t count, size_t elementSize=1)
static bool copyToUser(void *destination, const void *source, size_t count, size_t elementSize=1)
size_t getUserspaceId() const
Definition Process.h:504
Process * getParent()
Definition Process.h:620
static ProcessorInformation & information()
static Scheduler & instance()
Definition Scheduler.h:96
@ Dec
Definition Log.h:126