Kernel

From Vita Development Wiki
Revision as of 21:40, 19 January 2023 by CelesteBlue (talk | contribs)
Jump to navigation Jump to search

The PS Vita has a purely modular kernel. It is divided in a Secure Kernel and a Non-secure Kernel. All modules of the kernel are Kernel PRX files. They are listed in Modules. Most Non-secure Kernel modules are stored in the os0: partition whilst Secure Kernel modules are stored in the SLB2 partition. Most Non-secure Kernel modules are encrypted and signed as .skprx files, but some are packed as plain Kernel PRX in bootimage.skprx. Secure Kernel modules are in kernel_boot_loader.self and sometimes are LZRA-encoded.

UID

Class

Version Module Name Superclass Size (bytes) Description
3.60 SceSysmem SceUIDClass None 0x8 For Group/Reserved UID.
3.60 SceUIDDLinkClass SceUIDClass 0xC For Group.
3.60 SceUIDHeapClass 0xC
3.60 SceUIDFixedHeapClass SceUIDHeapClass 0xA4
3.60 SceUIDEntryHeapClass 0xB0
3.60 SceUIDKernelHeapClass 0x80
3.60 SceUIDSysrootClass SceUIDClass 0x41C
3.60 SceUIDSimpleMemBlockClass SceUIDDLinkClass 0x40
3.60 SceUIDMemBlockClass 0x40
3.60 SceUIDTinyPartitionClass SceUIDClass 0x38
3.60 SceUIDPartitionClass SceUIDTinyPartitionClass 0x80
3.60 SceUIDAddressSpaceClass SceUIDClass 0x170
3.60 SceUIDPhyMemPartClass 0xAC
3.60 SceUIDSysEventClass 0x20
3.60 SceUIDProcEventClass 0x30
3.60-3.73 SceKernelModulemgr SceUIDModuleClass SceUIDClass 0xF4
3.60-3.73 SceUIDLibraryClass 0x10
3.60-3.73 SceUIDLibStubClass 0x10
3.60 SceKernelThreadMgr SceUIDCacheClass SceUIDClass 0x10
3.60 SceUIDWaitableClass SceUIDCacheClass 0x28
3.60 SceUIDThreadClass SceUIDWaitableClass 0x200
3.60 SceUIDFastMutexClass 0x80
3.60 SceUIDCallbackClass SceUIDClass 0x80
3.60 SceUIDRegisterCallbackClass SceUIDWaitableClass 0x30
3.60 SceUIDThreadEventClass SceUIDClass 0x80
3.60 SceUIDEventFlagClass SceUIDWaitableClass 0x80
3.60 SceUIDSemaphoreClass 0x80
3.60 SceUIDMutexClass 0x80
3.60 SceUIDCondClass 0x80
3.60 SceUIDEventClass SceUIDRegisterCallbackClass 0x38
3.60 SceUIDMsgPipeClass SceUIDEventClass 0x80
3.60 SceUIDLwMutexClass SceUIDWaitableClass 0x80
3.60 SceUIDLwCondClass 0x80
3.60 SceUIDRWLockClass 0x80
3.60 SceUIDSimpleEventClass SceUIDEventClass 0x80
3.60 SceUIDWorkQueueClass SceUIDWaitableClass 0x80
3.60 SceUIDWorkTaskClass 0x80
3.60 SceUIDExceptionClass 0x80
3.60 SceUIDCpuTimerClass SceUIDEventClass 0x58
3.60 SceUIDDelayClass SceUIDCpuTimerClass 0x80
3.60 SceUIDAlarmClass 0x80
3.60 SceUIDTimerClass 0x80
3.60 SceProcessmgr SceUIDProcBudgetClass SceUIDClass 0x74
3.60 SceUIDProcessClass 0x4E0
3.60 Unknown SceUIDVSlotClass SceUIDDLinkClass 0x40
3.60 SceIofilemgr SceUIDVfsFileClass SceUIDClass 0x48
3.60 SceUIDIoMountEventClass SceUIDEventClass 0x4C
3.60 SceUIDIoErrorEventClass 0x50
3.60 SceUIDIoAsyncEventClass 0xF8
3.60 SceDisplay SceUIDVblankEventClass SceUIDEventClass 0x38
3.60 SceCodecEngineWrapper SceUIDCodecEngineMemoryClass SceUIDClass 0x34
3.60 SceCoredump SceUIDCafContextClass SceUIDClass 0x4E0
3.60 SceDeci4pUserp SceUIDDeci4pUserpClass SceUIDClass 0x10

