Skip to content

Instantly share code, notes, and snippets.

@john-tornblom
Created December 21, 2025 14:08
Show Gist options
  • Select an option

  • Save john-tornblom/61c4f381c449706243fffaff990d671b to your computer and use it in GitHub Desktop.

Select an option

Save john-tornblom/61c4f381c449706243fffaff990d671b to your computer and use it in GitHub Desktop.
/* Copyright (C) 2025 John Törnblom
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>. */
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/un.h>
#include <ps5/kernel.h>
static char*
bin2hex(const uint8_t* bin, char* hex, size_t binsize) {
hex[0] = '0';
hex[1] = 'x';
for(size_t i=0; i<binsize; ++i) {
sprintf(&hex[i*2 + 2], "%02x", bin[i]);
}
hex[binsize*2 + 2] = '\0';
return hex;
}
static void
print_privileges(pid_t pid) {
uint8_t qaflags[16] = {0};
uint8_t caps[16] = {0};
char buf[16*3];
kernel_get_qaflags(qaflags);
kernel_get_ucred_caps(pid, caps);
puts("Console info");
puts("------------");
printf("Firmware: %08x\n", kernel_get_fw_version());
printf("TARGETID: 0x%02x\n", kernel_getchar(KERNEL_ADDRESS_TARGETID));
printf("SECURITY_FLAGS: 0x%02x\n", kernel_getchar(KERNEL_ADDRESS_SECURITY_FLAGS));
printf("UTOKEN_FLAGS: 0x%02x\n", kernel_getchar(KERNEL_ADDRESS_UTOKEN_FLAGS));
printf("QA_FLAGS: %s\n", bin2hex(qaflags, buf, sizeof(qaflags)));
puts("");
puts("Privileges");
puts("----------");
printf("SCE authid: 0x%016lx\n", kernel_get_ucred_authid(pid));
printf("SCE attrs: 0x%016lx\n", kernel_get_ucred_attrs(pid));
printf("SCE caps: %s\n", bin2hex(caps, buf, sizeof(caps)));
printf("uid: %d\n", getuid());
printf("euid: %d\n", geteuid());
printf("jail vnode: 0x%lx\n", kernel_get_proc_jaildir(pid));
puts("");
}
static int
raise_privileges(pid_t pid) {
static const uint8_t caps[16] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
kernel_set_ucred_authid(pid, 0x4800000000010003l);
kernel_set_ucred_attrs(pid, -1l);
kernel_set_ucred_uid(pid, 0);
kernel_set_ucred_ruid(pid, 0);
kernel_set_ucred_caps(pid, caps);
return 0;
}
static int
test_symlinks(void) {
int err = 0;
puts("");
puts("Testing symlinks");
puts("----------------");
if(__syscall(SYS_symlink, "/data", "/system_data/temp/symlink_to_data")) {
perror("ufs symlink (/system_data)");
err = 1;
} else {
puts("ufs symlink (/system_data): OK");
unlink("/system_data/temp/symlink_to_data");
}
//
if(__syscall(SYS_symlink, "/data", "/system_tmp/symlink_to_data")) {
perror("nullfs symlink (/system_tmp)");
err = 1;
} else {
puts("nullfs symlink (/system_tmp): OK");
unlink("/system_tmp/symlink_to_data");
}
//
if(__syscall(SYS_symlink, "/data", "/user/temp/symlink_to_data")) {
perror("bfs symlink (/user/temp)");
err = 1;
} else {
puts("bfs symlink (/user/temp): OK");
unlink("/user/temp/symlink_to_data");
}
return err;
}
static int
test_domain_socket(const char* test_name, const char* path) {
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
int err = 0;
struct sockaddr_un addr;
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, path);
if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
printf("%s: %s\n", test_name, strerror(errno));
err = -1;
} else {
printf("%s: OK\n", test_name);
}
close(fd);
unlink(addr.sun_path);
return err;
}
static int
test_hardlinks(void) {
int err = 0;
puts("");
puts("Testing hardlinks");
puts("-----------------");
if(__syscall(SYS_mkdir, "/system_data/temp/test")) {
perror("mkdir /system_data/temp/test");
err = -1;
} else if(__syscall(SYS_link, "/system_data/temp/test", "/system_data/temp/link_to_test")) {
perror("ufs hardlink (/system_data)");
err = -1;
} else {
puts("ufs hardlink (/system_data): OK");
}
__syscall(SYS_unlink, "/system_data/temp/link_to_test");
__syscall(SYS_rmdir, "/system_data/temp/test");
//
if(__syscall(SYS_mkdir, "/system_tmp/test")) {
perror("mkdir /system_tmp/test");
err = -1;
} else if(__syscall(SYS_link, "/system_tmp/test", "/system_tmp/link_to_test")) {
perror("nullfs hardlink (/system_tmp)");
err = -1;
} else {
puts("nullfs hardlink (/system_tmp): OK");
}
__syscall(SYS_unlink, "/system_tmp/link_to_test");
__syscall(SYS_rmdir, "/system_tmp/test");
//
if(__syscall(SYS_mkdir, "/user/temp/test")) {
perror("mkdir /user/temp/test");
err = -1;
} else if(__syscall(SYS_link, "/user/temp/test", "/user/temp/link_to_test")) {
perror("bfs hardlink (/user/temp)");
err = -1;
} else {
puts("bfs hardlink (/user/temp): OK");
}
__syscall(SYS_unlink, "/user/temp/link_to_test");
__syscall(SYS_rmdir, "/user/temp/test");
return err;
}
static int
test_mknod_fifo(void) {
int err = 0;
puts("");
puts("Testing mknod(S_IFIFO)");
puts("----------------------");
if(__syscall(SYS_mknod, "/system_data/temp/fifo", S_IFIFO | 0666, 0)) {
perror("ufs mknod S_IFIFO (/system_data)");
err = 1;
} else {
puts("ufs mknod S_IFIFO (/system_data): OK");
unlink("/system_data/temp/fifo");
}
if(__syscall(SYS_mknod, "/system_tmp/fifo", S_IFIFO | 0666, 0)) {
perror("nullfs mknod S_IFIFO (/system_tmp)");
err = 1;
} else {
puts("nullfs mknod S_IFIFO (/system_tmp): OK");
unlink("/system_tmp/fifo");
}
if(__syscall(SYS_mknod, "/user/temp/fifo", S_IFIFO | 0666, 0)) {
perror("bfs mknod S_IFIFO (/user/temp)");
err = 1;
} else {
puts("bfs mknod S_IFIFO (/user/temp): OK");
unlink("/user/temp/fifo");
}
return err;
}
int
main() {
raise_privileges(-1);
print_privileges(-1);
test_symlinks();
test_hardlinks();
test_mknod_fifo();
puts("");
puts("Testing UNIX domain socket");
puts("--------------------------");
test_domain_socket("ufs domain socket", "/system_data/temp/sock");
test_domain_socket("nullfs domain socket", "/system_tmp/sock");
test_domain_socket("bfs domain socket", "/user/temp/sock");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment