mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 14:16:47 +00:00
* feat(ebpf): support Aya framework. 1. fix the rbpf bug 2. use new Aya template 3. add kprobe related device files and attributes to sysfs --- Signed-off-by: chenlinfeng <chenlinfeng25@outlook.com>
320 lines
11 KiB
Rust
320 lines
11 KiB
Rust
use core::{
|
|
intrinsics::{likely, unlikely},
|
|
panic,
|
|
};
|
|
|
|
use alloc::sync::Arc;
|
|
use log::error;
|
|
use x86::{bits64::rflags::RFlags, controlregs::Cr4};
|
|
|
|
use crate::{
|
|
arch::{
|
|
interrupt::{trap::X86PfErrorCode, TrapFrame},
|
|
ipc::signal::{SigCode, Signal},
|
|
mm::{MemoryManagementArch, X86_64MMArch},
|
|
CurrentIrqArch, MMArch,
|
|
},
|
|
exception::InterruptArch,
|
|
ipc::signal_types::{SigInfo, SigType},
|
|
mm::{
|
|
fault::{FaultFlags, PageFaultHandler, PageFaultMessage},
|
|
ucontext::{AddressSpace, LockedVMA},
|
|
VirtAddr, VmFaultReason, VmFlags,
|
|
},
|
|
process::ProcessManager,
|
|
};
|
|
|
|
use super::LockedFrameAllocator;
|
|
|
|
pub type PageMapper =
|
|
crate::mm::page::PageMapper<crate::arch::x86_64::mm::X86_64MMArch, LockedFrameAllocator>;
|
|
|
|
impl X86_64MMArch {
|
|
pub fn vma_access_error(vma: Arc<LockedVMA>, error_code: X86PfErrorCode) -> bool {
|
|
let vm_flags = *vma.lock_irqsave().vm_flags();
|
|
let foreign = false;
|
|
if error_code.contains(X86PfErrorCode::X86_PF_PK) {
|
|
return true;
|
|
}
|
|
|
|
if unlikely(error_code.contains(X86PfErrorCode::X86_PF_SGX)) {
|
|
return true;
|
|
}
|
|
|
|
if !Self::vma_access_permitted(
|
|
vma.clone(),
|
|
error_code.contains(X86PfErrorCode::X86_PF_WRITE),
|
|
error_code.contains(X86PfErrorCode::X86_PF_INSTR),
|
|
foreign,
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
if error_code.contains(X86PfErrorCode::X86_PF_WRITE) {
|
|
if unlikely(!vm_flags.contains(VmFlags::VM_WRITE)) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
if unlikely(error_code.contains(X86PfErrorCode::X86_PF_PROT)) {
|
|
return true;
|
|
}
|
|
|
|
if unlikely(!vma.is_accessible()) {
|
|
return true;
|
|
}
|
|
false
|
|
}
|
|
|
|
pub fn show_fault_oops(
|
|
regs: &'static TrapFrame,
|
|
error_code: X86PfErrorCode,
|
|
address: VirtAddr,
|
|
) {
|
|
let mapper =
|
|
unsafe { PageMapper::current(crate::mm::PageTableKind::User, LockedFrameAllocator) };
|
|
if let Some(entry) = mapper.get_entry(address, 0) {
|
|
if entry.present() {
|
|
if !entry.flags().has_execute() {
|
|
error!("kernel tried to execute NX-protected page - exploit attempt?");
|
|
} else if mapper.table().phys().data() & MMArch::ENTRY_FLAG_USER != 0
|
|
&& unsafe { x86::controlregs::cr4().contains(Cr4::CR4_ENABLE_SMEP) }
|
|
{
|
|
error!("unable to execute userspace code (SMEP?)");
|
|
}
|
|
}
|
|
}
|
|
if address.data() < X86_64MMArch::PAGE_SIZE && !regs.is_from_user() {
|
|
error!(
|
|
"BUG: kernel NULL pointer dereference, address: {:#x}",
|
|
address.data()
|
|
);
|
|
} else {
|
|
error!(
|
|
"BUG: unable to handle page fault for address: {:#x}",
|
|
address.data()
|
|
);
|
|
}
|
|
|
|
error!(
|
|
"#PF: {} {} in {} mode\n",
|
|
if error_code.contains(X86PfErrorCode::X86_PF_USER) {
|
|
"user"
|
|
} else {
|
|
"supervisor"
|
|
},
|
|
if error_code.contains(X86PfErrorCode::X86_PF_INSTR) {
|
|
"instruction fetch"
|
|
} else if error_code.contains(X86PfErrorCode::X86_PF_WRITE) {
|
|
"write access"
|
|
} else {
|
|
"read access"
|
|
},
|
|
if regs.is_from_user() {
|
|
"user"
|
|
} else {
|
|
"kernel"
|
|
}
|
|
);
|
|
error!(
|
|
"#PF: error_code({:#04x}) - {}\n",
|
|
error_code,
|
|
if !error_code.contains(X86PfErrorCode::X86_PF_PROT) {
|
|
"not-present page"
|
|
} else if error_code.contains(X86PfErrorCode::X86_PF_RSVD) {
|
|
"reserved bit violation"
|
|
} else if error_code.contains(X86PfErrorCode::X86_PF_PK) {
|
|
"protection keys violation"
|
|
} else {
|
|
"permissions violation"
|
|
}
|
|
);
|
|
}
|
|
|
|
pub fn page_fault_oops(
|
|
regs: &'static TrapFrame,
|
|
error_code: X86PfErrorCode,
|
|
address: VirtAddr,
|
|
) {
|
|
if regs.is_from_user() {
|
|
Self::show_fault_oops(regs, error_code, address);
|
|
}
|
|
panic!()
|
|
}
|
|
|
|
/// 内核态缺页异常处理
|
|
/// ## 参数
|
|
///
|
|
/// - `regs`: 中断栈帧
|
|
/// - `error_code`: 错误标志
|
|
/// - `address`: 发生缺页异常的虚拟地址
|
|
pub fn do_kern_addr_fault(
|
|
_regs: &'static TrapFrame,
|
|
error_code: X86PfErrorCode,
|
|
address: VirtAddr,
|
|
) {
|
|
panic!(
|
|
"do_kern_addr_fault has not yet been implemented,
|
|
fault address: {:#x},
|
|
error_code: {:#b},
|
|
pid: {}\n",
|
|
address.data(),
|
|
error_code,
|
|
crate::process::ProcessManager::current_pid().data()
|
|
);
|
|
//TODO https://code.dragonos.org.cn/xref/linux-6.6.21/arch/x86/mm/fault.c#do_kern_addr_fault
|
|
}
|
|
|
|
/// 用户态缺页异常处理
|
|
/// ## 参数
|
|
///
|
|
/// - `regs`: 中断栈帧
|
|
/// - `error_code`: 错误标志
|
|
/// - `address`: 发生缺页异常的虚拟地址
|
|
pub unsafe fn do_user_addr_fault(
|
|
regs: &'static TrapFrame,
|
|
error_code: X86PfErrorCode,
|
|
address: VirtAddr,
|
|
) {
|
|
let rflags = RFlags::from_bits_truncate(regs.rflags);
|
|
let mut flags: FaultFlags = FaultFlags::FAULT_FLAG_ALLOW_RETRY
|
|
| FaultFlags::FAULT_FLAG_KILLABLE
|
|
| FaultFlags::FAULT_FLAG_INTERRUPTIBLE;
|
|
|
|
if error_code & (X86PfErrorCode::X86_PF_USER | X86PfErrorCode::X86_PF_INSTR)
|
|
== X86PfErrorCode::X86_PF_INSTR
|
|
{
|
|
Self::page_fault_oops(regs, error_code, address);
|
|
}
|
|
|
|
let feature = x86::cpuid::CpuId::new()
|
|
.get_extended_feature_info()
|
|
.unwrap();
|
|
if unlikely(
|
|
feature.has_smap()
|
|
&& !error_code.contains(X86PfErrorCode::X86_PF_USER)
|
|
&& rflags.contains(RFlags::FLAGS_AC),
|
|
) {
|
|
Self::page_fault_oops(regs, error_code, address);
|
|
}
|
|
|
|
if unlikely(error_code.contains(X86PfErrorCode::X86_PF_RSVD)) {
|
|
// TODO https://code.dragonos.org.cn/xref/linux-6.6.21/arch/x86/mm/fault.c#pgtable_bad
|
|
panic!(
|
|
"Reserved bits are never expected to be set, error_code: {:#b}, address: {:#x}",
|
|
error_code,
|
|
address.data()
|
|
);
|
|
}
|
|
|
|
if regs.is_from_user() {
|
|
unsafe { CurrentIrqArch::interrupt_enable() };
|
|
flags |= FaultFlags::FAULT_FLAG_USER;
|
|
} else if rflags.contains(RFlags::FLAGS_IF) {
|
|
unsafe { CurrentIrqArch::interrupt_enable() };
|
|
}
|
|
|
|
if error_code.contains(X86PfErrorCode::X86_PF_SHSTK) {
|
|
flags |= FaultFlags::FAULT_FLAG_WRITE;
|
|
}
|
|
if error_code.contains(X86PfErrorCode::X86_PF_WRITE) {
|
|
flags |= FaultFlags::FAULT_FLAG_WRITE;
|
|
}
|
|
if error_code.contains(X86PfErrorCode::X86_PF_INSTR) {
|
|
flags |= FaultFlags::FAULT_FLAG_INSTRUCTION;
|
|
}
|
|
|
|
let current_address_space: Arc<AddressSpace> = AddressSpace::current().unwrap();
|
|
let mut space_guard = current_address_space.write_irqsave();
|
|
let mut fault;
|
|
loop {
|
|
let vma = space_guard.mappings.find_nearest(address);
|
|
// let vma = space_guard.mappings.contains(address);
|
|
|
|
let vma = match vma {
|
|
Some(vma) => vma,
|
|
None => {
|
|
log::error!(
|
|
"can not find nearest vma, error_code: {:#b}, address: {:#x}",
|
|
error_code,
|
|
address.data(),
|
|
);
|
|
let pid = ProcessManager::current_pid();
|
|
let mut info =
|
|
SigInfo::new(Signal::SIGSEGV, 0, SigCode::User, SigType::Kill(pid));
|
|
Signal::SIGSEGV
|
|
.send_signal_info(Some(&mut info), pid)
|
|
.expect("failed to send SIGSEGV to process");
|
|
return;
|
|
}
|
|
};
|
|
let guard = vma.lock_irqsave();
|
|
let region = *guard.region();
|
|
let vm_flags = *guard.vm_flags();
|
|
drop(guard);
|
|
|
|
if !region.contains(address) {
|
|
if vm_flags.contains(VmFlags::VM_GROWSDOWN) {
|
|
space_guard
|
|
.extend_stack(region.start() - address)
|
|
.unwrap_or_else(|_| {
|
|
panic!(
|
|
"user stack extend failed, error_code: {:#b}, address: {:#x}",
|
|
error_code,
|
|
address.data(),
|
|
)
|
|
});
|
|
} else {
|
|
log::error!(
|
|
"No mapped vma, error_code: {:#b}, address: {:#x}, flags: {:?}",
|
|
error_code,
|
|
address.data(),
|
|
flags
|
|
);
|
|
let pid = ProcessManager::current_pid();
|
|
let mut info =
|
|
SigInfo::new(Signal::SIGSEGV, 0, SigCode::User, SigType::Kill(pid));
|
|
Signal::SIGSEGV
|
|
.send_signal_info(Some(&mut info), pid)
|
|
.expect("failed to send SIGSEGV to process");
|
|
return;
|
|
}
|
|
}
|
|
|
|
if unlikely(Self::vma_access_error(vma.clone(), error_code)) {
|
|
panic!(
|
|
"vma access error, error_code: {:#b}, address: {:#x}",
|
|
error_code,
|
|
address.data(),
|
|
);
|
|
}
|
|
let mapper = &mut space_guard.user_mapper.utable;
|
|
let message = PageFaultMessage::new(vma.clone(), address, flags, mapper);
|
|
|
|
fault = PageFaultHandler::handle_mm_fault(message);
|
|
|
|
if fault.contains(VmFaultReason::VM_FAULT_COMPLETED) {
|
|
return;
|
|
}
|
|
|
|
if unlikely(fault.contains(VmFaultReason::VM_FAULT_RETRY)) {
|
|
flags |= FaultFlags::FAULT_FLAG_TRIED;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
let vm_fault_error = VmFaultReason::VM_FAULT_OOM
|
|
| VmFaultReason::VM_FAULT_SIGBUS
|
|
| VmFaultReason::VM_FAULT_SIGSEGV
|
|
| VmFaultReason::VM_FAULT_HWPOISON
|
|
| VmFaultReason::VM_FAULT_HWPOISON_LARGE
|
|
| VmFaultReason::VM_FAULT_FALLBACK;
|
|
|
|
if likely(!fault.contains(vm_fault_error)) {
|
|
panic!("fault error: {:?}", fault)
|
|
}
|
|
}
|
|
}
|