Temp

TODO: move these to an appropriate place.

SceUIDKernelHeapObject
#define SCE_KERNEL_HEAP_ATTR_AUTO_EXTEND        0x00000001
#define SCE_KERNEL_HEAP_ATTR_UNKNOWN_0x02       0x00000002
#define SCE_KERNEL_HEAP_ATTR_HEAP_CORRUPT_CHECK 0x00000010
#define SCE_KERNEL_HEAP_ATTR_HEAP_AVAILABLE     0x00000020
#define SCE_KERNEL_HEAP_ATTR_EXTEND_LIMIT       0x00000100
#define SCE_KERNEL_HEAP_ATTR_WITH_BASE          0x00000200
#define SCE_KERNEL_HEAP_ATTR_WITH_MEMORY_TYPE   0x00000400
#define SCE_KERNEL_HEAP_ATTR_SOME_SIZE          0x00000800
#define SCE_KERNEL_HEAP_ATTR_IMPORT_FROM_OBJECT 0x00001000

typedef struct SceKernelHeap { // size is 0x78-bytes
    uintptr_t unk_0x00;
    int cpu_intr;
    uintptr_t unk_0x08[2];
    SceUInt32 attr;
    SceSize unk_0x14; // from opt.field_14
    SceUInt32 heap_memory_type;
    SceSize unk_0x1C; // from opt.field_8
    SceSize heapSize1;
    SceSize heapSize2;
    SceUInt32 currentHeapCount;
    SceUInt32 maximumHeapCount;
    SceSize currentHeapUsedSize;
    SceSize maximumHeapUsedSize;
    SceSize maximumRequestSize;
    void *pWorkingArea; // for internal
    char *name;
    void *data_0x44;
    SceUInt32 unk_0x48;
    SceUInt32 unk_0x4C[0xB]; // zeros
} SceKernelHeap;

typedef struct SceUIDKernelHeapObject { // size is 0x80-bytes
    union {
        uintptr_t sce_rsvd[2];
        struct {
            void *pUserdata;
            SceClass *pClass;
        };
    };
    SceKernelHeap kernelHeap;
} SceUIDKernelHeapObject;
SceUIDCacheObject
typedef struct SceUIDCacheObject { // size is 0x10-bytes
	SceUIDObject uid_obj;
	int unk_0x08;
	int unk_0x0C;
} SceUIDCacheObject;
SceUIDWaitableObject
typedef struct SceUIDWaitableObject { // size is 0x28-bytes
	SceUIDCacheObject cache;
	int unk_0x10;
	int unk_0x14;
	int unk_0x18;
	int unk_0x1C;
	int unk_0x20;
	int unk_0x24;
} SceUIDWaitableObject;
SceUIDProcEventObject
typedef struct SceKernelProcEvent { // size is 0x28-bytes
	struct SceKernelProcEvent *root;
	struct SceKernelProcEvent *next;
	SceUID procEventId;
	void *args;
	int (* create)(SceUID pid, SceProcEventInvokeParam2 *a2, int a3);
	int (* exit)(SceUID pid, SceProcEventInvokeParam1 *a2, int a3);                             // current process exit
	int (* kill)(SceUID pid, SceProcEventInvokeParam1 *a2, int a3);                             // by SceShell
	int (* stop)(SceUID pid, int event_type, SceProcEventInvokeParam1 *a3, int a4);
	int (* start)(SceUID pid, int event_type, SceProcEventInvokeParam1 *a3, int a4);
	int (* switch_process)(int event_id, int event_type, SceProcEventInvokeParam2 *a3, int a4); // switch display frame?
} SceKernelProcEvent;

