linfeng 72423f90bb
feat(ebpf): support Aya framework. (#1070)
* 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>
2024-12-07 16:41:37 +08:00

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)
}
}
}