feat(cred): 初步实现Cred (#846)

* 初步实现Cred

* 添加seteuid和setegid

* 添加cred测试程序

* 修改Cred::fscmp返回结果为CredFsCmp枚举

* 完善root用户相关信息
This commit is contained in:
Jomo
2024-08-02 09:42:34 +08:00
committed by GitHub
parent 703ce5a77c
commit 0648a547da
13 changed files with 405 additions and 24 deletions

View File

@ -20,7 +20,7 @@ use crate::{
event_poll::{EPollItem, EPollPrivateData, EventPoll},
socket::SocketInode,
},
process::ProcessManager,
process::{cred::Cred, ProcessManager},
};
use super::{Dirent, FileType, IndexNode, InodeId, Metadata, SpecialNodeData};
@ -131,6 +131,8 @@ pub struct File {
/// readdir时候用的暂存的本次循环中所有子目录项的名字的数组
readdir_subdirs_name: SpinLock<Vec<String>>,
pub private_data: SpinLock<FilePrivateData>,
/// 文件的凭证
cred: Cred,
}
impl File {
@ -154,6 +156,7 @@ impl File {
file_type,
readdir_subdirs_name: SpinLock::new(Vec::default()),
private_data: SpinLock::new(FilePrivateData::default()),
cred: ProcessManager::current_pcb().cred(),
};
f.inode.open(f.private_data.lock(), &mode)?;
@ -408,6 +411,7 @@ impl File {
file_type: self.file_type,
readdir_subdirs_name: SpinLock::new(self.readdir_subdirs_name.lock().clone()),
private_data: SpinLock::new(self.private_data.lock().clone()),
cred: self.cred.clone(),
};
// 调用inode的open方法让inode知道有新的文件打开了这个inode
if self

170
kernel/src/process/cred.rs Normal file
View File

@ -0,0 +1,170 @@
use core::sync::atomic::AtomicUsize;
use alloc::vec::Vec;
const GLOBAL_ROOT_UID: Kuid = Kuid(0);
const GLOBAL_ROOT_GID: Kgid = Kgid(0);
pub static INIT_CRED: Cred = Cred::init();
int_like!(Kuid, AtomicKuid, usize, AtomicUsize);
int_like!(Kgid, AtomicKgid, usize, AtomicUsize);
bitflags! {
pub struct CAPFlags:u64{
const CAP_EMPTY_SET = 0;
const CAP_FULL_SET = (1 << 41) - 1;
}
}
pub enum CredFsCmp {
Equal,
Less,
Greater,
}
/// 凭证集
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Cred {
/// 进程实际uid
pub uid: Kuid,
/// 进程实际gid
pub gid: Kgid,
/// 进程保存的uid
pub suid: Kuid,
/// 进程保存的gid
pub sgid: Kgid,
/// 进程有效的uid
pub euid: Kuid,
/// 进程有效的gid
pub egid: Kgid,
/// UID for VFS ops
pub fsuid: Kuid,
/// GID for VFS ops
pub fsgid: Kgid,
/// 子进程可以继承的权限
pub cap_inheritable: CAPFlags,
/// 当前进程被赋予的权限
pub cap_permitted: CAPFlags,
/// 当前进程实际使用的权限
pub cap_effective: CAPFlags,
/// capability bounding set
pub cap_bset: CAPFlags,
/// Ambient capability set
pub cap_ambient: CAPFlags,
/// supplementary groups for euid/fsgid
pub group_info: Option<GroupInfo>,
}
impl Cred {
pub const fn init() -> Self {
Self {
uid: GLOBAL_ROOT_UID,
gid: GLOBAL_ROOT_GID,
suid: GLOBAL_ROOT_UID,
sgid: GLOBAL_ROOT_GID,
euid: GLOBAL_ROOT_UID,
egid: GLOBAL_ROOT_GID,
fsuid: GLOBAL_ROOT_UID,
fsgid: GLOBAL_ROOT_GID,
cap_inheritable: CAPFlags::CAP_EMPTY_SET,
cap_permitted: CAPFlags::CAP_FULL_SET,
cap_effective: CAPFlags::CAP_FULL_SET,
cap_bset: CAPFlags::CAP_FULL_SET,
cap_ambient: CAPFlags::CAP_FULL_SET,
group_info: None,
}
}
#[allow(dead_code)]
/// Compare two credentials with respect to filesystem access.
pub fn fscmp(&self, other: Cred) -> CredFsCmp {
if *self == other {
return CredFsCmp::Equal;
}
if self.fsuid < other.fsuid {
return CredFsCmp::Less;
}
if self.fsuid > other.fsuid {
return CredFsCmp::Greater;
}
if self.fsgid < other.fsgid {
return CredFsCmp::Less;
}
if self.fsgid > other.fsgid {
return CredFsCmp::Greater;
}
if self.group_info == other.group_info {
return CredFsCmp::Equal;
}
if let (Some(ga), Some(gb)) = (&self.group_info, &other.group_info) {
let ga_count = ga.gids.len();
let gb_count = gb.gids.len();
if ga_count < gb_count {
return CredFsCmp::Less;
}
if ga_count > gb_count {
return CredFsCmp::Greater;
}
for i in 0..ga_count {
if ga.gids[i] < gb.gids[i] {
return CredFsCmp::Less;
}
if ga.gids[i] > gb.gids[i] {
return CredFsCmp::Greater;
}
}
} else {
if self.group_info.is_none() {
return CredFsCmp::Less;
}
if other.group_info.is_none() {
return CredFsCmp::Greater;
}
}
return CredFsCmp::Equal;
}
pub fn setuid(&mut self, uid: usize) {
self.uid.0 = uid;
}
pub fn seteuid(&mut self, euid: usize) {
self.euid.0 = euid;
}
pub fn setsuid(&mut self, suid: usize) {
self.suid.0 = suid;
}
pub fn setfsuid(&mut self, fsuid: usize) {
self.fsuid.0 = fsuid;
}
pub fn setgid(&mut self, gid: usize) {
self.gid.0 = gid;
}
pub fn setegid(&mut self, egid: usize) {
self.egid.0 = egid;
}
pub fn setsgid(&mut self, sgid: usize) {
self.sgid.0 = sgid;
}
pub fn setfsgid(&mut self, fsgid: usize) {
self.fsgid.0 = fsgid;
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct GroupInfo {
pub gids: Vec<Kgid>,
}

View File

@ -13,6 +13,7 @@ use alloc::{
sync::{Arc, Weak},
vec::Vec,
};
use cred::INIT_CRED;
use hashbrown::HashMap;
use log::{debug, error, info, warn};
use system_error::SystemError;
@ -64,10 +65,11 @@ use crate::{
};
use timer::AlarmTimer;
use self::kthread::WorkerPrivate;
use self::{cred::Cred, kthread::WorkerPrivate};
pub mod abi;
pub mod c_adapter;
pub mod cred;
pub mod exec;
pub mod exit;
pub mod fork;
@ -649,6 +651,9 @@ pub struct ProcessControlBlock {
/// 进程的robust lock列表
robust_list: RwLock<Option<RobustListHead>>,
/// 进程作为主体的凭证集
cred: SpinLock<Cred>,
}
impl ProcessControlBlock {
@ -687,12 +692,16 @@ impl ProcessControlBlock {
#[inline(never)]
fn do_create_pcb(name: String, kstack: KernelStack, is_idle: bool) -> Arc<Self> {
let (pid, ppid, cwd) = if is_idle {
(Pid(0), Pid(0), "/".to_string())
let (pid, ppid, cwd, cred) = if is_idle {
let cred = INIT_CRED.clone();
(Pid(0), Pid(0), "/".to_string(), cred)
} else {
let ppid = ProcessManager::current_pcb().pid();
let mut cred = ProcessManager::current_pcb().cred();
cred.cap_permitted = cred.cap_ambient;
cred.cap_effective = cred.cap_ambient;
let cwd = ProcessManager::current_pcb().basic().cwd();
(Self::generate_pid(), ppid, cwd)
(Self::generate_pid(), ppid, cwd, cred)
};
let basic_info = ProcessBasicInfo::new(Pid(0), ppid, name, cwd, None);
@ -727,6 +736,7 @@ impl ProcessControlBlock {
thread: RwLock::new(ThreadInfo::new()),
alarm_timer: SpinLock::new(None),
robust_list: RwLock::new(None),
cred: SpinLock::new(cred),
};
// 初始化系统调用栈
@ -879,6 +889,11 @@ impl ProcessControlBlock {
return self.basic.read().fd_table().unwrap();
}
#[inline(always)]
pub fn cred(&self) -> Cred {
self.cred.lock().clone()
}
/// 根据文件描述符序号获取socket对象的Arc指针
///
/// ## 参数

View File

@ -6,6 +6,7 @@ use system_error::SystemError;
use super::{
abi::WaitOption,
cred::{Kgid, Kuid},
exit::kernel_wait4,
fork::{CloneFlags, KernelCloneArgs},
resource::{RLimit64, RLimitID, RUsage, RUsageWho},
@ -286,25 +287,125 @@ impl Syscall {
}
pub fn getuid() -> Result<usize, SystemError> {
// todo: 增加credit功能之后需要修改
return Ok(0);
let pcb = ProcessManager::current_pcb();
return Ok(pcb.cred.lock().uid.data());
}
pub fn getgid() -> Result<usize, SystemError> {
// todo: 增加credit功能之后需要修改
return Ok(0);
let pcb = ProcessManager::current_pcb();
return Ok(pcb.cred.lock().gid.data());
}
pub fn geteuid() -> Result<usize, SystemError> {
// todo: 增加credit功能之后需要修改
return Ok(0);
let pcb = ProcessManager::current_pcb();
return Ok(pcb.cred.lock().euid.data());
}
pub fn getegid() -> Result<usize, SystemError> {
// todo: 增加credit功能之后需要修改
let pcb = ProcessManager::current_pcb();
return Ok(pcb.cred.lock().egid.data());
}
pub fn setuid(uid: usize) -> Result<usize, SystemError> {
let pcb = ProcessManager::current_pcb();
let mut guard = pcb.cred.lock();
if guard.uid.data() == 0 {
guard.setuid(uid);
guard.seteuid(uid);
guard.setsuid(uid);
} else if uid == guard.uid.data() || uid == guard.suid.data() {
guard.seteuid(uid);
} else {
return Err(SystemError::EPERM);
}
return Ok(0);
}
pub fn setgid(gid: usize) -> Result<usize, SystemError> {
let pcb = ProcessManager::current_pcb();
let mut guard = pcb.cred.lock();
if guard.egid.data() == 0 {
guard.setgid(gid);
guard.setegid(gid);
guard.setsgid(gid);
guard.setfsgid(gid);
} else if guard.gid.data() == gid || guard.sgid.data() == gid {
guard.setegid(gid);
guard.setfsgid(gid);
} else {
return Err(SystemError::EPERM);
}
return Ok(0);
}
pub fn seteuid(euid: usize) -> Result<usize, SystemError> {
let pcb = ProcessManager::current_pcb();
let mut guard = pcb.cred.lock();
if euid == usize::MAX || (euid == guard.euid.data() && euid == guard.fsuid.data()) {
return Ok(0);
}
if euid != usize::MAX {
guard.seteuid(euid);
}
let euid = guard.euid.data();
guard.setfsuid(euid);
return Ok(0);
}
pub fn setegid(egid: usize) -> Result<usize, SystemError> {
let pcb = ProcessManager::current_pcb();
let mut guard = pcb.cred.lock();
if egid == usize::MAX || (egid == guard.egid.data() && egid == guard.fsgid.data()) {
return Ok(0);
}
if egid != usize::MAX {
guard.setegid(egid);
}
let egid = guard.egid.data();
guard.setfsgid(egid);
return Ok(0);
}
pub fn setfsuid(fsuid: usize) -> Result<usize, SystemError> {
let fsuid = Kuid::new(fsuid);
let pcb = ProcessManager::current_pcb();
let mut guard = pcb.cred.lock();
let old_fsuid = guard.fsuid;
if fsuid == guard.uid || fsuid == guard.euid || fsuid == guard.suid {
guard.setfsuid(fsuid.data());
}
Ok(old_fsuid.data())
}
pub fn setfsgid(fsgid: usize) -> Result<usize, SystemError> {
let fsgid = Kgid::new(fsgid);
let pcb = ProcessManager::current_pcb();
let mut guard = pcb.cred.lock();
let old_fsgid = guard.fsgid;
if fsgid == guard.gid || fsgid == guard.egid || fsgid == guard.sgid {
guard.setfsgid(fsgid.data());
}
Ok(old_fsgid.data())
}
pub fn get_rusage(who: i32, rusage: *mut RUsage) -> Result<usize, SystemError> {
let who = RUsageWho::try_from(who)?;
let mut writer = UserBufferWriter::new(rusage, core::mem::size_of::<RUsage>(), true)?;

View File

@ -875,7 +875,6 @@ impl Syscall {
}
SYS_GETTID => Self::gettid().map(|tid| tid.into()),
SYS_GETUID => Self::getuid(),
SYS_SYSLOG => {
let syslog_action_type = args[0];
@ -889,27 +888,29 @@ impl Syscall {
Self::do_syslog(syslog_action_type, user_buf, len)
}
SYS_GETUID => Self::getuid(),
SYS_GETGID => Self::getgid(),
SYS_SETUID => {
warn!("SYS_SETUID has not yet been implemented");
Ok(0)
}
SYS_SETGID => {
warn!("SYS_SETGID has not yet been implemented");
Ok(0)
}
SYS_SETUID => Self::setuid(args[0]),
SYS_SETGID => Self::setgid(args[0]),
SYS_GETEUID => Self::geteuid(),
SYS_GETEGID => Self::getegid(),
SYS_SETRESUID => Self::seteuid(args[1]),
SYS_SETRESGID => Self::setegid(args[1]),
SYS_SETFSUID => Self::setfsuid(args[0]),
SYS_SETFSGID => Self::setfsgid(args[0]),
SYS_SETSID => {
warn!("SYS_SETSID has not yet been implemented");
Ok(0)
}
SYS_GETEUID => Self::geteuid(),
SYS_GETEGID => Self::getegid(),
SYS_GETRUSAGE => {
let who = args[0] as c_int;
let rusage = args[1] as *mut RUsage;
Self::get_rusage(who, rusage)
}
#[cfg(target_arch = "x86_64")]
SYS_READLINK => {
let path = args[0] as *const u8;