From 2fd2dd12ded8976cd536c441d7892f8a94408094 Mon Sep 17 00:00:00 2001 From: tompro Date: Sun, 18 Feb 2024 01:22:37 +0100 Subject: [PATCH 1/4] Refactors regmgr_call --- src/kernel/src/regmgr/command.rs | 30 +++++++++++++++++ src/kernel/src/regmgr/mod.rs | 42 ++++++++++++++--------- src/kernel/src/ucred/mod.rs | 1 + src/kernel/src/ucred/privilege.rs | 56 +++++++++++++++++-------------- 4 files changed, 87 insertions(+), 42 deletions(-) create mode 100644 src/kernel/src/regmgr/command.rs diff --git a/src/kernel/src/regmgr/command.rs b/src/kernel/src/regmgr/command.rs new file mode 100644 index 000000000..de5c5afae --- /dev/null +++ b/src/kernel/src/regmgr/command.rs @@ -0,0 +1,30 @@ +use super::RegError; + +#[repr(u32)] +pub(super) enum RegMgrCommand<'a> { + SetInt(&'a SetIngArg) = 0x18, + Unk1(&'a Unk1Arg) = 0x19, +} +impl RegMgrCommand<'_> { + pub fn try_from_raw_parts(cmd: u32, arg: *const u8) -> Result { + match cmd { + 0x18 => Ok(RegMgrCommand::SetInt(unsafe { &*(arg as *const _) })), + 0x19 => Ok(RegMgrCommand::Unk1(unsafe { &*(arg as *const _) })), + 0x27 | 0x40.. => Err(RegError::V800d0219), + v => todo!("RegMgrCommand({v})"), + } + } +} + +#[repr(C)] +pub(super) struct SetIngArg { + pub v1: u64, + pub v2: u32, + pub value: i32, +} + +#[repr(C)] +pub(super) struct Unk1Arg { + pub v1: u64, + pub v2: u32, +} diff --git a/src/kernel/src/regmgr/mod.rs b/src/kernel/src/regmgr/mod.rs index 41b5c7a80..6bda21b40 100644 --- a/src/kernel/src/regmgr/mod.rs +++ b/src/kernel/src/regmgr/mod.rs @@ -1,16 +1,17 @@ -pub use self::key::*; - +use self::command::*; use crate::errno::EINVAL; use crate::process::VThread; use crate::syscalls::{SysErr, SysIn, SysOut, Syscalls}; -use crate::ucred::Ucred; +use crate::ucred::{Privilege, Ucred}; use crate::{info, warn}; use std::fmt::{Display, Formatter}; use std::num::NonZeroI32; -use std::ptr::read; use std::sync::Arc; use thiserror::Error; +pub use self::key::*; + +mod command; mod key; /// An implementation of PS4 registry manager. @@ -33,7 +34,10 @@ impl RegMgr { let req: *const u8 = i.args[3].into(); let reqlen: usize = i.args[4].into(); - // TODO: Check the result of priv_check(td, 682). + let td = VThread::current().unwrap(); + + td.cred().priv_check(Privilege::SCE682)?; + if buf.is_null() { todo!("regmgr_call with buf = null"); } @@ -46,13 +50,21 @@ impl RegMgr { todo!("regmgr_call with reqlen > 2048"); } + let command = match RegMgrCommand::try_from_raw_parts(op, req) { + Ok(v) => v, + Err(e) => { + warn!(e, "regmgr_call({op}) failed"); + unsafe { *buf = e.code() }; + return Ok(SysOut::ZERO); + } + }; + // Execute the operation. - let td = VThread::current().unwrap(); - let r = match op { - 0x18 => { - let v1 = unsafe { read::(req as _) }; - let v2 = unsafe { read::(req.add(8) as _) }; - let value = unsafe { read::(req.add(12) as _) }; + let r = match command { + RegMgrCommand::SetInt(arg) => { + let v1 = arg.v1; + let v2 = arg.v2; + let value = arg.value; info!( "Attempting to set registry with v1: {}, v2: {}, value: {}.", @@ -64,15 +76,13 @@ impl RegMgr { self.set_int(k, value) }) } - 0x19 => { - let v1 = unsafe { read::(req as _) }; - let v2 = unsafe { read::(req.add(8) as _) }; + RegMgrCommand::Unk1(arg) => { + let v1 = arg.v1; + let v2 = arg.v2; self.decode_key(v1, v2, td.cred(), 1) .and_then(|k| todo!("regmgr_call({op}) with matched key = {k}")) } - 0x27 | 0x40.. => Err(RegError::V800d0219), - v => todo!("regmgr_call({v})"), }; // Write the result. diff --git a/src/kernel/src/ucred/mod.rs b/src/kernel/src/ucred/mod.rs index b452b432b..0459d3071 100644 --- a/src/kernel/src/ucred/mod.rs +++ b/src/kernel/src/ucred/mod.rs @@ -99,6 +99,7 @@ impl Ucred { Privilege::MAXFILES | Privilege::PROC_SETLOGIN | Privilege::SCE680 + | Privilege::SCE682 | Privilege::SCE683 | Privilege::SCE686 => self.is_system(), v => todo!("priv_check_cred(cred, {v})"), diff --git a/src/kernel/src/ucred/privilege.rs b/src/kernel/src/ucred/privilege.rs index b3169580f..b05b345b8 100644 --- a/src/kernel/src/ucred/privilege.rs +++ b/src/kernel/src/ucred/privilege.rs @@ -8,33 +8,37 @@ use std::fmt::{Display, Formatter}; #[derive(Clone, Copy, PartialEq, Eq)] pub struct Privilege(i32); -impl Privilege { - pub const MAXFILES: Self = Self(3); - pub const PROC_SETLOGIN: Self = Self(161); - pub const VFS_READ: Self = Self(310); - pub const VFS_WRITE: Self = Self(311); - pub const VFS_ADMIN: Self = Self(312); - pub const VFS_EXEC: Self = Self(313); - pub const VFS_LOOKUP: Self = Self(314); - pub const SCE680: Self = Self(680); - pub const SCE683: Self = Self(683); - pub const SCE686: Self = Self(686); -} +macro_rules! privileges { + ($($name:ident($value:expr)),*) => { + impl Privilege { + $( + pub const $name: Self = Self($value); + )* + } -impl Display for Privilege { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match *self { - Self::MAXFILES => f.write_str("PRIV_MAXFILES"), - Self::PROC_SETLOGIN => f.write_str("PRIV_PROC_SETLOGIN"), - Self::VFS_READ => f.write_str("PRIV_VFS_READ"), - Self::VFS_WRITE => f.write_str("PRIV_VFS_WRITE"), - Self::VFS_ADMIN => f.write_str("PRIV_VFS_ADMIN"), - Self::VFS_EXEC => f.write_str("PRIV_VFS_EXEC"), - Self::VFS_LOOKUP => f.write_str("PRIV_VFS_LOOKUP"), - Self::SCE680 => f.write_str("SCE680"), - Self::SCE683 => f.write_str("SCE683"), - Self::SCE686 => f.write_str("SCE686"), - v => v.0.fmt(f), + impl Display for Privilege { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match *self { + $( + Self($value) => f.write_str(stringify!($name)), + )* + v => v.0.fmt(f), + } + } } } } + +privileges! { + MAXFILES(3), + PROC_SETLOGIN(161), + VFS_READ(310), + VFS_WRITE(311), + VFS_ADMIN(312), + VFS_EXEC(313), + VFS_LOOKUP(314), + SCE680(680), + SCE682(682), + SCE683(683), + SCE686(686) +} From 42d8f06c29414a1fd59f71f13afbe9deceb6e840 Mon Sep 17 00:00:00 2001 From: tompro Date: Sun, 18 Feb 2024 01:33:50 +0100 Subject: [PATCH 2/4] rename type --- src/kernel/src/regmgr/command.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/kernel/src/regmgr/command.rs b/src/kernel/src/regmgr/command.rs index de5c5afae..872c54948 100644 --- a/src/kernel/src/regmgr/command.rs +++ b/src/kernel/src/regmgr/command.rs @@ -2,7 +2,7 @@ use super::RegError; #[repr(u32)] pub(super) enum RegMgrCommand<'a> { - SetInt(&'a SetIngArg) = 0x18, + SetInt(&'a SetIntArg) = 0x18, Unk1(&'a Unk1Arg) = 0x19, } impl RegMgrCommand<'_> { @@ -17,7 +17,7 @@ impl RegMgrCommand<'_> { } #[repr(C)] -pub(super) struct SetIngArg { +pub(super) struct SetIntArg { pub v1: u64, pub v2: u32, pub value: i32, From 08b1c44bb09336c443a2c8645f70091e6df01cb1 Mon Sep 17 00:00:00 2001 From: tompro Date: Sun, 18 Feb 2024 16:27:24 +0100 Subject: [PATCH 3/4] refactor --- src/kernel/src/fs/ioctl.rs | 8 ++++++-- src/kernel/src/fs/mod.rs | 2 +- src/kernel/src/regmgr/command.rs | 16 ++++++++++++---- src/kernel/src/regmgr/mod.rs | 6 +++--- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/kernel/src/fs/ioctl.rs b/src/kernel/src/fs/ioctl.rs index ff11048c5..31f5d0296 100644 --- a/src/kernel/src/fs/ioctl.rs +++ b/src/kernel/src/fs/ioctl.rs @@ -1,5 +1,7 @@ use crate::errno::ENOTTY; +use crate::syscalls::SysArg; use crate::syscalls::SysErr; +use std::convert::Into; /// This macro does some compile time verification to ensure we don't mistype anything. /// It also ensures that we don't miss any commands, since [`IoCmd::try_from_raw_parts`] will panic with a todo! if it encounters an unknown command. @@ -43,7 +45,9 @@ macro_rules! commands { pub const IOC_OUT: u32 = 0x40000000; pub const IOC_IN: u32 = 0x80000000; - pub fn try_from_raw_parts(cmd: u64, arg: *mut u8) -> Result { + /// # Safety + /// `arg` has to be a pointer to the correct value + pub unsafe fn try_from_raw_parts(cmd: u64, arg: SysArg) -> Result { let cmd = cmd as u32; if Self::is_invalid(cmd) { @@ -51,7 +55,7 @@ macro_rules! commands { } let cmd = match cmd { - $( $value => Self::$variant $( ( unsafe { &mut *(arg as *mut $type) } ) )? ,)* + $( $value => Self::$variant $( ( unsafe { &mut *(Into::<*mut $type>::into(arg)) } ) )? ,)* _ => todo!("Unhandled ioctl command {:#x}", cmd) }; diff --git a/src/kernel/src/fs/mod.rs b/src/kernel/src/fs/mod.rs index a64233928..ddde47892 100644 --- a/src/kernel/src/fs/mod.rs +++ b/src/kernel/src/fs/mod.rs @@ -448,7 +448,7 @@ impl Fs { fn sys_ioctl(self: &Arc, i: &SysIn) -> Result { let fd: i32 = i.args[0].try_into().unwrap(); // Our IoCmd contains both the command and the argument (if there is one). - let cmd = IoCmd::try_from_raw_parts(i.args[1].into(), i.args[2].into())?; + let cmd = unsafe { IoCmd::try_from_raw_parts(i.args[1].into(), i.args[2].into())? }; let td = VThread::current().unwrap(); diff --git a/src/kernel/src/regmgr/command.rs b/src/kernel/src/regmgr/command.rs index 872c54948..3e73e40c7 100644 --- a/src/kernel/src/regmgr/command.rs +++ b/src/kernel/src/regmgr/command.rs @@ -1,15 +1,23 @@ use super::RegError; +use crate::syscalls::SysArg; +use std::convert::Into; #[repr(u32)] pub(super) enum RegMgrCommand<'a> { SetInt(&'a SetIntArg) = 0x18, Unk1(&'a Unk1Arg) = 0x19, } -impl RegMgrCommand<'_> { - pub fn try_from_raw_parts(cmd: u32, arg: *const u8) -> Result { +impl<'a> RegMgrCommand<'a> { + /// # Safety + /// `arg` has to be a pointer to the correct value + pub unsafe fn try_from_raw_parts(cmd: u32, arg: SysArg) -> Result { match cmd { - 0x18 => Ok(RegMgrCommand::SetInt(unsafe { &*(arg as *const _) })), - 0x19 => Ok(RegMgrCommand::Unk1(unsafe { &*(arg as *const _) })), + 0x18 => Ok(RegMgrCommand::SetInt(unsafe { + &*(Into::<*mut _>::into(arg)) + })), + 0x19 => Ok(RegMgrCommand::Unk1(unsafe { + &*(Into::<*mut _>::into(arg)) + })), 0x27 | 0x40.. => Err(RegError::V800d0219), v => todo!("RegMgrCommand({v})"), } diff --git a/src/kernel/src/regmgr/mod.rs b/src/kernel/src/regmgr/mod.rs index 6bda21b40..08c42d71e 100644 --- a/src/kernel/src/regmgr/mod.rs +++ b/src/kernel/src/regmgr/mod.rs @@ -31,7 +31,7 @@ impl RegMgr { // Get arguments. let op: u32 = i.args[0].try_into().unwrap(); let buf: *mut i32 = i.args[2].into(); - let req: *const u8 = i.args[3].into(); + let req = i.args[3]; let reqlen: usize = i.args[4].into(); let td = VThread::current().unwrap(); @@ -42,7 +42,7 @@ impl RegMgr { todo!("regmgr_call with buf = null"); } - if req.is_null() { + if req == 0 { todo!("regmgr_call with req = null"); } @@ -50,7 +50,7 @@ impl RegMgr { todo!("regmgr_call with reqlen > 2048"); } - let command = match RegMgrCommand::try_from_raw_parts(op, req) { + let command = match unsafe { RegMgrCommand::try_from_raw_parts(op, req) } { Ok(v) => v, Err(e) => { warn!(e, "regmgr_call({op}) failed"); From 78f573cead066cc96ebc8c3724137a35f357a83b Mon Sep 17 00:00:00 2001 From: tompro Date: Sat, 24 Feb 2024 09:56:20 +0100 Subject: [PATCH 4/4] refactor --- src/kernel/src/fs/ioctl.rs | 28 ++++++++++++++++++++++++++-- src/kernel/src/fs/mod.rs | 5 ++++- src/kernel/src/regmgr/command.rs | 9 ++++----- src/kernel/src/regmgr/mod.rs | 6 +++--- 4 files changed, 37 insertions(+), 11 deletions(-) diff --git a/src/kernel/src/fs/ioctl.rs b/src/kernel/src/fs/ioctl.rs index 31f5d0296..250c78c3e 100644 --- a/src/kernel/src/fs/ioctl.rs +++ b/src/kernel/src/fs/ioctl.rs @@ -47,7 +47,7 @@ macro_rules! commands { /// # Safety /// `arg` has to be a pointer to the correct value - pub unsafe fn try_from_raw_parts(cmd: u64, arg: SysArg) -> Result { + pub unsafe fn try_from_raw_parts(cmd: u64, arg: RawCommandArg) -> Result { let cmd = cmd as u32; if Self::is_invalid(cmd) { @@ -55,7 +55,7 @@ macro_rules! commands { } let cmd = match cmd { - $( $value => Self::$variant $( ( unsafe { &mut *(Into::<*mut $type>::into(arg)) } ) )? ,)* + $( $value => Self::$variant $( ( unsafe { &mut *(arg.ptr() as *mut $type) } ) )? ,)* _ => todo!("Unhandled ioctl command {:#x}", cmd) }; @@ -106,3 +106,27 @@ commands! { DIOCGMEDIASIZE(&i64) = 0x40086418, } } + +pub struct RawCommandArg<'a> { + ptr: *mut u8, + _phantom: std::marker::PhantomData<&'a u8>, +} + +impl<'a> RawCommandArg<'a> { + pub fn ptr(&self) -> *mut u8 { + self.ptr + } + + pub fn is_null(&self) -> bool { + self.ptr.is_null() + } +} + +impl From for RawCommandArg<'_> { + fn from(arg: SysArg) -> Self { + Self { + ptr: arg.into(), + _phantom: std::marker::PhantomData, + } + } +} diff --git a/src/kernel/src/fs/mod.rs b/src/kernel/src/fs/mod.rs index 93385a1cc..c608bcd33 100644 --- a/src/kernel/src/fs/mod.rs +++ b/src/kernel/src/fs/mod.rs @@ -441,8 +441,11 @@ impl Fs { fn sys_ioctl(self: &Arc, td: &VThread, i: &SysIn) -> Result { let fd: i32 = i.args[0].try_into().unwrap(); + let cmd: u64 = i.args[1].into(); + let arg: RawCommandArg = i.args[2].into(); + // Our IoCmd contains both the command and the argument (if there is one). - let cmd = unsafe { IoCmd::try_from_raw_parts(i.args[1].into(), i.args[2].into())? }; + let cmd = unsafe { IoCmd::try_from_raw_parts(cmd, arg)? }; info!("Executing ioctl({cmd:?}) on file descriptor {fd}."); diff --git a/src/kernel/src/regmgr/command.rs b/src/kernel/src/regmgr/command.rs index 3e73e40c7..d3f3f1886 100644 --- a/src/kernel/src/regmgr/command.rs +++ b/src/kernel/src/regmgr/command.rs @@ -1,6 +1,5 @@ use super::RegError; -use crate::syscalls::SysArg; -use std::convert::Into; +use crate::fs::RawCommandArg; #[repr(u32)] pub(super) enum RegMgrCommand<'a> { @@ -10,13 +9,13 @@ pub(super) enum RegMgrCommand<'a> { impl<'a> RegMgrCommand<'a> { /// # Safety /// `arg` has to be a pointer to the correct value - pub unsafe fn try_from_raw_parts(cmd: u32, arg: SysArg) -> Result { + pub unsafe fn try_from_raw_parts(cmd: u32, arg: RawCommandArg) -> Result { match cmd { 0x18 => Ok(RegMgrCommand::SetInt(unsafe { - &*(Into::<*mut _>::into(arg)) + &*(arg.ptr() as *mut SetIntArg) })), 0x19 => Ok(RegMgrCommand::Unk1(unsafe { - &*(Into::<*mut _>::into(arg)) + &*(arg.ptr() as *mut Unk1Arg) })), 0x27 | 0x40.. => Err(RegError::V800d0219), v => todo!("RegMgrCommand({v})"), diff --git a/src/kernel/src/regmgr/mod.rs b/src/kernel/src/regmgr/mod.rs index 3f32dd599..361e1543b 100644 --- a/src/kernel/src/regmgr/mod.rs +++ b/src/kernel/src/regmgr/mod.rs @@ -1,5 +1,6 @@ use self::command::*; use crate::errno::EINVAL; +use crate::fs::RawCommandArg; use crate::process::VThread; use crate::syscalls::{SysErr, SysIn, SysOut, Syscalls}; use crate::ucred::{Privilege, Ucred}; @@ -7,7 +8,6 @@ use crate::{info, warn}; use std::fmt::{Display, Formatter}; use std::num::NonZeroI32; use std::ops::Index; -use std::ptr::read; use std::sync::Arc; use thiserror::Error; @@ -33,7 +33,7 @@ impl RegMgr { // Get arguments. let op: u32 = i.args[0].try_into().unwrap(); let buf: *mut i32 = i.args[2].into(); - let req = i.args[3]; + let req: RawCommandArg = i.args[3].into(); let reqlen: usize = i.args[4].into(); let td = VThread::current().unwrap(); @@ -44,7 +44,7 @@ impl RegMgr { todo!("regmgr_call with buf = null"); } - if req == 0 { + if req.is_null() { todo!("regmgr_call with req = null"); }