Skip to content

Commit

Permalink
Adds kern_openat for 11.00
Browse files Browse the repository at this point in the history
  • Loading branch information
ultimaweapon committed May 5, 2024
1 parent fc0bb89 commit 5450916
Show file tree
Hide file tree
Showing 12 changed files with 193 additions and 32 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ ps4k-1100 = { path = "ps4k-1100" }
opt-level = "z"

[workspace]
members = ["ps4k", "ps4k-1100"]
members = ["ps4k", "ps4k-1100", "ps4k-macros"]
19 changes: 19 additions & 0 deletions ps4k-1100/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
#![no_std]

use self::thread::Thread;
use core::ffi::{c_char, c_int};
use ps4k::offset;

mod thread;

/// Implementation of [`ps4k::version::KernelVersion`] for 11.00.
pub struct KernelVersion {
elf: &'static [u8],
}

impl ps4k::version::KernelVersion for KernelVersion {
type Thread = Thread;

unsafe fn new(base: *const u8) -> Self {
let elf = Self::get_mapped_elf(base);

Expand All @@ -15,4 +23,15 @@ impl ps4k::version::KernelVersion for KernelVersion {
unsafe fn elf(&self) -> &'static [u8] {
self.elf
}

#[offset(0xE63B0)]
unsafe fn kern_openat(
&self,
td: *mut Self::Thread,
fd: c_int,
path: *const c_char,
kernel: bool,
flags: c_int,
mode: c_int,
) -> c_int;
}
12 changes: 12 additions & 0 deletions ps4k-1100/src/thread.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/// Implementation of [`ps4k::version::Thread`] for 11.00.
#[repr(C)]
pub struct Thread {
pad: [u8; 0x398],
ret: [usize; 2], // td_retval
}

impl ps4k::version::Thread for Thread {
fn ret(&self, i: usize) -> usize {
self.ret[i]
}
}
12 changes: 12 additions & 0 deletions ps4k-macros/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "ps4k-macros"
version = "0.1.0"
edition = "2021"

[lib]
proc-macro = true

[dependencies]
proc-macro2 = "1.0.81"
quote = "1.0.36"
syn = { version = "2.0.60", features = ["full"] }
14 changes: 14 additions & 0 deletions ps4k-macros/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use proc_macro::TokenStream;
use syn::{parse_macro_input, Error, LitInt};

mod offset;

#[proc_macro_attribute]
pub fn offset(args: TokenStream, item: TokenStream) -> TokenStream {
let args = parse_macro_input!(args as LitInt);
let item = parse_macro_input!(item as self::offset::OffsetItem);

self::offset::transform(args, item)
.unwrap_or_else(Error::into_compile_error)
.into()
}
79 changes: 79 additions & 0 deletions ps4k-macros/src/offset.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
use proc_macro2::TokenStream;
use quote::quote;
use syn::parse::{Parse, ParseStream};
use syn::punctuated::Punctuated;
use syn::{parenthesized, Error, Ident, LitInt, Pat, PatType, Receiver, ReturnType, Token};

pub fn transform(args: LitInt, item: OffsetItem) -> syn::Result<TokenStream> {
match item {
OffsetItem::Method(v) => transform_method(args, v),
}
}

fn transform_method(args: LitInt, item: Method) -> syn::Result<TokenStream> {
// Assemble.
let offset: usize = args.base10_parse()?;
let unsafety = item.unsafety;
let ident = item.ident;
let receiver = item.receiver;
let params = item.params;
let ret = item.ret;
let args: Punctuated<&Pat, Token![,]> = params.iter().map(|p| p.pat.as_ref()).collect();

Ok(quote! {
#unsafety fn #ident(#receiver, #params) #ret {
let ad = unsafe { self.elf().as_ptr().add(#offset) };
let fp: unsafe extern "C" fn(#params) #ret = unsafe { core::mem::transmute(ad) };
unsafe { fp(#args) }
}
})
}

/// Item of `offset` attribute.
pub enum OffsetItem {
Method(Method),
}

impl Parse for OffsetItem {
fn parse(input: ParseStream) -> syn::Result<Self> {
let unsafety = input.parse()?;
let item = if input.parse::<Option<Token![fn]>>()?.is_some() {
// Parse name.
let ident = input.parse()?;
let params;

parenthesized!(params in input);

// Parse receiver.
let receiver = params.parse()?;

params.parse::<Option<Token![,]>>()?;

// Parse return type.
let ret = input.parse()?;

input.parse::<Token![;]>()?;

Self::Method(Method {
unsafety,
ident,
receiver,
params: params.parse_terminated(PatType::parse, Token![,])?,
ret,
})
} else {
return Err(Error::new(input.span(), "unsupported offset item"));
};

Ok(item)
}
}

/// A method that have `offset` attribute.
pub struct Method {
unsafety: Option<Token![unsafe]>,
ident: Ident,
receiver: Receiver,
params: Punctuated<PatType, Token![,]>,
ret: ReturnType,
}
1 change: 1 addition & 0 deletions ps4k/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ version = "0.1.0"
edition = "2021"

[dependencies]
ps4k-macros = { path = "../ps4k-macros" }
2 changes: 2 additions & 0 deletions ps4k/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

use self::version::KernelVersion;

pub use ps4k_macros::*;

pub mod elf;
pub mod version;

Expand Down
21 changes: 20 additions & 1 deletion ps4k/src/version/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
pub use self::thread::*;
use crate::elf::ProgramType;
use core::ffi::{c_char, c_int};

mod thread;

/// Provides information about the PS4 kernel for a specific version.
pub trait KernelVersion: Send + Sync {
pub trait KernelVersion: Send + Sync + 'static {
type Thread: Thread;

/// # Safety
/// `base` must point to a valid address of the kernel. Behavior is undefined if format of the
/// kernel is unknown.
Expand All @@ -17,6 +23,19 @@ pub trait KernelVersion: Send + Sync {
/// can mutate at any time. The whole slice is guarantee to be readable.
unsafe fn elf(&self) -> &'static [u8];

/// # Safety
/// - `td` cannot be null.
/// - `path` cannot be null and must point to a null-terminated string if `kernel` is `true`.
unsafe fn kern_openat(
&self,
td: *mut Self::Thread,
fd: c_int,
path: *const c_char,
kernel: bool,
flags: c_int,
mode: c_int,
) -> c_int;

/// # Safety
/// `base` must point to a valid address of the kernel. Behavior is undefined if format of the
/// kernel is unknown.
Expand Down
20 changes: 20 additions & 0 deletions ps4k/src/version/thread.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use core::arch::asm;

/// Represents `thread` structure.
pub trait Thread: Sized {
fn current() -> *mut Self {
let mut p;

unsafe {
asm!("mov {}, gs:[0]", out(reg) p, options(readonly, pure, preserves_flags, nostack))
};

p
}

/// Returns value of `td_retval[i]`.
///
/// # Panics
/// If `i` is not `0` or `1`.
fn ret(&self, i: usize) -> usize;
}
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ pub extern "C" fn main(_: *const u8) {

// Setup dumping method.
#[cfg(method = "syscall")]
let method = unsafe { crate::syscall::SyscallMethod::new(base.as_ptr()) };
let method = unsafe { crate::syscall::SyscallMethod::new(&kernel) };

// Create dump file.
let out = match method.open(
Expand Down
41 changes: 12 additions & 29 deletions src/syscall.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use crate::method::{DumpMethod, OpenFlags, OwnedFd};
use core::arch::asm;
use core::ffi::{c_int, c_void, CStr};
use core::mem::transmute;
use core::num::NonZeroI32;
use ps4k::version::{KernelVersion, Thread};
use ps4k::Kernel;
use x86_64::registers::control::Cr0;

/// Implementation of [`DumpMethod`] using syscalls.
Expand All @@ -12,13 +13,14 @@ use x86_64::registers::control::Cr0;
///
/// The reason this method exists because in order for the direct method to work we need to get the
/// first dump to find the required function addresses.
pub struct SyscallMethod {
sysents: &'static [Sysent; 678],
pub struct SyscallMethod<V: KernelVersion> {
sysents: &'static [Sysent<V>; 678],
}

impl SyscallMethod {
pub unsafe fn new(base: *const u8) -> Self {
impl<V: KernelVersion> SyscallMethod<V> {
pub unsafe fn new(kernel: &Kernel<V>) -> Self {
// Remove address checking from copyin, copyout and copyinstr.
let base = kernel.version().elf().as_ptr();
let cr0 = Cr0::read_raw();

unsafe { Cr0::write_raw(cr0 & !(1 << 16)) };
Expand Down Expand Up @@ -53,7 +55,7 @@ impl SyscallMethod {
}
}

impl DumpMethod for SyscallMethod {
impl<V: KernelVersion> DumpMethod for SyscallMethod<V> {
fn open(
&self,
path: &CStr,
Expand All @@ -71,7 +73,7 @@ impl DumpMethod for SyscallMethod {
match NonZeroI32::new(errno) {
Some(v) => Err(v),
None => Ok(OwnedFd::new(self, unsafe {
(*td).ret[0].try_into().unwrap()
(*td).ret(0).try_into().unwrap()
})),
}
}
Expand All @@ -87,7 +89,7 @@ impl DumpMethod for SyscallMethod {

match NonZeroI32::new(errno) {
Some(v) => Err(v),
None => Ok(unsafe { (*td).ret[0] }),
None => Ok(unsafe { (*td).ret(0) }),
}
}

Expand Down Expand Up @@ -124,27 +126,8 @@ impl DumpMethod for SyscallMethod {

/// Implementation of `sysent` structure.
#[repr(C)]
struct Sysent {
struct Sysent<V: KernelVersion> {
narg: c_int,
handler: unsafe extern "C" fn(td: *mut Thread, uap: *const c_void) -> c_int,
handler: unsafe extern "C" fn(td: *mut V::Thread, uap: *const c_void) -> c_int,
pad: [u8; 0x20],
}

/// Implementation of `thread` structure.
#[repr(C)]
struct Thread {
pad: [u8; 0x398],
ret: [usize; 2], // td_retval
}

impl Thread {
fn current() -> *mut Self {
let mut p;

unsafe {
asm!("mov {}, gs:[0]", out(reg) p, options(readonly, pure, preserves_flags, nostack))
};

p
}
}

0 comments on commit 5450916

Please sign in to comment.