From b30367eb346d5342dda87174ac4442b909850f77 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Tue, 31 Dec 2024 11:53:55 +0000 Subject: [PATCH 1/3] implement /proc/pid/stat --- tee/kernel/src/fs/node/procfs.rs | 166 ++++++++++++++++++-- tee/kernel/src/user/process.rs | 35 ++++- tee/kernel/src/user/process/memory.rs | 34 +++- tee/kernel/src/user/process/syscall.rs | 8 +- tee/kernel/src/user/process/syscall/args.rs | 12 ++ tee/kernel/src/user/process/thread.rs | 107 ++++++++++++- tee/kernel/src/user/process/usage.rs | 6 +- 7 files changed, 343 insertions(+), 25 deletions(-) diff --git a/tee/kernel/src/fs/node/procfs.rs b/tee/kernel/src/fs/node/procfs.rs index 35ce0a2e..a5ddd45f 100644 --- a/tee/kernel/src/fs/node/procfs.rs +++ b/tee/kernel/src/fs/node/procfs.rs @@ -353,6 +353,7 @@ pub struct ProcessInos { fd_dir: u64, exe_link: u64, maps_file: u64, + stat_file: u64, } impl ProcessInos { @@ -363,6 +364,7 @@ impl ProcessInos { fd_dir: new_ino(), exe_link: new_ino(), maps_file: new_ino(), + stat_file: new_ino(), } } } @@ -376,6 +378,7 @@ struct ProcessDir { fd_file_lock_record: LazyFileLockRecord, exe_link_lock_record: LazyFileLockRecord, maps_file_lock_record: LazyFileLockRecord, + stat_file_lock_record: LazyFileLockRecord, } impl ProcessDir { @@ -393,6 +396,7 @@ impl ProcessDir { fd_file_lock_record: LazyFileLockRecord::new(), exe_link_lock_record: LazyFileLockRecord::new(), maps_file_lock_record: LazyFileLockRecord::new(), + stat_file_lock_record: LazyFileLockRecord::new(), }) } } @@ -448,28 +452,30 @@ impl Directory for ProcessDir { } fn get_node(&self, file_name: &FileName, _ctx: &FileAccessContext) -> Result { - if file_name == "fd" { - Ok(FdDir::new( + Ok(match file_name.as_bytes() { + b"fd" => FdDir::new( StaticLocation::new(self.this.upgrade().unwrap(), file_name.clone().into_owned()), self.fs.clone(), self.process.clone(), self.fd_file_lock_record.get().clone(), - )) - } else if file_name == "exe" { - Ok(ExeLink::new( + ), + b"exe" => ExeLink::new( self.fs.clone(), self.process.clone(), self.exe_link_lock_record.get().clone(), - )) - } else if file_name == "maps" { - Ok(MapsFile::new( + ), + b"maps" => MapsFile::new( self.fs.clone(), self.process.clone(), self.maps_file_lock_record.get().clone(), - )) - } else { - bail!(NoEnt) - } + ), + b"stat" => ProcessStatFile::new( + self.fs.clone(), + self.process.clone(), + self.stat_file_lock_record.get().clone(), + ), + _ => bail!(NoEnt), + }) } fn create_file( @@ -548,6 +554,11 @@ impl Directory for ProcessDir { ty: FileType::File, name: DirEntryName::FileName(FileName::new(b"maps").unwrap()), }); + entries.push(DirEntry { + ino: process.inos.stat_file, + ty: FileType::File, + name: DirEntryName::FileName(FileName::new(b"stat").unwrap()), + }); Ok(entries) } @@ -1171,3 +1182,134 @@ impl File for MapsFile { bail!(Acces) } } + +struct ProcessStatFile { + this: Weak, + fs: Arc, + process: Weak, + file_lock_record: Arc, +} + +impl ProcessStatFile { + pub fn new( + fs: Arc, + process: Weak, + file_lock_record: Arc, + ) -> Arc { + Arc::new_cyclic(|this| Self { + this: this.clone(), + fs, + process, + file_lock_record, + }) + } +} + +impl INode for ProcessStatFile { + fn stat(&self) -> Result { + let process = self.process.upgrade().ok_or(err!(Srch))?; + Ok(Stat { + dev: self.fs.dev, + ino: process.inos.maps_file, + nlink: 1, + mode: FileTypeAndMode::new(FileType::File, FileMode::from_bits_retain(0o444)), + uid: Uid::SUPER_USER, + gid: Gid::SUPER_USER, + rdev: 0, + size: 0, + blksize: 0, + blocks: 0, + atime: Timespec::ZERO, + mtime: Timespec::ZERO, + ctime: Timespec::ZERO, + }) + } + + fn fs(&self) -> Result> { + Ok(self.fs.clone()) + } + + fn open(&self, path: Path, flags: OpenFlags) -> Result { + open_file(path, self.this.upgrade().unwrap(), flags) + } + + fn chmod(&self, _: FileMode, _: &FileAccessContext) -> Result<()> { + bail!(Perm) + } + + fn chown(&self, _: Uid, _: Gid, _: &FileAccessContext) -> Result<()> { + Ok(()) + } + + fn update_times(&self, _ctime: Timespec, _atime: Option, _mtime: Option) {} + + fn file_lock_record(&self) -> &Arc { + &self.file_lock_record + } +} + +impl File for ProcessStatFile { + fn get_page(&self, _page_idx: usize, _shared: bool) -> Result { + bail!(NoDev) + } + + fn read(&self, offset: usize, buf: &mut [u8], _no_atime: bool) -> Result { + let process = self.process.upgrade().ok_or(err!(Srch))?; + let thread = process.thread_group_leader().upgrade().ok_or(err!(Srch))?; + let stat = thread.lock().stat(); + let offset = cmp::min(offset, stat.len()); + let stat = &stat[offset..]; + let len = cmp::min(stat.len(), buf.len()); + buf[..len].copy_from_slice(&stat[..len]); + Ok(len) + } + + fn read_to_user( + &self, + offset: usize, + vm: &VirtualMemory, + pointer: Pointer<[u8]>, + len: usize, + _no_atime: bool, + ) -> Result { + let process = self.process.upgrade().ok_or(err!(Srch))?; + let thread = process.thread_group_leader().upgrade().ok_or(err!(Srch))?; + let stat = thread.lock().stat(); + let offset = cmp::min(offset, stat.len()); + let stat = &stat[offset..]; + let len = cmp::min(stat.len(), len); + vm.write_bytes(pointer.get(), &stat[..len])?; + Ok(len) + } + + fn write(&self, _offset: usize, _buf: &[u8]) -> Result { + bail!(Acces) + } + + fn write_from_user( + &self, + _offset: usize, + _vm: &VirtualMemory, + _pointer: Pointer<[u8]>, + _len: usize, + ) -> Result { + bail!(Acces) + } + + fn append(&self, _buf: &[u8]) -> Result { + bail!(Acces) + } + + fn append_from_user( + &self, + _vm: &VirtualMemory, + _pointer: Pointer<[u8]>, + _len: usize, + ) -> Result { + bail!(Acces) + } + + fn truncate(&self, _length: usize) -> Result<()> { + bail!(Acces) + } +} diff --git a/tee/kernel/src/user/process.rs b/tee/kernel/src/user/process.rs index 72325996..dbce1c46 100644 --- a/tee/kernel/src/user/process.rs +++ b/tee/kernel/src/user/process.rs @@ -14,6 +14,7 @@ use alloc::{ sync::{Arc, Weak}, vec::Vec, }; +use arrayvec::ArrayVec; use futures::{select_biased, FutureExt}; use limits::{CurrentStackLimit, Limits}; use syscall::args::{ClockId, Rusage, Timespec}; @@ -28,7 +29,7 @@ use crate::{ tmpfs::{TmpFs, TmpFsFile}, DynINode, FileAccessContext, INode, }, - path::Path, + path::{Path, PathSegment}, StaticFile, }, rt::{notify::Notify, once::OnceCell, oneshot, spawn}, @@ -59,8 +60,11 @@ pub mod syscall; pub mod thread; pub mod usage; +const TASK_COMM_CAPACITY: usize = 16; + pub struct Process { pid: u32, + start_time: Timespec, futexes: Arc, exit_status: OnceCell, parent: Weak, @@ -74,6 +78,7 @@ pub struct Process { running: AtomicUsize, pub inos: ProcessInos, exe: RwLock, + task_comm: Mutex>, alarm: Mutex>, stop_state: StopState, pub credentials: Mutex, @@ -99,8 +104,19 @@ impl Process { limits: Limits, umask: FileMode, ) -> Arc { + let PathSegment::FileName(last_path_segment) = exe.segments().last().unwrap() else { + unreachable!() + }; + let task_comm = last_path_segment + .as_bytes() + .iter() + .copied() + .take(TASK_COMM_CAPACITY) + .collect(); + let this = Self { pid: first_tid, + start_time: now(ClockId::Monotonic), futexes: Arc::new(Futexes::new()), exit_status: OnceCell::new(), parent: parent.clone(), @@ -113,6 +129,7 @@ impl Process { running: AtomicUsize::new(0), inos: ProcessInos::new(), exe: RwLock::new(exe), + task_comm: Mutex::new(task_comm), alarm: Mutex::new(None), stop_state: StopState::default(), credentials: Mutex::new(credentials), @@ -137,10 +154,26 @@ impl Process { self.pid } + pub fn ppid(&self) -> u32 { + self.parent.upgrade().map_or(1, |parent| parent.pid()) + } + + pub fn pgrp(&self) -> u32 { + self.process_group.lock().pgid + } + + pub fn sid(&self) -> u32 { + self.process_group.lock().session.lock().sid + } + pub fn exe(&self) -> Path { self.exe.read().clone() } + pub fn task_comm(&self) -> ArrayVec { + self.task_comm.lock().clone() + } + pub fn cwd(&self) -> DynINode { self.cwd.lock().clone() } diff --git a/tee/kernel/src/user/process/memory.rs b/tee/kernel/src/user/process/memory.rs index 483bc318..aec08625 100644 --- a/tee/kernel/src/user/process/memory.rs +++ b/tee/kernel/src/user/process/memory.rs @@ -24,7 +24,7 @@ use crate::{ }, user::process::syscall::args::Stat, }; -use alloc::{collections::BTreeMap, ffi::CString, format, sync::Arc, vec::Vec}; +use alloc::{collections::BTreeMap, ffi::CString, sync::Arc, vec::Vec}; use bitflags::bitflags; use log::debug; use usize_conversions::{usize_from, FromUsize}; @@ -323,8 +323,7 @@ impl VirtualMemory { let permissions = mapping.permissions; let offset = mapping.page_offset; let (major, minor, ino, path) = mapping.backing.location(); - let line= format!("{start:08x}-{end:08x} {permissions}p {offset:05x}000 {major:02x}:{minor:02x} {ino} "); - maps.extend_from_slice(line.as_bytes()); + write!(maps,"{start:08x}-{end:08x} {permissions}p {offset:05x}000 {major:02x}:{minor:02x} {ino} ").unwrap(); if let Some(path) = path { maps.extend_from_slice(path.as_bytes()); } @@ -336,6 +335,16 @@ impl VirtualMemory { pub fn usage(&self) -> &MemoryUsage { &self.usage } + + pub fn size(&self) -> usize { + self.state + .read() + .mappings + .values() + .map(|mapping| mapping.lock().pages.len()) + .sum::() + * 0x1000 + } } impl Default for VirtualMemory { @@ -1095,3 +1104,22 @@ impl Drop for SplitVec { } } } + +/// An extension trait for Vec that makes it possible to use the `write!()` +/// macro on it. +pub trait WriteToVec { + fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result; +} + +impl WriteToVec for Vec { + fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result { + struct WriteImpl<'a>(&'a mut Vec); + impl Write for WriteImpl<'_> { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.0.extend_from_slice(s.as_bytes()); + Ok(()) + } + } + core::fmt::write(&mut WriteImpl(self), args) + } +} diff --git a/tee/kernel/src/user/process/syscall.rs b/tee/kernel/src/user/process/syscall.rs index 5f514b22..6e70a813 100644 --- a/tee/kernel/src/user/process/syscall.rs +++ b/tee/kernel/src/user/process/syscall.rs @@ -2412,17 +2412,13 @@ fn setpgid(thread: &mut ThreadGuard, pid: u32, pgid: u32) -> SyscallResult { #[syscall(i386 = 64, amd64 = 110)] fn getppid(thread: &mut ThreadGuard) -> SyscallResult { - let ppid = thread - .process() - .parent - .upgrade() - .map_or(1, |parent| parent.pid); + let ppid = thread.process().ppid(); Ok(u64::from(ppid)) } #[syscall(i386 = 65, amd64 = 111)] fn getpgrp(thread: &mut ThreadGuard) -> SyscallResult { - let pgrp = thread.process().pid; + let pgrp = thread.process().pgrp(); Ok(u64::from(pgrp)) } diff --git a/tee/kernel/src/user/process/syscall/args.rs b/tee/kernel/src/user/process/syscall/args.rs index a85d2e13..d12d235e 100644 --- a/tee/kernel/src/user/process/syscall/args.rs +++ b/tee/kernel/src/user/process/syscall/args.rs @@ -919,6 +919,10 @@ impl Timespec { tv_nsec: 0, }) } + + pub fn kernel_ticks(&self) -> u64 { + u64::from(self.tv_sec) * 1_000_000 + u64::from(self.tv_nsec).div_ceil(1000) + } } impl Add for Timespec { @@ -954,6 +958,10 @@ impl Timeval { Self { tv_sec, tv_usec } } } + + pub fn kernel_ticks(&self) -> u64 { + u64::from(self.tv_sec) * 1_000_000 + u64::from(self.tv_usec) + } } impl From for Timespec { @@ -1409,6 +1417,10 @@ pub struct Nice(i8); impl Nice { pub const DEFAULT: Self = Self(0); + pub fn get(&self) -> i8 { + self.0 + } + pub fn as_syscall_return_value(self) -> u64 { (self.0 + 21) as u64 } diff --git a/tee/kernel/src/user/process/thread.rs b/tee/kernel/src/user/process/thread.rs index 15d44557..921ad9b7 100644 --- a/tee/kernel/src/user/process/thread.rs +++ b/tee/kernel/src/user/process/thread.rs @@ -29,6 +29,7 @@ use alloc::{ collections::VecDeque, string::String, sync::{Arc, Weak}, + vec::Vec, }; use bit_field::BitField; use bitflags::bitflags; @@ -46,7 +47,7 @@ use crate::{ use super::{ limits::{CurrentStackLimit, Limits}, - memory::VirtualMemory, + memory::{VirtualMemory, WriteToVec}, syscall::{ args::{FileMode, Nice, Pointer, Rusage, Signal, UserDesc, WStatus}, cpu_state::{CpuState, Exit, PageFaultExit}, @@ -672,6 +673,110 @@ impl ThreadGuard<'_> { pub fn get_rusage(&self) -> Rusage { usage::collect(self.virtual_memory.usage(), &self.thread.usage) } + + pub fn stat(&self) -> Vec { + let mut buffer = Vec::new(); + + write!(buffer, "{}", self.process().pid()).unwrap(); + + buffer.extend_from_slice(b" ("); + buffer.extend_from_slice(&self.process().task_comm()); + buffer.extend_from_slice(b")"); + + buffer.extend_from_slice(b" R"); // TODO: Don't always display the thread as running. + + write!(buffer, " {}", self.process().ppid()).unwrap(); + + write!(buffer, " {}", self.process().pgrp()).unwrap(); + + write!(buffer, " {}", self.process().sid()).unwrap(); + + buffer.extend_from_slice(b" 1"); // TODO: tty_nr + + write!(buffer, " {}", self.process().pgrp()).unwrap(); // TODO: tpgid + + buffer.extend_from_slice(b" 0"); // TODO: flags + + let rusage = self.get_rusage(); + let children_rusage = *self.process().children_usage.lock(); + write!(buffer, " {}", rusage.minflt).unwrap(); + write!(buffer, " {}", children_rusage.minflt).unwrap(); + write!(buffer, " {}", rusage.majflt).unwrap(); + write!(buffer, " {}", children_rusage.majflt).unwrap(); + write!(buffer, " {}", rusage.utime.kernel_ticks()).unwrap(); + write!(buffer, " {}", rusage.stime.kernel_ticks()).unwrap(); + write!(buffer, " {}", children_rusage.utime.kernel_ticks()).unwrap(); + write!(buffer, " {}", children_rusage.stime.kernel_ticks()).unwrap(); + + let nice = self.thread.nice.load(); + write!(buffer, " {}", nice.as_syscall_return_value()).unwrap(); + write!(buffer, " {}", nice.get()).unwrap(); + + write!(buffer, " {}", self.process().threads.lock().len()).unwrap(); + + buffer.extend_from_slice(b" 0"); // hard-coded to be 0. + + write!(buffer, " {}", self.process().start_time.kernel_ticks()).unwrap(); + + write!(buffer, " {}", self.virtual_memory().size()).unwrap(); + + let virtual_memory_usage = self.virtual_memory.usage(); + write!(buffer, " {}", virtual_memory_usage.rss()).unwrap(); + + buffer.extend_from_slice(b" 18446744073709551615"); // rsslim + + buffer.extend_from_slice(b" 0"); // TODO: startcode + buffer.extend_from_slice(b" 18446744073709551615"); // TODO: encode + + buffer.extend_from_slice(b" 0"); // TODO: startstack + buffer.extend_from_slice(b" 0"); // TODO: kstkesp + buffer.extend_from_slice(b" 0"); // TODO: kstkeip + + buffer.extend_from_slice(b" 0"); // TODO: signal + buffer.extend_from_slice(b" 0"); // TODO: blocked + buffer.extend_from_slice(b" 0"); // TODO: sigignore + buffer.extend_from_slice(b" 0"); // TODO: sigcatch + + buffer.extend_from_slice(b" 0"); // wchan + + buffer.extend_from_slice(b" 0"); // nswap + buffer.extend_from_slice(b" 0"); // cnswap + + write!( + buffer, + " {}", + self.process().termination_signal.map_or(0, |s| s.get()) + ) + .unwrap(); + + buffer.extend_from_slice(b" 0"); // processor + + buffer.extend_from_slice(b" 0"); // rt_priority + + buffer.extend_from_slice(b" 0"); // policy + + buffer.extend_from_slice(b" 0"); // delayacct_blkio_ticks + + buffer.extend_from_slice(b" 0"); // guest_time + buffer.extend_from_slice(b" 0"); // cguest_time + + buffer.extend_from_slice(b" 0"); // TODO: start_data + buffer.extend_from_slice(b" 18446744073709551615"); // TODO: end_data + + buffer.extend_from_slice(b" 0"); // TODO: start_brk + + buffer.extend_from_slice(b" 0"); // TODO: arg_start + buffer.extend_from_slice(b" 18446744073709551615"); // TODO: arg_end + + buffer.extend_from_slice(b" 0"); // TODO: env_start + buffer.extend_from_slice(b" 18446744073709551615"); // TODO: env_end + + buffer.extend_from_slice(b" 0"); // TODO: exit_code + + buffer.push(b'\n'); + + buffer + } } impl Deref for ThreadGuard<'_> { diff --git a/tee/kernel/src/user/process/usage.rs b/tee/kernel/src/user/process/usage.rs index 374490d7..6eb81cc4 100644 --- a/tee/kernel/src/user/process/usage.rs +++ b/tee/kernel/src/user/process/usage.rs @@ -24,9 +24,7 @@ impl MemoryUsage { rss: AtomicU64::new(rss), } } -} -impl MemoryUsage { pub fn record_minor_page_fault(&self) { self.minflt.fetch_add(1, Ordering::Relaxed); } @@ -44,6 +42,10 @@ impl MemoryUsage { self.rss .fetch_sub(u64::from_usize(delta), Ordering::Relaxed); } + + pub fn rss(&self) -> u64 { + self.rss.load(Ordering::Relaxed) + } } #[derive(Default)] From ca768556fbd5ca01dd54689f3c04b558e899217d Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Tue, 31 Dec 2024 11:57:21 +0000 Subject: [PATCH 2/3] implement /proc/stat --- tee/kernel/src/fs/node/procfs.rs | 182 ++++++++++++++++++++++++++++--- 1 file changed, 167 insertions(+), 15 deletions(-) diff --git a/tee/kernel/src/fs/node/procfs.rs b/tee/kernel/src/fs/node/procfs.rs index a5ddd45f..e5c7ffb2 100644 --- a/tee/kernel/src/fs/node/procfs.rs +++ b/tee/kernel/src/fs/node/procfs.rs @@ -8,6 +8,7 @@ use alloc::{ vec::Vec, }; use async_trait::async_trait; +use constants::MAX_APS_COUNT; use crate::{ error::{bail, ensure, err, ErrorKind, Result}, @@ -23,7 +24,7 @@ use crate::{ }, memory::page::KernelPage, user::process::{ - memory::VirtualMemory, + memory::{VirtualMemory, WriteToVec}, syscall::args::{ FdNum, FileMode, FileType, FileTypeAndMode, OpenFlags, Pointer, Stat, Timespec, }, @@ -69,10 +70,11 @@ pub fn new(location: MountLocation) -> Result { file_lock_record: LazyFileLockRecord::new(), self_link: Arc::new(SelfLink { parent: this.clone(), - fs, + fs: fs.clone(), ino: new_ino(), file_lock_record: LazyFileLockRecord::new(), }), + stat_file: StatFile::new(fs), })) } @@ -83,6 +85,7 @@ struct ProcFsRoot { location: MountLocation, file_lock_record: LazyFileLockRecord, self_link: Arc, + stat_file: Arc, } impl INode for ProcFsRoot { @@ -135,19 +138,24 @@ impl Directory for ProcFsRoot { } fn get_node(&self, file_name: &FileName, _ctx: &FileAccessContext) -> Result { - if file_name == "self" { - Ok(self.self_link.clone()) - } else { - let bytes = file_name.as_bytes(); - let str = core::str::from_utf8(bytes).map_err(|_| err!(NoEnt))?; - let pid = str.parse().map_err(|_| err!(NoEnt))?; - let process = Process::find_by_pid(pid).ok_or(err!(NoEnt))?; - Ok(ProcessDir::new( - StaticLocation::new(self.this.upgrade().unwrap(), file_name.clone().into_owned()), - self.fs.clone(), - Arc::downgrade(&process), - )) - } + Ok(match file_name.as_bytes() { + b"self" => self.self_link.clone(), + b"stat" => self.stat_file.clone(), + _ => { + let bytes = file_name.as_bytes(); + let str = core::str::from_utf8(bytes).map_err(|_| err!(NoEnt))?; + let pid = str.parse().map_err(|_| err!(NoEnt))?; + let process = Process::find_by_pid(pid).ok_or(err!(NoEnt))?; + ProcessDir::new( + StaticLocation::new( + self.this.upgrade().unwrap(), + file_name.clone().into_owned(), + ), + self.fs.clone(), + Arc::downgrade(&process), + ) + } + }) } fn create_file( @@ -215,6 +223,11 @@ impl Directory for ProcFsRoot { ty: FileType::Link, name: DirEntryName::FileName(FileName::new(b"self").unwrap()), }); + entries.push(DirEntry { + ino: self.stat_file.ino, + ty: FileType::File, + name: DirEntryName::FileName(FileName::new(b"stat").unwrap()), + }); entries.extend(Process::all().map(|process| { DirEntry { ino: process.inos.root_dir, @@ -1313,3 +1326,142 @@ impl File for ProcessStatFile { bail!(Acces) } } + +struct StatFile { + this: Weak, + fs: Arc, + ino: u64, + file_lock_record: LazyFileLockRecord, +} + +impl StatFile { + pub fn new(fs: Arc) -> Arc { + Arc::new_cyclic(|this| Self { + this: this.clone(), + fs, + ino: new_ino(), + file_lock_record: LazyFileLockRecord::new(), + }) + } + + fn content(&self) -> Vec { + let mut buffer = Vec::new(); + + // TODO: Don't hard-code values. + buffer + .extend_from_slice(b"cpu 10132153 290696 3084719 46828483 16683 0 25195 0 175628 0\n"); + for cpu in 0..MAX_APS_COUNT { + writeln!( + buffer, + "cpu{cpu} 10132153 290696 3084719 46828483 16683 0 25195 0 175628 0", + ) + .unwrap(); + } + + buffer + } +} + +impl INode for StatFile { + fn stat(&self) -> Result { + Ok(Stat { + dev: self.fs.dev, + ino: self.ino, + nlink: 1, + mode: FileTypeAndMode::new(FileType::File, FileMode::from_bits_retain(0o444)), + uid: Uid::SUPER_USER, + gid: Gid::SUPER_USER, + rdev: 0, + size: 0, + blksize: 0, + blocks: 0, + atime: Timespec::ZERO, + mtime: Timespec::ZERO, + ctime: Timespec::ZERO, + }) + } + + fn fs(&self) -> Result> { + Ok(self.fs.clone()) + } + + fn open(&self, path: Path, flags: OpenFlags) -> Result { + open_file(path, self.this.upgrade().unwrap(), flags) + } + + fn chmod(&self, _: FileMode, _: &FileAccessContext) -> Result<()> { + bail!(Perm) + } + + fn chown(&self, _: Uid, _: Gid, _: &FileAccessContext) -> Result<()> { + Ok(()) + } + + fn update_times(&self, _ctime: Timespec, _atime: Option, _mtime: Option) {} + + fn file_lock_record(&self) -> &Arc { + self.file_lock_record.get() + } +} + +impl File for StatFile { + fn get_page(&self, _page_idx: usize, _shared: bool) -> Result { + bail!(NoDev) + } + + fn read(&self, offset: usize, buf: &mut [u8], _no_atime: bool) -> Result { + let content = self.content(); + let offset = cmp::min(offset, content.len()); + let content = &content[offset..]; + let len = cmp::min(content.len(), buf.len()); + buf[..len].copy_from_slice(&content[..len]); + Ok(len) + } + + fn read_to_user( + &self, + offset: usize, + vm: &VirtualMemory, + pointer: Pointer<[u8]>, + len: usize, + _no_atime: bool, + ) -> Result { + let content = self.content(); + let offset = cmp::min(offset, content.len()); + let content = &content[offset..]; + let len = cmp::min(content.len(), len); + vm.write_bytes(pointer.get(), &content[..len])?; + Ok(len) + } + + fn write(&self, _offset: usize, _buf: &[u8]) -> Result { + bail!(Acces) + } + + fn write_from_user( + &self, + _offset: usize, + _vm: &VirtualMemory, + _pointer: Pointer<[u8]>, + _len: usize, + ) -> Result { + bail!(Acces) + } + + fn append(&self, _buf: &[u8]) -> Result { + bail!(Acces) + } + + fn append_from_user( + &self, + _vm: &VirtualMemory, + _pointer: Pointer<[u8]>, + _len: usize, + ) -> Result { + bail!(Acces) + } + + fn truncate(&self, _length: usize) -> Result<()> { + bail!(Acces) + } +} From 5ce02878d3cc598e91a953ce87ecbf203f7bdf5b Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Tue, 31 Dec 2024 11:59:14 +0000 Subject: [PATCH 3/3] implement /proc/uptime --- tee/kernel/src/fs/node/procfs.rs | 161 ++++++++++++++++++++++++++++++- 1 file changed, 159 insertions(+), 2 deletions(-) diff --git a/tee/kernel/src/fs/node/procfs.rs b/tee/kernel/src/fs/node/procfs.rs index e5c7ffb2..47bea357 100644 --- a/tee/kernel/src/fs/node/procfs.rs +++ b/tee/kernel/src/fs/node/procfs.rs @@ -23,10 +23,11 @@ use crate::{ FileSystem, StatFs, }, memory::page::KernelPage, + time::now, user::process::{ memory::{VirtualMemory, WriteToVec}, syscall::args::{ - FdNum, FileMode, FileType, FileTypeAndMode, OpenFlags, Pointer, Stat, Timespec, + ClockId, FdNum, FileMode, FileType, FileTypeAndMode, OpenFlags, Pointer, Stat, Timespec, }, thread::{Gid, Uid}, Process, @@ -74,7 +75,8 @@ pub fn new(location: MountLocation) -> Result { ino: new_ino(), file_lock_record: LazyFileLockRecord::new(), }), - stat_file: StatFile::new(fs), + stat_file: StatFile::new(fs.clone()), + uptime_file: UptimeFile::new(fs), })) } @@ -86,6 +88,7 @@ struct ProcFsRoot { file_lock_record: LazyFileLockRecord, self_link: Arc, stat_file: Arc, + uptime_file: Arc, } impl INode for ProcFsRoot { @@ -141,6 +144,7 @@ impl Directory for ProcFsRoot { Ok(match file_name.as_bytes() { b"self" => self.self_link.clone(), b"stat" => self.stat_file.clone(), + b"uptime" => self.uptime_file.clone(), _ => { let bytes = file_name.as_bytes(); let str = core::str::from_utf8(bytes).map_err(|_| err!(NoEnt))?; @@ -228,6 +232,11 @@ impl Directory for ProcFsRoot { ty: FileType::File, name: DirEntryName::FileName(FileName::new(b"stat").unwrap()), }); + entries.push(DirEntry { + ino: self.uptime_file.ino, + ty: FileType::File, + name: DirEntryName::FileName(FileName::new(b"uptime").unwrap()), + }); entries.extend(Process::all().map(|process| { DirEntry { ino: process.inos.root_dir, @@ -1465,3 +1474,151 @@ impl File for StatFile { bail!(Acces) } } + +struct UptimeFile { + this: Weak, + fs: Arc, + ino: u64, + file_lock_record: LazyFileLockRecord, +} + +impl UptimeFile { + pub fn new(fs: Arc) -> Arc { + Arc::new_cyclic(|this| Self { + this: this.clone(), + fs, + ino: new_ino(), + file_lock_record: LazyFileLockRecord::new(), + }) + } + + fn content(&self) -> Vec { + let mut buffer = Vec::new(); + + let uptime = now(ClockId::Monotonic); + // TODO: We currently don't track the idle time, so we just multiple + // the uptime by 3. + let idle_time = uptime.saturating_add(uptime).saturating_add(uptime); + + write!( + buffer, + "{}.{:02}", + uptime.tv_sec, + uptime.tv_nsec / 10_000_000 + ) + .unwrap(); + write!( + buffer, + "{}.{:02}", + idle_time.tv_sec, + idle_time.tv_nsec / 10_000_000 + ) + .unwrap(); + + buffer + } +} + +impl INode for UptimeFile { + fn stat(&self) -> Result { + Ok(Stat { + dev: self.fs.dev, + ino: self.ino, + nlink: 1, + mode: FileTypeAndMode::new(FileType::File, FileMode::from_bits_retain(0o444)), + uid: Uid::SUPER_USER, + gid: Gid::SUPER_USER, + rdev: 0, + size: 0, + blksize: 0, + blocks: 0, + atime: Timespec::ZERO, + mtime: Timespec::ZERO, + ctime: Timespec::ZERO, + }) + } + + fn fs(&self) -> Result> { + Ok(self.fs.clone()) + } + + fn open(&self, path: Path, flags: OpenFlags) -> Result { + open_file(path, self.this.upgrade().unwrap(), flags) + } + + fn chmod(&self, _: FileMode, _: &FileAccessContext) -> Result<()> { + bail!(Perm) + } + + fn chown(&self, _: Uid, _: Gid, _: &FileAccessContext) -> Result<()> { + Ok(()) + } + + fn update_times(&self, _ctime: Timespec, _atime: Option, _mtime: Option) {} + + fn file_lock_record(&self) -> &Arc { + self.file_lock_record.get() + } +} + +impl File for UptimeFile { + fn get_page(&self, _page_idx: usize, _shared: bool) -> Result { + bail!(NoDev) + } + + fn read(&self, offset: usize, buf: &mut [u8], _no_atime: bool) -> Result { + let content = self.content(); + let offset = cmp::min(offset, content.len()); + let content = &content[offset..]; + let len = cmp::min(content.len(), buf.len()); + buf[..len].copy_from_slice(&content[..len]); + Ok(len) + } + + fn read_to_user( + &self, + offset: usize, + vm: &VirtualMemory, + pointer: Pointer<[u8]>, + len: usize, + _no_atime: bool, + ) -> Result { + let content = self.content(); + let offset = cmp::min(offset, content.len()); + let content = &content[offset..]; + let len = cmp::min(content.len(), len); + vm.write_bytes(pointer.get(), &content[..len])?; + Ok(len) + } + + fn write(&self, _offset: usize, _buf: &[u8]) -> Result { + bail!(Acces) + } + + fn write_from_user( + &self, + _offset: usize, + _vm: &VirtualMemory, + _pointer: Pointer<[u8]>, + _len: usize, + ) -> Result { + bail!(Acces) + } + + fn append(&self, _buf: &[u8]) -> Result { + bail!(Acces) + } + + fn append_from_user( + &self, + _vm: &VirtualMemory, + _pointer: Pointer<[u8]>, + _len: usize, + ) -> Result { + bail!(Acces) + } + + fn truncate(&self, _length: usize) -> Result<()> { + bail!(Acces) + } +}