2#include "namespace-syscalls.h"
3#include "pedigree/kernel/Version.h"
4#include "pedigree/kernel/process/Thread.h"
5#include "pedigree/kernel/process/Uninterruptible.h"
6#include "pedigree/kernel/processor/Processor.h"
7#include "pedigree/kernel/processor/ProcessorInformation.h"
8#include "pedigree/kernel/syscallError.h"
9#include "pedigree/kernel/utilities/utility.h"
11#include "PosixProcess.h"
12#include "PosixSubsystem.h"
13#include "ipc-namespace.h"
15#include "modules/system/vfs/MountView.h"
16#include "namespace-file.h"
17#include "network-namespace.h"
18#include "sandbox-state.h"
19#include "sysv-semaphore-syscalls.h"
20#include "user-namespace.h"
21#include <sys/utsname.h>
24constexpr unsigned long NewMount = 0x20000, NewUts = 0x04000000, NewIpc = 0x08000000,
25 NewUser = 0x10000000, NewPid = 0x20000000, NewNet = 0x40000000;
26constexpr unsigned long KnownUnshare = 0x80 | 0x100 | 0x200 | 0x400 | 0x800 | 0x10000 | 0x20000 |
27 0x40000 | 0x02000000 | NewUts | 0x08000000 | 0x10000000 |
28 0x20000000 | 0x40000000;
30class NamespaceResult {
32 NamespaceResult() : m_Thread(*
Processor::information().getCurrentThread()) {}
34 m_Thread.setErrno(m_Error);
36 int finish(
int value) {
37 m_Error = value < 0 ? m_Thread.getErrno() : 0;
47 if (!posix_namespace_capable(owner, PosixCapabilities::SysAdmin)) {
48 SYSCALL_ERROR(NotEnoughPermissions);
56 if (process->getType() != Process::Posix || !process->getSubsystem())
58 return static_cast<PosixSubsystem*
>(process->getSubsystem())->namespaceContext();
61int setName(
const char* name,
size_t suppliedLength,
bool domain) {
62 NamespaceResult result;
65 const int32_t length =
static_cast<int32_t
>(suppliedLength);
66 if (length < 0 || length > 64) {
67 SYSCALL_ERROR(InvalidArgument);
68 return result.finish(-1);
72 SYSCALL_ERROR(BadAddress);
73 return result.finish(-1);
75 auto selected = context();
78 return result.finish(posix_uts_error(UtsStatus::Missing));
79 if (!administrative(space->owner())) {
80 return result.finish(-1);
82 space->setName(domain, bytes,
static_cast<size_t>(length));
83 return result.finish(0);
86void copyField(
char* output,
size_t capacity,
const char* source) {
88 while (source[length] && length + 1 < capacity)
90 MemoryCopy(output, source, length);
94int posix_sethostname(
const char* name,
size_t length) {
95 return setName(name, length,
false);
97int posix_setdomainname(
const char* name,
size_t length) {
98 return setName(name, length,
true);
101int posix_unshare(
unsigned long flags) {
102 NamespaceResult result;
104 if (flags & ~KnownUnshare) {
105 SYSCALL_ERROR(InvalidArgument);
106 return result.finish(-1);
108 if (flags & ~(NewMount | NewUts | NewUser | NewPid | NewIpc | NewNet)) {
109 SYSCALL_ERROR(OperationNotSupported);
110 return result.finish(-1);
113 return result.finish(0);
117 if ((flags & (NewMount | NewUser | NewPid)) && process->
getNumThreads() != 1) {
118 SYSCALL_ERROR(InvalidArgument);
119 return result.finish(-1);
121 if (flags & NewPid) {
122 if (flags != NewPid) {
123 SYSCALL_ERROR(OperationNotSupported);
124 return result.finish(-1);
126 if (!posix_capable(PosixCapabilities::SysAdmin)) {
127 SYSCALL_ERROR(NotEnoughPermissions);
128 return result.finish(-1);
130 if (!process->pidNamespaceReady()) {
131 SYSCALL_ERROR(OutOfMemory);
132 return result.finish(-1);
134 const auto active = process->pidNamespace();
135 if (process->pidNamespaceForChildren().
get() != active.get()) {
136 SYSCALL_ERROR(InvalidArgument);
137 return result.finish(-1);
139 if (active->depth() >= 32) {
140 SYSCALL_ERROR(NoSpaceLeftOnDevice);
141 return result.finish(-1);
145 SYSCALL_ERROR(OutOfMemory);
146 return result.finish(-1);
148 if (!process->unsharePidNamespace(prepared)) {
149 SYSCALL_ERROR(InvalidArgument);
150 return result.finish(-1);
152 return result.finish(0);
155 if ((flags & NewUser) && !posix_user_namespace_prepare(thread, credentials)) {
156 return result.finish(-1);
158 if (!(flags & NewUser) && !posix_capable(PosixCapabilities::SysAdmin)) {
159 SYSCALL_ERROR(NotEnoughPermissions);
160 return result.finish(-1);
162 const auto owner = credentials ? credentials->userNamespace : posix_user_namespace(thread);
164 auto previousFilesystem = process->acquireFilesystemContext();
165 if (flags & NewMount) {
166 auto* view = VfsMountView::fromContext(previousFilesystem);
168 !view->forkNamespace(previousFilesystem, filesystem, owner ? owner->identity() : 0)) {
169 return result.finish(-1);
172 auto selected = context();
173 UtsRef source, replacement;
174 if (flags & NewUts) {
175 if (!selected || !selected->acquireThread(thread, source)) {
176 return result.finish(posix_uts_error(UtsStatus::Missing));
178 const auto status = posix_uts_copy(source, replacement, owner);
179 if (status != UtsStatus::Success) {
180 return result.finish(posix_uts_error(status));
184 if ((flags & NewNet) && !posix_network_namespace_prepare(owner, network)) {
185 return result.finish(-1);
188 if (flags & NewIpc) {
191 SYSCALL_ERROR(OutOfMemory);
192 return result.finish(-1);
196 const auto previousState = thread.securityState();
198 if (!posix_sandbox_prepare_namespaces(thread, credentials, ipc, network, preparedState)) {
199 return result.finish(-1);
201 thread.setSecurityState(preparedState);
202 if (replacement && selected->replaceThread(thread, replacement) != UtsStatus::Success) {
203 thread.setSecurityState(previousState);
204 return result.finish(posix_uts_error(UtsStatus::Missing));
207 !process->replaceFilesystemContext(pedigree_std::move(filesystem), previousFilesystem)) {
209 selected->replaceThread(thread, source);
211 thread.setSecurityState(previousState);
212 SYSCALL_ERROR(NoMoreProcesses);
213 return result.finish(-1);
216 posix_sem_thread_exit(&thread);
218 return result.finish(0);
221int posix_setns(
int fd,
int type) {
222 NamespaceResult result;
225 auto* subsystem =
static_cast<PosixSubsystem*
>(process->getSubsystem());
227 if (!subsystem || !subsystem->acquireFileDescriptor(fd, descriptor)) {
228 SYSCALL_ERROR(BadFileDescriptor);
229 return result.finish(-1);
232 if (!posix_uts_file_namespace(descriptor->getFile(), space) ||
233 (type &&
static_cast<unsigned int>(type) != NewUts)) {
234 SYSCALL_ERROR(InvalidArgument);
235 return result.finish(-1);
238 if (!administrative(space->owner())) {
239 return result.finish(-1);
241 auto selected = context();
243 return result.finish(posix_uts_error(UtsStatus::Missing));
244 return result.finish(posix_uts_error(
248int posix_uname(
struct utsname* user) {
249 NamespaceResult result;
251 auto selected = context();
254 if (!selected || !selected->acquireThread(thread, space))
255 return result.finish(posix_uts_error(UtsStatus::Missing));
256 const auto names = space->snapshot();
258 if (subsystem->getAbi() == PosixSubsystem::LinuxAbi) {
259 struct LinuxUtsname {
262 static_assert(
sizeof(snapshot) == 390,
"Linux utsname size");
263 copyField(snapshot.fields[0], 65,
"Pedigree");
264 MemoryCopy(snapshot.fields[1], names.node, 65);
265 copyField(snapshot.fields[2], 65,
"2.6.32-generic");
266 copyField(snapshot.fields[3], 65, g_pBuildRevision);
268 copyField(snapshot.fields[4], 65,
"aarch64");
270 copyField(snapshot.fields[4], 65,
271 thread.executionPersonality().value() == ExecutionPersonality::Linux32
275 MemoryCopy(snapshot.fields[5], names.domain, 65);
277 SYSCALL_ERROR(BadAddress);
278 return result.finish(-1);
281 struct utsname snapshot = {};
282 copyField(snapshot.sysname,
sizeof(snapshot.sysname),
"Pedigree");
283 MemoryCopy(snapshot.nodename, names.node,
284 sizeof(snapshot.nodename) < 65 ?
sizeof(snapshot.nodename) : 65);
285 copyField(snapshot.release,
sizeof(snapshot.release), g_pBuildRevision);
286 copyField(snapshot.version,
sizeof(snapshot.version),
"Foster");
287 copyField(snapshot.machine,
sizeof(snapshot.machine),
288 thread.executionPersonality().value() == ExecutionPersonality::Linux32
292 SYSCALL_ERROR(BadAddress);
293 return result.finish(-1);
296 return result.finish(0);
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)
static ProcessorInformation & information()
static SharedPointer< T > tryAllocate(Args...)
Process * getParent() const