kmod_loader/arch/
x86_64.rs1use goblin::elf::{Elf, SectionHeader};
2use int_enum::IntEnum;
3
4use crate::{
5 ModuleErr, Result,
6 arch::{Ptr, get_rela_sym_idx, get_rela_type},
7 loader::{KernelModuleHelper, ModuleLoadInfo, ModuleOwner},
8};
9
10#[derive(Debug, Clone, Copy, Default)]
11#[repr(C)]
12pub struct ModuleArchSpecific {}
13
14#[repr(u32)]
15#[derive(Debug, Clone, Copy, IntEnum)]
16#[allow(non_camel_case_types)]
17pub enum ArchRelocationType {
19 R_X86_64_NONE = 0,
21 R_X86_64_64 = 1,
23 R_X86_64_PC32 = 2,
25 R_X86_64_GOT32 = 3,
27 R_X86_64_PLT32 = 4,
29 R_X86_64_COPY = 5,
31 R_X86_64_GLOB_DAT = 6,
33 R_X86_64_JUMP_SLOT = 7,
35 R_X86_64_RELATIVE = 8,
37 R_X86_64_GOTPCREL = 9,
39 R_X86_64_32 = 10,
41 R_X86_64_32S = 11,
43 R_X86_64_16 = 12,
45 R_X86_64_PC16 = 13,
47 R_X86_64_8 = 14,
49 R_X86_64_PC8 = 15,
51 R_X86_64_PC64 = 24,
53}
54
55type X64RelTy = ArchRelocationType;
56
57impl ArchRelocationType {
58 fn apply_relocation(&self, location: u64, mut target_addr: u64) -> Result<()> {
59 let size;
60 let location = Ptr(location);
61 let overflow = || {
62 log::error!(
63 "overflow in relocation type {:?}, target address {:#x}",
64 self,
65 target_addr
66 );
67 log::error!("module likely not compiled with -mcmodel=kernel");
68 ModuleErr::ENOEXEC
69 };
70 match self {
71 X64RelTy::R_X86_64_NONE => return Ok(()),
72 X64RelTy::R_X86_64_64 => {
73 size = 8;
74 }
75 X64RelTy::R_X86_64_32 => {
76 if target_addr != target_addr as u32 as u64 {
77 return Err(overflow());
78 }
79 size = 4;
80 }
81 X64RelTy::R_X86_64_32S => {
82 if (target_addr as i64) != ((target_addr as i32) as i64) {
86 return Err(overflow());
87 }
88 size = 4;
89 }
90 X64RelTy::R_X86_64_PC32 | X64RelTy::R_X86_64_PLT32 => {
91 target_addr = target_addr.wrapping_sub(location.0);
92 size = 4;
93 }
94 X64RelTy::R_X86_64_PC64 => {
95 target_addr = target_addr.wrapping_sub(location.0);
96 size = 8;
97 }
98 _ => {
99 log::error!("x86/modules: Unsupported relocation type: {:?}", self);
100 return Err(ModuleErr::ENOEXEC);
101 }
102 }
103 if location.as_slice::<u8>(size).iter().any(|&b| b != 0) {
105 log::error!(
106 "x86/modules: Invalid relocation target, existing value is nonzero for type {:?}, loc: {:#x}, value: {:#x}",
107 self,
108 location.0,
109 target_addr
110 );
111 return Err(ModuleErr::ENOEXEC);
112 } else {
113 match size {
115 4 => location.write::<u32>(target_addr as u32),
116 8 => location.write::<u64>(target_addr),
117 _ => unreachable!(),
118 }
119 }
120 Ok(())
121 }
122}
123
124pub struct ArchRelocate;
125
126#[allow(unused_assignments)]
127impl ArchRelocate {
128 pub fn apply_relocate_add<H: KernelModuleHelper>(
130 rela_list: &[goblin::elf64::reloc::Rela],
131 rel_section: &SectionHeader,
132 sechdrs: &[SectionHeader],
133 load_info: &ModuleLoadInfo,
134 module: &ModuleOwner<H>,
135 ) -> Result<()> {
136 for rela in rela_list {
137 let rel_type = get_rela_type(rela.r_info);
138 let sym_idx = get_rela_sym_idx(rela.r_info);
139
140 let location = sechdrs[rel_section.sh_info as usize].sh_addr + rela.r_offset;
142 let (sym, sym_name) = &load_info.syms[sym_idx];
143
144 let reloc_type = ArchRelocationType::try_from(rel_type).map_err(|_| {
145 log::error!(
146 "[{:?}]: Invalid relocation type: {}",
147 module.name(),
148 rel_type
149 );
150 ModuleErr::ENOEXEC
151 })?;
152
153 let target_addr = sym.st_value.wrapping_add(rela.r_addend as u64);
154
155 log::info!(
156 "[{:?}]: Applying relocation {:?} at location {:#x} with target addr {:#x}",
157 module.name(),
158 reloc_type,
159 location,
160 target_addr
161 );
162
163 let res = reloc_type.apply_relocation(location, target_addr);
164 match res {
165 Err(e) => {
166 log::error!("[{:?}]: '{}' {:?}", module.name(), sym_name, e);
167 return Err(e);
168 }
169 Ok(_) => { }
170 }
171 }
172 Ok(())
173 }
174}
175
176pub fn module_frob_arch_sections<H: KernelModuleHelper>(
177 elf: &mut Elf,
178 owner: &mut ModuleOwner<H>,
179) -> Result<()> {
180 Ok(())
181}