typedef struct SceUIDProcEventObject { // size is 0x30-bytes
	uintptr_t sce_rsvd[2];
	SceKernelProcEvent procEvent;
} SceUIDProcEventObject;
SceUIDSysEventObject
typedef struct SceKernelSysEvent { // size is 0x18-bytes
	struct SceKernelProcEvent *root;
	struct SceKernelProcEvent *next;
	SceUID sysEventId;
	SceSysEventHandler handler;
	void *args;
	SceUInt32 unused;
} SceKernelSysEvent;

typedef struct SceUIDSysEventObject { // size is 0x20-bytes
	uintptr_t sce_rsvd[2];
	SceKernelSysEvent sysEvent;
} SceUIDSysEventObject;

UID Attr

     Mask   Description
  0x70000 |   vis_level
 0x300000 |   act entry

GUID

Global UID.

0 0 00 0000 0000 0001 0000 0000 0000 000 1

Error bit. should be 0.

PUID bit. should be 0.

Sub UID. 14-bits wide. Has no effect directly for core uid. Somewhat random values are used for security (With increase method).

Core UID. 15-bits wide. Value to identify the object.

UID bit. should be 1.


The Core UID is 15-bits so in theory the system can create to 0x8000 (32768) objects


Example : 0x10005, 0x10007, 0x10547, 0x2DF84A9

PUID

Process UID.

0 1 00 0000 0000 0001 0000 0000 0000 000 1

Error bit. should be 0.

PUID bit. should be 1.

Unknown. maybe sub UID. 14-bits wide.

Unknown. maybe core UID. 15-bits wide.

UID bit. should be 1.

Example : 0x40010001

Security

KASLR

Since PS Vita FW 1.80 or so, the kernel implements kernel address space layout randomization to discourage ROP attacks.

Canaries

Since PS Vita FW 1.80 or so, the kernel makes use of stack canaries to detect stack buffer overflows and halts the system when an overflow is detected.

Memory Domains

Memory domains is a feature in ARM MMU that provides an easy way of showing and hiding groups of addresses as well as their permissions. When a system call is done, the handler disables all access to memory domains for usermode memory so kernel code cannot directly access usermode memory. This means that if a usermode pointer is passed in and if the kernel forgets to check it and dereferences it directly, it will abort with an exception. See SceExcpmgr. In order to access usermode memory, special functions are used that temporarily enable all domains. The access is implemented with the ARM unprivileged access instructions LDRT and STRT to make sure that the access functions cannot read or write in kernel memory space. As long as the domain disabling code in the syscall hander is secure and as long as the usermode memory access functions are secure, there is no need for additional checks implemented per function. A similar security on Linux is "SMAP" that crashes the kernel when kernel stack pointer points to usermode memory. Additionally all non-code pages are marked as "execute never" (XN) in both kernel and usermode.

Syscall Randomization

The numbers assigned to syscalls change on each boot but the delta between the same functions exported by the same module will stay consistent.

NID Poisoning

Since PS Vita FW 2.10, SceKernelModulemgr replaces the function/variable NIDs entries in the module import tables with junk data. This means that an attacker can no longer map syscall numbers to function NIDs.

Usermode stack pivot protection

Since unknown PS Vita System Software version (seen on 3.18) the kernel terminates an application if it notices that its stack pointer register (SP) is not pointing into the stack memory.

Usermode and kernel heaps overflow protection

dlmalloc, used for heap allocations, is compiled with -DFOOTERS=1 to enable more heap overflow checks. Additionally, a custom SceNetPs malloc implementation also does some heap overflow checks on its own.