mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-16 14:06:48 +00:00
* feat: debug kernel stack Signed-off-by: Godones <chenlinfeng25@outlook.com> * fix: Create guard pages for the kstack through remap Signed-off-by: Godones <chenlinfeng25@outlook.com> * feat(arch/x86_64): 启用内核态写保护功能 添加enable_kernel_wp函数来设置CR0的WP位,防止内核错误写入只读页面 Signed-off-by: longjin <longjin@DragonOS.org> * fix(x86_64/mm): 在内核地址错误处理中添加RIP寄存器信息 Signed-off-by: longjin <longjin@DragonOS.org> * fix: Fixed the error introduced by enabling WP flag on x86 Restore accidentally deleted functions. Signed-off-by: Godones <chenlinfeng25@outlook.com> * refactor: 移除kstack_protect默认特性并优化内存管理 - 从default特性中移除kstack_protect - 为X86_64MMBootstrapInfo添加kernel_rodata_start字段 - 调整内核页标志对rodata区域的判断逻辑 Signed-off-by: longjin <longjin@DragonOS.org> * fix(mm): 解决加载二进制文件到用户空间的时候,忘记关闭wp的问题 Signed-off-by: longjin <longjin@DragonOS.org> * fix Signed-off-by: longjin <longjin@DragonOS.org> --------- Signed-off-by: Godones <chenlinfeng25@outlook.com> Signed-off-by: longjin <longjin@DragonOS.org> Co-authored-by: longjin <longjin@DragonOS.org>
365 lines
11 KiB
Rust
365 lines
11 KiB
Rust
//! 这个文件用于放置一些内核态访问用户态数据的函数
|
||
|
||
use core::{
|
||
mem::size_of,
|
||
num::NonZero,
|
||
slice::{from_raw_parts, from_raw_parts_mut},
|
||
};
|
||
|
||
use alloc::{ffi::CString, vec::Vec};
|
||
use defer::defer;
|
||
|
||
use crate::{
|
||
arch::MMArch,
|
||
mm::{verify_area, MemoryManagementArch, VirtAddr},
|
||
};
|
||
|
||
use super::SystemError;
|
||
|
||
/// 清空用户空间指定范围内的数据
|
||
///
|
||
/// ## 参数
|
||
///
|
||
/// - `dest`:用户空间的目标地址
|
||
/// - `len`:要清空的数据长度
|
||
///
|
||
/// ## 返回值
|
||
///
|
||
/// 返回清空的数据长度
|
||
///
|
||
/// ## 错误
|
||
///
|
||
/// - `EFAULT`:目标地址不合法
|
||
pub unsafe fn clear_user(dest: VirtAddr, len: usize) -> Result<usize, SystemError> {
|
||
verify_area(dest, len).map_err(|_| SystemError::EFAULT)?;
|
||
|
||
let p = dest.data() as *mut u8;
|
||
// 清空用户空间的数据
|
||
p.write_bytes(0, len);
|
||
return Ok(len);
|
||
}
|
||
|
||
pub unsafe fn copy_to_user(dest: VirtAddr, src: &[u8]) -> Result<usize, SystemError> {
|
||
verify_area(dest, src.len()).map_err(|_| SystemError::EFAULT)?;
|
||
MMArch::disable_kernel_wp();
|
||
defer!({
|
||
MMArch::enable_kernel_wp();
|
||
});
|
||
|
||
let p = dest.data() as *mut u8;
|
||
// 拷贝数据
|
||
p.copy_from_nonoverlapping(src.as_ptr(), src.len());
|
||
return Ok(src.len());
|
||
}
|
||
|
||
/// 从用户空间拷贝数据到内核空间
|
||
pub unsafe fn copy_from_user(dst: &mut [u8], src: VirtAddr) -> Result<usize, SystemError> {
|
||
verify_area(src, dst.len()).map_err(|_| SystemError::EFAULT)?;
|
||
|
||
let src: &[u8] = core::slice::from_raw_parts(src.data() as *const u8, dst.len());
|
||
// 拷贝数据
|
||
dst.copy_from_slice(src);
|
||
|
||
return Ok(dst.len());
|
||
}
|
||
|
||
/// 检查并从用户态拷贝一个 C 字符串。
|
||
///
|
||
/// 一旦遇到非法地址,就会返回错误
|
||
///
|
||
/// ## 参数
|
||
///
|
||
/// - `user`:用户态的 C 字符串指针
|
||
/// - `max_length`:最大拷贝长度
|
||
///
|
||
/// ## 返回值
|
||
///
|
||
/// 返回拷贝的 C 字符串
|
||
///
|
||
/// ## 错误
|
||
///
|
||
/// - `EFAULT`:用户态地址不合法
|
||
/// - `EINVAL`:字符串不是合法的 C 字符串
|
||
pub fn check_and_clone_cstr(
|
||
user: *const u8,
|
||
max_length: Option<usize>,
|
||
) -> Result<CString, SystemError> {
|
||
if user.is_null() {
|
||
return Err(SystemError::EFAULT);
|
||
}
|
||
|
||
// 从用户态读取,直到遇到空字符 '\0' 或者达到最大长度
|
||
let mut buffer = Vec::new();
|
||
for i in 0.. {
|
||
if max_length.is_some() && max_length.as_ref().unwrap() <= &i {
|
||
break;
|
||
}
|
||
|
||
let addr = unsafe { user.add(i) };
|
||
let mut c = [0u8; 1];
|
||
unsafe {
|
||
copy_from_user(&mut c, VirtAddr::new(addr as usize))?;
|
||
}
|
||
if c[0] == 0 {
|
||
break;
|
||
}
|
||
buffer.push(NonZero::new(c[0]).ok_or(SystemError::EINVAL)?);
|
||
}
|
||
|
||
let cstr = CString::from(buffer);
|
||
|
||
return Ok(cstr);
|
||
}
|
||
|
||
/// 检查并从用户态拷贝一个 C 字符串数组
|
||
///
|
||
/// 一旦遇到空指针,就会停止拷贝. 一旦遇到非法地址,就会返回错误
|
||
/// ## 参数
|
||
///
|
||
/// - `user`:用户态的 C 字符串指针数组
|
||
///
|
||
/// ## 返回值
|
||
///
|
||
/// 返回拷贝的 C 字符串数组
|
||
///
|
||
/// ## 错误
|
||
///
|
||
/// - `EFAULT`:用户态地址不合法
|
||
pub fn check_and_clone_cstr_array(user: *const *const u8) -> Result<Vec<CString>, SystemError> {
|
||
if user.is_null() {
|
||
Ok(Vec::new())
|
||
} else {
|
||
// debug!("check_and_clone_cstr_array: {:p}\n", user);
|
||
let mut buffer = Vec::new();
|
||
for i in 0.. {
|
||
let addr = unsafe { user.add(i) };
|
||
let str_ptr: *const u8;
|
||
// 读取这个地址的值(这个值也是一个指针)
|
||
unsafe {
|
||
let dst = [0usize; 1];
|
||
let mut dst = core::mem::transmute::<[usize; 1], [u8; size_of::<usize>()]>(dst);
|
||
copy_from_user(&mut dst, VirtAddr::new(addr as usize))?;
|
||
let dst = core::mem::transmute::<[u8; size_of::<usize>()], [usize; 1]>(dst);
|
||
str_ptr = dst[0] as *const u8;
|
||
|
||
// debug!("str_ptr: {:p}, addr:{addr:?}\n", str_ptr);
|
||
}
|
||
|
||
if str_ptr.is_null() {
|
||
break;
|
||
}
|
||
// 读取这个指针指向的字符串
|
||
let string = check_and_clone_cstr(str_ptr, None)?;
|
||
// 将字符串放入 buffer 中
|
||
buffer.push(string);
|
||
}
|
||
return Ok(buffer);
|
||
}
|
||
}
|
||
|
||
#[derive(Debug)]
|
||
pub struct UserBufferWriter<'a> {
|
||
buffer: &'a mut [u8],
|
||
}
|
||
|
||
#[derive(Debug)]
|
||
pub struct UserBufferReader<'a> {
|
||
buffer: &'a [u8],
|
||
}
|
||
|
||
#[allow(dead_code)]
|
||
impl UserBufferReader<'_> {
|
||
/// 构造一个指向用户空间位置的BufferReader,为了兼容类似传入 *const u8 的情况,使用单独的泛型来进行初始化
|
||
///
|
||
/// @param addr 用户空间指针
|
||
/// @param len 缓冲区的字节长度
|
||
/// @param frm_user 代表是否要检验地址来自用户空间
|
||
/// @return 构造成功返回UserbufferReader实例,否则返回错误码
|
||
///
|
||
pub fn new<U>(addr: *const U, len: usize, from_user: bool) -> Result<Self, SystemError> {
|
||
if from_user && verify_area(VirtAddr::new(addr as usize), len).is_err() {
|
||
return Err(SystemError::EFAULT);
|
||
}
|
||
return Ok(Self {
|
||
buffer: unsafe { core::slice::from_raw_parts(addr as *const u8, len) },
|
||
});
|
||
}
|
||
|
||
pub fn size(&self) -> usize {
|
||
return self.buffer.len();
|
||
}
|
||
|
||
/// 从用户空间读取数据(到变量中)
|
||
///
|
||
/// @param offset 字节偏移量
|
||
/// @return 返回用户空间数据的切片(对单个结构体就返回长度为一的切片)
|
||
///
|
||
pub fn read_from_user<T>(&self, offset: usize) -> Result<&[T], SystemError> {
|
||
return self.convert_with_offset(self.buffer, offset);
|
||
}
|
||
/// 从用户空间读取一个指定偏移量的数据(到变量中)
|
||
///
|
||
/// @param offset 字节偏移量
|
||
/// @return 返回用户空间数据的引用
|
||
///
|
||
pub fn read_one_from_user<T>(&self, offset: usize) -> Result<&T, SystemError> {
|
||
return self.convert_one_with_offset(self.buffer, offset);
|
||
}
|
||
|
||
/// 从用户空间拷贝数据(到指定地址中)
|
||
///
|
||
/// @param dst 目标地址指针
|
||
/// @return 拷贝成功的话返回拷贝的元素数量
|
||
///
|
||
pub fn copy_from_user<T: core::marker::Copy>(
|
||
&self,
|
||
dst: &mut [T],
|
||
offset: usize,
|
||
) -> Result<usize, SystemError> {
|
||
let data = self.convert_with_offset(self.buffer, offset)?;
|
||
dst.copy_from_slice(data);
|
||
return Ok(dst.len());
|
||
}
|
||
|
||
/// 从用户空间拷贝数据(到指定地址中)
|
||
///
|
||
/// @param dst 目标地址指针
|
||
/// @return 拷贝成功的话返回拷贝的元素数量
|
||
///
|
||
pub fn copy_one_from_user<T: core::marker::Copy>(
|
||
&self,
|
||
dst: &mut T,
|
||
offset: usize,
|
||
) -> Result<(), SystemError> {
|
||
let data = self.convert_one_with_offset::<T>(self.buffer, offset)?;
|
||
dst.clone_from(data);
|
||
return Ok(());
|
||
}
|
||
|
||
/// 把用户空间的数据转换成指定类型的切片
|
||
///
|
||
/// ## 参数
|
||
///
|
||
/// - `offset`:字节偏移量
|
||
pub fn buffer<T>(&self, offset: usize) -> Result<&[T], SystemError> {
|
||
self.convert_with_offset::<T>(self.buffer, offset)
|
||
.map_err(|_| SystemError::EINVAL)
|
||
}
|
||
|
||
fn convert_with_offset<T>(&self, src: &[u8], offset: usize) -> Result<&[T], SystemError> {
|
||
if offset >= src.len() {
|
||
return Err(SystemError::EINVAL);
|
||
}
|
||
let byte_buffer: &[u8] = &src[offset..];
|
||
if byte_buffer.len() % core::mem::size_of::<T>() != 0 || byte_buffer.is_empty() {
|
||
return Err(SystemError::EINVAL);
|
||
}
|
||
|
||
let chunks = unsafe {
|
||
from_raw_parts(
|
||
byte_buffer.as_ptr() as *const T,
|
||
byte_buffer.len() / core::mem::size_of::<T>(),
|
||
)
|
||
};
|
||
return Ok(chunks);
|
||
}
|
||
|
||
fn convert_one_with_offset<T>(&self, src: &[u8], offset: usize) -> Result<&T, SystemError> {
|
||
if offset + core::mem::size_of::<T>() > src.len() {
|
||
return Err(SystemError::EINVAL);
|
||
}
|
||
let byte_buffer: &[u8] = &src[offset..offset + core::mem::size_of::<T>()];
|
||
|
||
let chunks = unsafe { from_raw_parts(byte_buffer.as_ptr() as *const T, 1) };
|
||
let data = &chunks[0];
|
||
return Ok(data);
|
||
}
|
||
}
|
||
|
||
#[allow(dead_code)]
|
||
impl<'a> UserBufferWriter<'a> {
|
||
/// 构造一个指向用户空间位置的BufferWriter
|
||
///
|
||
/// @param addr 用户空间指针
|
||
/// @param len 缓冲区的字节长度
|
||
/// @return 构造成功返回UserbufferWriter实例,否则返回错误码
|
||
///
|
||
pub fn new<U>(addr: *mut U, len: usize, from_user: bool) -> Result<Self, SystemError> {
|
||
if from_user && verify_area(VirtAddr::new(addr as usize), len).is_err() {
|
||
return Err(SystemError::EFAULT);
|
||
}
|
||
return Ok(Self {
|
||
buffer: unsafe { core::slice::from_raw_parts_mut(addr as *mut u8, len) },
|
||
});
|
||
}
|
||
|
||
pub fn size(&self) -> usize {
|
||
return self.buffer.len();
|
||
}
|
||
|
||
/// 从指定地址写入数据到用户空间
|
||
///
|
||
/// @param data 要写入的数据地址
|
||
/// @param offset 在UserBuffer中的字节偏移量
|
||
/// @return 返回写入元素的数量
|
||
///
|
||
pub fn copy_to_user<T: core::marker::Copy>(
|
||
&'a mut self,
|
||
src: &[T],
|
||
offset: usize,
|
||
) -> Result<usize, SystemError> {
|
||
let dst = Self::convert_with_offset(self.buffer, offset)?;
|
||
dst.copy_from_slice(src);
|
||
return Ok(src.len());
|
||
}
|
||
|
||
/// 从指定地址写入一个数据到用户空间
|
||
///
|
||
/// @param data 要写入的数据地址
|
||
/// @param offset 在UserBuffer中的字节偏移量
|
||
/// @return Ok/Err
|
||
///
|
||
pub fn copy_one_to_user<T: core::marker::Copy>(
|
||
&'a mut self,
|
||
src: &T,
|
||
offset: usize,
|
||
) -> Result<(), SystemError> {
|
||
let dst = Self::convert_one_with_offset::<T>(self.buffer, offset)?;
|
||
dst.clone_from(src);
|
||
return Ok(());
|
||
}
|
||
|
||
pub fn buffer<T>(&'a mut self, offset: usize) -> Result<&'a mut [T], SystemError> {
|
||
Self::convert_with_offset::<T>(self.buffer, offset).map_err(|_| SystemError::EINVAL)
|
||
}
|
||
|
||
fn convert_with_offset<T>(src: &mut [u8], offset: usize) -> Result<&mut [T], SystemError> {
|
||
if offset >= src.len() {
|
||
return Err(SystemError::EINVAL);
|
||
}
|
||
let byte_buffer: &mut [u8] = &mut src[offset..];
|
||
if byte_buffer.len() % core::mem::size_of::<T>() != 0 || byte_buffer.is_empty() {
|
||
return Err(SystemError::EINVAL);
|
||
}
|
||
|
||
let chunks = unsafe {
|
||
from_raw_parts_mut(
|
||
byte_buffer.as_mut_ptr() as *mut T,
|
||
byte_buffer.len() / core::mem::size_of::<T>(),
|
||
)
|
||
};
|
||
return Ok(chunks);
|
||
}
|
||
|
||
fn convert_one_with_offset<T>(src: &mut [u8], offset: usize) -> Result<&mut T, SystemError> {
|
||
if offset + core::mem::size_of::<T>() > src.len() {
|
||
return Err(SystemError::EINVAL);
|
||
}
|
||
let byte_buffer: &mut [u8] = &mut src[offset..offset + core::mem::size_of::<T>()];
|
||
|
||
let chunks = unsafe { from_raw_parts_mut(byte_buffer.as_mut_ptr() as *mut T, 1) };
|
||
let data = &mut chunks[0];
|
||
return Ok(data);
|
||
}
|
||
}
|