kernel
Loading...
Searching...
No Matches
systemcalls.c
Go to the documentation of this file.
1/*++
2
3Module Name:
4
5 syscall.c
6
7Purpose:
8
9 This module contains the list of system calls and their implementation of MatanelOS.
10
11Author:
12
13 slep (Matanel) 2025.
14
15Revision History:
16
17--*/
18
19#include "../../includes/mt.h"
20#include "../../includes/ob.h"
21#include "../../includes/mm.h"
22#include "../../includes/ps.h"
23#include "../../includes/mg.h"
25#include "../../includes/fs.h"
26#include "../../assert.h"
27
30 IN HANDLE ProcessHandle,
31 _In_Opt _Out_Opt void** BaseAddress,
32 IN size_t NumberOfBytes,
33 IN uint8_t AllocationType
34)
35
36
37/*++
38
39 Routine description:
40
41 System call for user virtual memory allocation (VAD)
42
43 Arguments:
44
45 [IN] HANDLE ProcessHandle - Handle to process that memory should be allocated for. (special handles supported, e.g MtCurrentProcess)
46 [IN OPTIONAL | OUT OPTIONAL] [PTR_TO_PTR] void** BaseAddress - The base address to allocate memory starting from if supplied. If NULL, a free gap is chosen and used by NumberOfBytes, and *BaseAddress is set to the found start of gap.
47 [IN] size_t NumberOfBytes - The amount in virtual memory to allocate.
48 [IN] uint8_t AllocationType - USER_ALLOCATION_TYPE Enum specifying which type of PTE flags the allocation should have. (executable, writable, none)
49
50 Return Values:
51
52 Various MTSTATUS Status codes.
53
54--*/
55
56{
57 // We must allocate more than 0 bytes. (it will be page size anyway, so..)
58 if (!NumberOfBytes) return MT_INVALID_PARAM;
59
60 // Handle checking.
61 PEPROCESS Process;
62 MTSTATUS Status;
63 if (ProcessHandle == MtCurrentProcess()) {
64 // Current process allocation.
65 Process = PsGetCurrentProcess();
66 // Reference it so it doesnt die. (and so the ObDereferenceObject at the end of the function doesnt decrement a reference by others)
67 if (!ObReferenceObject(Process)) {
68 // This shouldnt really be possible, as if someone called to terminate the process
69 // then this thread would have been dead. (or maybe not because we are in a syscall?)
71 }
72 }
73 else {
74 // Another process reference.
76 ProcessHandle,
79 (void**)&Process,
80 NULL
81 );
82 if (MT_FAILURE(Status)) return Status;
83 }
84
85 // Sanitize AllocationType to VAD_FLAGS.
87 switch (AllocationType) {
90 break;
91
94 break;
95
96 case PAGE_READWRITE:
98 break;
99
100 case PAGE_NOACCESS:
102 break;
103
104 default:
106 break;
107 }
108
109 if (Flags != VAD_FLAG_NONE) {
110 Status = MmAllocateVirtualMemory(Process, BaseAddress, NumberOfBytes, Flags);
111 }
112 else {
113 Status = MT_INVALID_PARAM;
114 }
115
116 // Dereference the reference made.
117 ObDereferenceObject(Process);
118 return Status;
119}
120
123 IN uint32_t ProcessId,
124 OUT PHANDLE ProcessHandle,
125 IN ACCESS_MASK DesiredAccess
126)
127
128/*++
129
130 Routine description:
131
132 System call for user process handle open.
133
134 Arguments:
135
136 [IN] uint32_t ProcessId - The PID of the process to open.
137 [OUT] PHANDLE ProcessHandle - Pointer to store handle of opened process.
138 [IN] ACCESS_MASK DesiredAccess - The desired access to have for the process.
139
140 Return Values:
141
142 Various MTSTATUS Status codes.
143
144--*/
145
146{
147 // TODO SIDS, check if the user process is allowed to open another process handle.
148 // TODO PPL, check if the user proecss is allowed to a process handle to ProcessId, check if its protection level is higher or equal.
149 // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-process_protection_level_information
150 // For now, we just disregard a process with PID 4 since its the system process.
151 MTSTATUS Status;
152 if (ProcessId == 4) return MT_ACCESS_DENIED;
153
154 if (MeGetPreviousMode() == UserMode) {
155 Status = ProbeForRead(ProcessHandle, sizeof(HANDLE), _Alignof(HANDLE));
156 if (MT_FAILURE(Status)) return Status;
157 }
158
159 // Retrieve the process.
160 PEPROCESS Process = PsLookupProcessByProcessId(ProcessId);
161 if (!Process) return MT_NOT_FOUND;
162
163 HANDLE OutHandleBefore;
164 Status = ObOpenObjectByPointer((void*)Process, PsProcessType, DesiredAccess, &OutHandleBefore);
165 if (MT_FAILURE(Status)) return Status;
166
167 // Attempt to write to user memory
168 try {
169 *ProcessHandle = OutHandleBefore;
170 } except{
171 // User gave invalid pointer, we return failure
172 HtClose(OutHandleBefore);
173 return GetExceptionCode();
174 }
175 end_try;
176
177 return MT_SUCCESS;
178}
179
182 IN HANDLE ProcessHandle,
183 IN MTSTATUS ExitStatus
184)
185
186/*++
187
188 Routine description:
189
190 System call for user process termination.
191
192 Arguments:
193
194 [IN] HANDLE ProcessHandle - The process that is to be terminated (special handles allowed)
195 [IN] MTSTATUS ExitStatus - The status the process will exit in (and its threads)
196
197 Return Values:
198
199 Various MTSTATUS Status codes.
200 Or none if current process.
201
202--*/
203
204{
205 PEPROCESS ProcessToTerminate;
206 MTSTATUS Status;
207 if (ProcessHandle == MtCurrentProcess()) {
208 ProcessToTerminate = PsGetCurrentProcess();
209 gop_printf(COLOR_RED, "[PROCESS-TERMINATE] Process %p called upon to terminate itself from this existence of the virtual world. | Status: %p\n", (void*)(uintptr_t)ProcessToTerminate, (void*)(uintptr_t)ExitStatus);
210 }
211 else {
212 // Attempt reference of handle.
214 ProcessHandle,
217 (void**)&ProcessToTerminate,
218 NULL
219 );
220 if (MT_FAILURE(Status)) return Status;
221 gop_printf(COLOR_RED, "[PROCESS-TERMINATE] Process %p called to be terminated. | Status: %p\n", (void*)(uintptr_t)ProcessToTerminate, (void*)(uintptr_t)ExitStatus);
222 }
223
224 // Kill the process.
225 Status = PsTerminateProcess(ProcessToTerminate, ExitStatus);
226
227 // Return status, if it wasnt ourselves who were killed.
228 return Status;
229}
230
233 IN HANDLE FileHandle,
234 IN uint64_t FileOffset,
235 OUT void* Buffer,
236 IN size_t BufferSize,
237 _Out_Opt size_t* BytesRead
238)
239
240/*++
241
242 Routine description:
243
244 System call for file reading.
245
246 Arguments:
247
248 [IN] HANDLE FileHandle - The handle of the file opened from MtCreateFile.
249 [IN] uint64_t FileOffset - File offset in bytes to start reading from.
250 [OUT] void* Buffer - The buffer to store read bytes in.
251 [IN] size_t BufferSize - The size of the buffer in bytes.
252 [OUT OPTIONAL] size_t* BytesRead - Optionally supply a pointer to store how many bytes were read to the buffer given.
253
254 Return Values:
255
256 Various MTSTATUS Status codes.
257
258--*/
259
260{
261 // We must be at IRQL that is less or equal than APC_LEVEL (so we can bring in pageable memory, both for user memory and kernel memory)
263 // Attempt reference of handle.
264 MTSTATUS Status;
265 PFILE_OBJECT FileObject;
266 PRIVILEGE_MODE PreviousMode = MeGetPreviousMode();
268 FileHandle,
271 (void**)&FileObject,
272 NULL
273 );
274 if (MT_FAILURE(Status)) return Status;
275
276 // Before everything, lets probe the buffer given. (if we came from user mode that is)
277 if (PreviousMode == UserMode) {
278 Status = ProbeForRead(Buffer, BufferSize, _Alignof(char));
279 if (MT_FAILURE(Status)) {
280 // Invalid buffer.
281 ObDereferenceObject(FileObject);
282 return Status;
283 }
284 }
285
286 if (BytesRead && PreviousMode == UserMode) {
287 Status = ProbeForRead(BytesRead, sizeof(size_t), _Alignof(size_t));
288 if (MT_FAILURE(Status)) {
289 // Invalid buffer
290 ObDereferenceObject(FileObject);
291 return Status;
292 }
293 }
294
295 // Create a paged pool large enough for the buffer size given.
296 void* KernelBuffer = MmAllocatePoolWithTag(PagedPool, BufferSize, 'fubk'); // kbuf
297 if (!KernelBuffer) {
298 ObDereferenceObject(FileObject);
299 return MT_NO_MEMORY;
300 }
301
302 size_t KernelBytesRead = 0;
303
304 // Call the FS layer.
305 Status = FsReadFile(
306 FileObject,
307 FileOffset,
308 KernelBuffer,
309 BufferSize,
310 &KernelBytesRead
311 );
312
313 // If we got EOF we dont return a full failure, and we still copy the data.
314 // Else, we got a failure and we free and return.
315 if (MT_FAILURE(Status) && KernelBytesRead == 0) {
316 MmFreePool(KernelBuffer);
317 ObDereferenceObject(FileObject);
318 return Status;
319 }
320
321 // Write back to user buffer based on bytes read.
322 try {
323 kmemcpy(Buffer, KernelBuffer, KernelBytesRead);
324 } except{
325 // Exception gotten on copying to user buffer, we abort and return failure.
326 MmFreePool(KernelBuffer);
327 ObDereferenceObject(FileObject);
328 return GetExceptionCode();
329 } end_try;
330
331 // Free the kernel buffer now.
332 MmFreePool(KernelBuffer);
333
334 if (BytesRead) {
335 // Write back how many bytes we read.
336 try {
337 *BytesRead = KernelBytesRead;
338 } except{
339 // Exception gotten on copying to user bytes read, BUT we successfully written everything to the buffer
340 // We return last exception code still, their problem.
341 ObDereferenceObject(FileObject);
342 return GetExceptionCode();
343 } end_try;
344 }
345
346 // Everything's good, dereference object, return to caller.
347 ObDereferenceObject(FileObject);
348 return MT_SUCCESS;
349}
350
353 IN HANDLE FileHandle,
354 IN uint64_t FileOffset,
355 IN void* Buffer,
356 IN size_t BufferSize,
357 _Out_Opt size_t* BytesWritten
358)
359
360{
361 // We must be at IRQL that is less or equal than APC_LEVEL (so we can bring in pageable memory, both for user memory and kernel memory)
363 // Attempt reference of handle.
364 MTSTATUS Status;
365 PFILE_OBJECT FileObject;
366 PRIVILEGE_MODE PreviousMode = MeGetPreviousMode();
368 FileHandle,
371 (void**)&FileObject,
372 NULL
373 );
374 if (MT_FAILURE(Status)) return Status;
375
376 // Before everything, lets probe the buffer given. (if we came from user mode that is)
377 if (PreviousMode == UserMode) {
378 Status = ProbeForRead(Buffer, BufferSize, _Alignof(char));
379 if (MT_FAILURE(Status)) {
380 // Invalid buffer.
381 ObDereferenceObject(FileObject);
382 return Status;
383 }
384 }
385
386 if (BytesWritten && PreviousMode == UserMode) {
387 Status = ProbeForRead(BytesWritten, sizeof(size_t), _Alignof(size_t));
388 if (MT_FAILURE(Status)) {
389 // Invalid buffer
390 ObDereferenceObject(FileObject);
391 return Status;
392 }
393 }
394
395 // Create a paged pool large enough for the buffer size given.
396 void* KernelBuffer = MmAllocatePoolWithTag(PagedPool, BufferSize, 'fubk'); // kbuf
397 if (!KernelBuffer) {
398 ObDereferenceObject(FileObject);
399 return MT_NO_MEMORY;
400 }
401
402 // Begin copying from user buffer to kernel buffer.
403 try {
404 kmemcpy(KernelBuffer, Buffer, BufferSize);
405 } except{
406 // Access violation while copying from user buffer.
407 // We return last exception code still, their problem.
408 ObDereferenceObject(FileObject);
409 MmFreePool(KernelBuffer);
410 return GetExceptionCode();
411 } end_try;
412
413 size_t KernelBytesWritten = 0;
414
415 // Call the FS layer.
416 Status = FsWriteFile(
417 FileObject,
418 FileOffset,
419 KernelBuffer,
420 BufferSize,
421 &KernelBytesWritten
422 );
423
424 // If we got EOF we dont return a full failure, and we still copy the data.
425 // Else, we got a failure and we free and return.
426 if (MT_FAILURE(Status) && KernelBytesWritten == 0) {
427 MmFreePool(KernelBuffer);
428 ObDereferenceObject(FileObject);
429 return Status;
430 }
431
432 // Free the kernel buffer now.
433 MmFreePool(KernelBuffer);
434
435 if (BytesWritten) {
436 // Write back how many bytes we read.
437 try {
438 *BytesWritten = KernelBytesWritten;
439 } except{
440 // Exception gotten on copying to user bytes read, BUT we successfully written everything to the buffer
441 // We return last exception code still, their problem.
442 ObDereferenceObject(FileObject);
443 return GetExceptionCode();
444 } end_try;
445 }
446
447 // Everything's good, dereference object, return to caller.
448 ObDereferenceObject(FileObject);
449 return MT_SUCCESS;
450}
451
454 IN const char* path,
455 IN ACCESS_MASK DesiredAccess,
456 OUT PHANDLE FileHandleOut
457)
458
459{
460 // We must be at IRQL that is less or equal than APC_LEVEL (FileSystem requirements)
462 MTSTATUS Status;
463 HANDLE KernelHandle;
464 PRIVILEGE_MODE PreviousMode = MeGetPreviousMode();
465 char KernelPath[MAX_PATH];
466
467 // Check if address given is good for writing.
468 if (PreviousMode == UserMode) {
469 Status = ProbeForRead(FileHandleOut, sizeof(HANDLE), _Alignof(HANDLE));
470 if (MT_FAILURE(Status)) return Status;
471
472 // This is a pointer without knowledge of how large it is, but we do know whats the maximum path length, so we scan by that.
473 Status = ProbeForRead(path, MAX_PATH, _Alignof(char));
474 if (MT_FAILURE(Status)) return Status;
475 }
476
477 // Copy user ptr to kernel.
478 try {
479 // Ensures null termination.
480 kstrncpy(KernelPath, path, MAX_PATH);
481 } except{
482 // Invalid char pointer.
483 return GetExceptionCode();
484 } end_try;
485
486 // Now call filesystem layer.
487 Status = FsCreateFile(
488 KernelPath,
489 DesiredAccess,
490 &KernelHandle
491 );
492 if (MT_FAILURE(Status)) return Status;
493
494 // Good, we opened/created the file, now we attempt to return back to caller.
495 try {
496 // Write the handle to the user handle ptr.
497 *FileHandleOut = KernelHandle;
498 } except{
499 // Exception while writing to user, close handle and return.
500 HtClose(KernelHandle);
501 return GetExceptionCode();
502 } end_try;
503
504 // Successful.
505 return MT_SUCCESS;
506}
507
510 IN HANDLE hObject
511)
512
513{
514 // Easiest syscall yet, just call internal function.
515 return HtClose(hObject);
516}
517
520 IN HANDLE ThreadHandle,
521 IN MTSTATUS ExitStatus
522)
523
524{
525 // Attempt to reference thread, or if it is ourselves use ourselves.
526 MTSTATUS Status;
527 PETHREAD Thread;
528 if (ThreadHandle == MtCurrentThread()) {
529 // Check if we are the last thread of the process.
530 if (PsGetCurrentProcess()->NumThreads == 1) {
531 // Illegal. (MtTerminateProcess(MtCurrentProcess(), status) must be called instead)
533 }
534
535 // Current Thread.
536 Thread = PsGetCurrentThread();
537
538 // Successful.
539 Status = MT_SUCCESS;
540 }
541 else {
542 // Remote Thread
544 ThreadHandle,
547 (void**)&Thread,
548 NULL
549 );
550 }
551
552 // Check if success.
553 if (MT_FAILURE(Status)) {
554 return Status;
555 }
556
557 // Call internal function.
558 return PsTerminateThread(Thread, ExitStatus);
559}
#define _In_Opt
Definition annotations.h:10
#define _Out_Opt
Definition annotations.h:11
#define IN
Definition annotations.h:8
#define OUT
Definition annotations.h:9
#define assert(...)
Definition assert.h:57
PEPROCESS PsLookupProcessByProcessId(IN HANDLE ProcessId)
Definition cid.c:114
uint32_t ACCESS_MASK
Definition core.h:59
int32_t * PHANDLE
Definition core.h:58
@ APC_LEVEL
Definition core.h:16
int32_t HANDLE
Definition core.h:58
EPROCESS * PEPROCESS
Definition core.h:52
ETHREAD * PETHREAD
Definition core.h:44
#define end_try
Definition exception.h:145
#define except
Definition exception.h:131
struct _FILE_OBJECT * PFILE_OBJECT
#define MT_FILE_READ_DATA
Definition fs.h:27
#define MAX_PATH
Definition fs.h:25
#define MT_FILE_WRITE_DATA
Definition fs.h:30
void gop_printf(uint32_t color, const char *fmt,...)
Definition gop.c:633
char * kstrncpy(char *dst, const char *src, size_t n)
Definition gop.c:365
MTSTATUS HtClose(IN HANDLE Handle)
Definition handle.c:536
FORCEINLINE IRQL MeGetCurrentIrql(void)
Definition me.h:415
FORCEINLINE PRIVILEGE_MODE MeGetPreviousMode(void)
Definition me.h:568
#define COLOR_RED
Colors definitions for easier access.
Definition mg.h:30
uint32_t Flags
Definition mh.h:44
@ PagedPool
Definition mm.h:356
@ VAD_FLAG_NONE
Definition mm.h:295
@ VAD_FLAG_READ
Definition mm.h:296
@ VAD_FLAG_RESERVED
Definition mm.h:302
@ VAD_FLAG_EXECUTE
Definition mm.h:298
@ VAD_FLAG_WRITE
Definition mm.h:297
FORCEINLINE void * kmemcpy(void *dest, const void *src, size_t len)
Definition mm.h:669
enum _PRIVILEGE_MODE PRIVILEGE_MODE
enum _VAD_FLAGS VAD_FLAGS
@ UserMode
Definition mm.h:372
@ PAGE_EXECUTE_READ
Definition mt.h:32
@ PAGE_EXECUTE_READWRITE
Definition mt.h:33
@ PAGE_READWRITE
Definition mt.h:34
@ PAGE_NOACCESS
Definition mt.h:36
#define MtCurrentThread()
Definition mt.h:29
#define MtCurrentProcess()
Definition mt.h:28
#define MT_NO_MEMORY
Definition mtstatus.h:42
#define MT_SUCCESS
Definition mtstatus.h:22
#define MT_PROCESS_IS_TERMINATING
Definition mtstatus.h:124
#define MT_CANT_TERMINATE_SELF
Definition mtstatus.h:143
#define MT_ACCESS_DENIED
Definition mtstatus.h:26
#define MT_FAILURE(Status)
Definition mtstatus.h:16
#define MT_INVALID_PARAM
Definition mtstatus.h:24
int32_t MTSTATUS
Definition mtstatus.h:12
#define MT_NOT_FOUND
Definition mtstatus.h:30
MTSTATUS ObReferenceObjectByHandle(IN HANDLE Handle, IN uint32_t DesiredAccess, IN POBJECT_TYPE DesiredType, OUT void **Object, _Out_Opt PHANDLE_TABLE_ENTRY HandleInformation)
Definition ob.c:277
void ObDereferenceObject(IN void *Object)
Definition ob.c:554
bool ObReferenceObject(IN void *Object)
Definition ob.c:163
MTSTATUS ObOpenObjectByPointer(IN void *Object, IN POBJECT_TYPE ObjectType, IN ACCESS_MASK DesiredAccess, OUT PHANDLE Handle)
Definition ob.c:252
void MmFreePool(IN void *buf)
Definition pool.c:632
void * MmAllocatePoolWithTag(IN enum _POOL_TYPE PoolType, IN size_t NumberOfBytes, IN uint32_t Tag)
Definition pool.c:443
MTSTATUS ProbeForRead(IN const void *Address, IN size_t Length, IN uint32_t Alignment)
Definition probe.c:23
MTSTATUS PsTerminateProcess(IN PEPROCESS Process, IN MTSTATUS ExitCode)
Definition process.c:435
#define MT_THREAD_TERMINATE
Definition ps.h:65
FORCEINLINE PEPROCESS PsGetCurrentProcess(void)
Definition ps.h:300
FORCEINLINE MTSTATUS GetExceptionCode(void)
Definition ps.h:346
#define MT_PROCESS_VM_OPERATION
Definition ps.h:80
#define MT_PROCESS_TERMINATE
Definition ps.h:78
POBJECT_TYPE PsThreadType
Definition psmgr.c:31
POBJECT_TYPE PsProcessType
Definition psmgr.c:30
MTSTATUS MtReadFile(IN HANDLE FileHandle, IN uint64_t FileOffset, OUT void *Buffer, IN size_t BufferSize, _Out_Opt size_t *BytesRead)
MTSTATUS MtTerminateProcess(IN HANDLE ProcessHandle, IN MTSTATUS ExitStatus)
MTSTATUS MtAllocateVirtualMemory(IN HANDLE ProcessHandle, _In_Opt _Out_Opt void **BaseAddress, IN size_t NumberOfBytes, IN uint8_t AllocationType)
Definition systemcalls.c:29
MTSTATUS MtClose(IN HANDLE hObject)
MTSTATUS MtOpenProcess(IN uint32_t ProcessId, OUT PHANDLE ProcessHandle, IN ACCESS_MASK DesiredAccess)
MTSTATUS MtTerminateThread(IN HANDLE ThreadHandle, IN MTSTATUS ExitStatus)
MTSTATUS MtWriteFile(IN HANDLE FileHandle, IN uint64_t FileOffset, IN void *Buffer, IN size_t BufferSize, _Out_Opt size_t *BytesWritten)
MTSTATUS MtCreateFile(IN const char *path, IN ACCESS_MASK DesiredAccess, OUT PHANDLE FileHandleOut)
MTSTATUS PsTerminateThread(IN PETHREAD Thread, IN MTSTATUS ExitStatus)
Definition thread.c:284
PETHREAD PsGetCurrentThread(void)
Definition thread.c:279
MTSTATUS MmAllocateVirtualMemory(IN PEPROCESS Process, _In_Opt _Out_Opt void **BaseAddress, IN size_t NumberOfBytes, IN VAD_FLAGS VadFlags)
Definition vad.c:740
POBJECT_TYPE FsFileType
Definition vfs.c:26
MTSTATUS FsReadFile(IN PFILE_OBJECT FileObject, IN uint64_t FileOffset, OUT void *Buffer, IN size_t BufferSize, _Out_Opt size_t *BytesRead)
Definition vfs.c:117
MTSTATUS FsCreateFile(IN const char *path, IN ACCESS_MASK DesiredAccess, OUT PHANDLE FileHandleOut)
Definition vfs.c:204
MTSTATUS FsWriteFile(IN PFILE_OBJECT FileObject, IN uint64_t FileOffset, IN void *Buffer, IN size_t BufferSize, _Out_Opt size_t *BytesWritten)
Definition vfs.c:132