linker.rs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. use alloc::{
  2. collections::BTreeMap,
  3. rc::Rc,
  4. string::{String, ToString},
  5. vec::Vec,
  6. };
  7. use core::{cell::RefCell, mem::transmute, ptr};
  8. use goblin::{
  9. elf::{program_header, reloc, sym::STT_TLS, Elf},
  10. error::{Error, Result},
  11. };
  12. use crate::{
  13. c_str::CString,
  14. fs::File,
  15. header::{
  16. dl_tls::{__tls_get_addr, dl_tls_index},
  17. fcntl, sys_mman,
  18. unistd::F_OK,
  19. },
  20. io::Read,
  21. platform::types::c_void,
  22. };
  23. use super::{
  24. access::accessible,
  25. callbacks::LinkerCallbacks,
  26. debug::{RTLDState, _dl_debug_state, _r_debug},
  27. dso::{is_pie_enabled, DSO},
  28. tcb::{round_up, Master, Tcb},
  29. ExpectTlsFree, PATH_SEP,
  30. };
  31. #[derive(Clone, Copy, Debug)]
  32. pub struct Symbol {
  33. pub value: usize,
  34. pub base: usize,
  35. pub size: usize,
  36. pub sym_type: u8,
  37. }
  38. impl Symbol {
  39. pub fn as_ptr(self) -> *mut c_void {
  40. (self.base + self.value) as *mut c_void
  41. }
  42. }
  43. pub struct Linker {
  44. ld_library_path: Option<String>,
  45. next_object_id: usize,
  46. next_tls_module_id: usize,
  47. tls_size: usize,
  48. objects: BTreeMap<usize, DSO>,
  49. name_to_object_id_map: BTreeMap<String, usize>,
  50. pub cbs: Rc<RefCell<LinkerCallbacks>>,
  51. }
  52. const root_id: usize = 1;
  53. impl Linker {
  54. pub fn new(ld_library_path: Option<String>) -> Self {
  55. Self {
  56. ld_library_path: ld_library_path,
  57. next_object_id: root_id,
  58. next_tls_module_id: 0,
  59. tls_size: 0,
  60. objects: BTreeMap::new(),
  61. name_to_object_id_map: BTreeMap::new(),
  62. cbs: Rc::new(RefCell::new(LinkerCallbacks::new())),
  63. }
  64. }
  65. pub fn load_program(&mut self, path: &str, base_addr: Option<usize>) -> Result<usize> {
  66. self.load_object(path, &None, base_addr, false)?;
  67. return Ok(self.objects.get(&root_id).unwrap().entry_point);
  68. }
  69. pub fn load_library(&mut self, name: Option<&str>) -> Result<usize> {
  70. match name {
  71. Some(name) => {
  72. if let Some(id) = self.name_to_object_id_map.get(name) {
  73. let obj = self.objects.get_mut(id).unwrap();
  74. obj.use_count += 1;
  75. return Ok(*id);
  76. } else {
  77. let parent_runpath = &self
  78. .objects
  79. .get(&root_id)
  80. .and_then(|parent| parent.runpath.clone());
  81. let lib_id = self.next_object_id;
  82. self.load_object(name, parent_runpath, None, true)?;
  83. return Ok(lib_id);
  84. }
  85. }
  86. None => return Ok(root_id),
  87. }
  88. }
  89. pub fn get_sym(&self, lib_id: usize, name: &str) -> Option<*mut c_void> {
  90. match self.objects.get(&lib_id) {
  91. Some(obj) => {
  92. return obj.get_sym(name).map(|(s, strong)| {
  93. if s.sym_type != STT_TLS {
  94. s.as_ptr()
  95. } else {
  96. unsafe {
  97. let mut tls_index = dl_tls_index {
  98. ti_module: obj.tls_module_id as u64,
  99. ti_offset: s.value as u64,
  100. };
  101. __tls_get_addr(&mut tls_index)
  102. }
  103. }
  104. });
  105. }
  106. _ => {
  107. return None;
  108. }
  109. }
  110. }
  111. pub fn unload(&mut self, lib_id: usize) {
  112. if let Some(obj) = self.objects.get_mut(&lib_id) {
  113. if obj.dlopened {
  114. if obj.use_count == 1 {
  115. let obj = self.objects.remove(&lib_id).unwrap();
  116. for dep in obj.dependencies.iter() {
  117. self.unload(*self.name_to_object_id_map.get(dep).unwrap());
  118. }
  119. self.name_to_object_id_map.remove(&obj.name);
  120. drop(obj);
  121. } else {
  122. obj.use_count -= 1;
  123. }
  124. }
  125. }
  126. }
  127. pub fn fini(&self) {
  128. for obj in self.objects.values() {
  129. obj.run_fini();
  130. }
  131. }
  132. fn load_object(
  133. &mut self,
  134. path: &str,
  135. runpath: &Option<String>,
  136. base_addr: Option<usize>,
  137. dlopened: bool,
  138. ) -> Result<()> {
  139. unsafe { _r_debug.state = RTLDState::RT_ADD };
  140. _dl_debug_state();
  141. let mut new_objects = Vec::new();
  142. let mut objects_data = Vec::new();
  143. let mut tcb_masters = Vec::new();
  144. self.load_objects_recursive(
  145. path,
  146. runpath,
  147. base_addr,
  148. dlopened,
  149. &mut new_objects,
  150. &mut objects_data,
  151. &mut tcb_masters,
  152. )?;
  153. unsafe {
  154. let tcb = match Tcb::current() {
  155. Some(some) => some,
  156. None => Tcb::new(self.tls_size)?,
  157. };
  158. tcb.append_masters(tcb_masters);
  159. tcb.copy_masters()?;
  160. tcb.activate();
  161. }
  162. self.relocate(&new_objects, &objects_data)?;
  163. self.run_init(&new_objects);
  164. for obj in new_objects.into_iter() {
  165. self.name_to_object_id_map.insert(obj.name.clone(), obj.id);
  166. self.objects.insert(obj.id, obj);
  167. }
  168. unsafe { _r_debug.state = RTLDState::RT_CONSISTENT };
  169. _dl_debug_state();
  170. return Ok(());
  171. }
  172. fn load_objects_recursive(
  173. &mut self,
  174. name: &str,
  175. parent_runpath: &Option<String>,
  176. base_addr: Option<usize>,
  177. dlopened: bool,
  178. new_objects: &mut Vec<DSO>,
  179. objects_data: &mut Vec<Vec<u8>>,
  180. tcb_masters: &mut Vec<Master>,
  181. ) -> Result<()> {
  182. if let Some(obj) = {
  183. if let Some(id) = self.name_to_object_id_map.get(name) {
  184. self.objects.get_mut(id)
  185. } else {
  186. new_objects.iter_mut().find(|o| o.name == name)
  187. }
  188. } {
  189. obj.use_count += 1;
  190. return Ok(());
  191. }
  192. let path = Linker::search_object(name, &self.ld_library_path, parent_runpath)?;
  193. let data = Linker::read_file(&path)?;
  194. let (obj, tcb_master) = DSO::new(
  195. &path,
  196. &data,
  197. base_addr,
  198. dlopened,
  199. self.next_object_id,
  200. self.next_tls_module_id,
  201. self.tls_size,
  202. )?;
  203. new_objects.push(obj);
  204. objects_data.push(data);
  205. self.next_object_id += 1;
  206. if let Some(master) = tcb_master {
  207. if self.next_tls_module_id == 0 {
  208. // Hack to allocate TCB on the first TLS module
  209. unsafe {
  210. if Tcb::current().is_none() {
  211. let tcb = Tcb::new(master.offset).expect_notls("failed to allocate TCB");
  212. tcb.activate();
  213. }
  214. }
  215. }
  216. self.next_tls_module_id += 1;
  217. self.tls_size = master.offset;
  218. tcb_masters.push(master);
  219. }
  220. let (runpath, dependencies) = {
  221. let parent = new_objects.last().unwrap();
  222. (parent.runpath.clone(), parent.dependencies.clone())
  223. };
  224. for dep_name in dependencies.iter() {
  225. self.load_objects_recursive(
  226. dep_name,
  227. &runpath,
  228. None,
  229. dlopened,
  230. new_objects,
  231. objects_data,
  232. tcb_masters,
  233. )?;
  234. }
  235. return Ok(());
  236. }
  237. fn search_object(
  238. name: &str,
  239. ld_library_path: &Option<String>,
  240. parent_runpath: &Option<String>,
  241. ) -> Result<String> {
  242. let mut full_path = name.to_string();
  243. if accessible(&full_path, F_OK) == 0 {
  244. return Ok(full_path);
  245. } else {
  246. let mut search_paths = Vec::new();
  247. if let Some(runpath) = parent_runpath {
  248. search_paths.extend(runpath.split(PATH_SEP));
  249. }
  250. if let Some(ld_path) = ld_library_path {
  251. search_paths.extend(ld_path.split(PATH_SEP));
  252. }
  253. search_paths.push("/lib");
  254. for part in search_paths.iter() {
  255. full_path = format!("{}/{}", part, name);
  256. trace!("trying path {}", full_path);
  257. if accessible(&full_path, F_OK) == 0 {
  258. return Ok(full_path);
  259. }
  260. }
  261. }
  262. return Err(Error::Malformed(format!("failed to locate '{}'", name)));
  263. }
  264. fn read_file(path: &str) -> Result<Vec<u8>> {
  265. let mut data = Vec::new();
  266. let path_c = CString::new(path)
  267. .map_err(|err| Error::Malformed(format!("invalid path '{}': {}", path, err)))?;
  268. let flags = fcntl::O_RDONLY | fcntl::O_CLOEXEC;
  269. let mut file = File::open(&path_c, flags)
  270. .map_err(|err| Error::Malformed(format!("failed to open '{}': {}", path, err)))?;
  271. file.read_to_end(&mut data)
  272. .map_err(|err| Error::Malformed(format!("failed to read '{}': {}", path, err)))?;
  273. return Ok(data);
  274. }
  275. fn relocate(&self, new_objects: &Vec<DSO>, objects_data: &Vec<Vec<u8>>) -> Result<()> {
  276. let symbols_lookup_objects: Vec<&DSO> =
  277. self.objects.values().chain(new_objects.iter()).collect();
  278. // Perform relocations
  279. for i in (0..new_objects.len()).rev() {
  280. let elf = Elf::parse(&objects_data[i])?;
  281. let obj = &new_objects[i];
  282. trace!("link {}", obj.name);
  283. let mmap = &obj.mmap;
  284. let b = mmap.as_ptr() as usize;
  285. // Relocate
  286. for rel in elf
  287. .dynrelas
  288. .iter()
  289. .chain(elf.dynrels.iter())
  290. .chain(elf.pltrelocs.iter())
  291. {
  292. trace!(
  293. " rel {}: {:x?}",
  294. reloc::r_to_str(rel.r_type, elf.header.e_machine),
  295. rel
  296. );
  297. let (symbol, t) = if rel.r_sym > 0 {
  298. let sym = elf.dynsyms.get(rel.r_sym).ok_or(Error::Malformed(format!(
  299. "missing symbol for relocation {:?}",
  300. rel
  301. )))?;
  302. let mut t = 0;
  303. let name =
  304. elf.dynstrtab
  305. .get(sym.st_name)
  306. .ok_or(Error::Malformed(format!(
  307. "missing name for symbol {:?}",
  308. sym
  309. )))??;
  310. let mut symbol = None;
  311. let mut found = false;
  312. let lookup_start = match rel.r_type {
  313. reloc::R_X86_64_COPY => 1,
  314. _ => 0,
  315. };
  316. for lookup_id in lookup_start..symbols_lookup_objects.len() {
  317. let lookup_obj = &symbols_lookup_objects[lookup_id];
  318. if let Some((s, strong)) = lookup_obj.get_sym(name) {
  319. trace!(
  320. "symbol {} from {} found in {} ({})",
  321. name,
  322. obj.name,
  323. lookup_obj.name,
  324. if strong { "strong" } else { "weak" }
  325. );
  326. symbol = Some(s);
  327. t = lookup_obj.tls_offset;
  328. found = true;
  329. // Stop looking if any strong symbol is found
  330. if strong {
  331. break;
  332. }
  333. }
  334. }
  335. // TODO: below doesn't work because of missing __preinit_array_{start,end} and __init_array_{start,end} symbols in dynamic linked programs
  336. /*
  337. if !found {
  338. return Err(Error::Malformed(format!("missing symbol for name {}", name)));
  339. }
  340. */
  341. (symbol, t)
  342. } else {
  343. (None, 0)
  344. };
  345. let s = symbol
  346. .as_ref()
  347. .map(|sym| sym.as_ptr() as usize)
  348. .unwrap_or(0);
  349. let a = rel.r_addend.unwrap_or(0) as usize;
  350. let ptr = if is_pie_enabled(&elf) {
  351. (b + rel.r_offset as usize) as *mut u8
  352. } else {
  353. rel.r_offset as *mut u8
  354. };
  355. let set_u64 = |value| {
  356. trace!(" set_u64 {:#x}", value);
  357. unsafe {
  358. *(ptr as *mut u64) = value;
  359. }
  360. };
  361. match rel.r_type {
  362. reloc::R_X86_64_64 => {
  363. set_u64((s + a) as u64);
  364. }
  365. reloc::R_X86_64_DTPMOD64 => {
  366. set_u64(obj.tls_module_id as u64);
  367. }
  368. reloc::R_X86_64_DTPOFF64 => {
  369. if s != 0 {
  370. set_u64((s - b) as u64);
  371. } else {
  372. set_u64(s as u64);
  373. }
  374. }
  375. reloc::R_X86_64_GLOB_DAT | reloc::R_X86_64_JUMP_SLOT => {
  376. set_u64(s as u64);
  377. }
  378. reloc::R_X86_64_RELATIVE => {
  379. set_u64((b + a) as u64);
  380. }
  381. reloc::R_X86_64_TPOFF64 => {
  382. if rel.r_sym > 0 {
  383. let sym = symbol
  384. .as_ref()
  385. .expect("R_X86_64_TPOFF64 called without valid symbol");
  386. set_u64((sym.value + a).wrapping_sub(t) as u64);
  387. } else {
  388. set_u64(a.wrapping_sub(t) as u64);
  389. }
  390. }
  391. reloc::R_X86_64_IRELATIVE => unsafe {
  392. let f: unsafe extern "C" fn() -> u64 = transmute(b + a);
  393. set_u64(f());
  394. },
  395. reloc::R_X86_64_COPY => unsafe {
  396. let sym = symbol
  397. .as_ref()
  398. .expect("R_X86_64_COPY called without valid symbol");
  399. ptr::copy_nonoverlapping(sym.as_ptr() as *const u8, ptr, sym.size as usize);
  400. },
  401. _ => {
  402. panic!(
  403. " {} unsupported",
  404. reloc::r_to_str(rel.r_type, elf.header.e_machine)
  405. );
  406. }
  407. }
  408. }
  409. // Protect pages
  410. for ph in elf
  411. .program_headers
  412. .iter()
  413. .filter(|ph| ph.p_type == program_header::PT_LOAD)
  414. {
  415. let voff = ph.p_vaddr % ph.p_align;
  416. let vaddr = (ph.p_vaddr - voff) as usize;
  417. let vsize = round_up((ph.p_memsz + voff) as usize, ph.p_align as usize);
  418. let mut prot = 0;
  419. if ph.p_flags & program_header::PF_R == program_header::PF_R {
  420. prot |= sys_mman::PROT_READ;
  421. }
  422. // W ^ X. If it is executable, do not allow it to be writable, even if requested
  423. if ph.p_flags & program_header::PF_X == program_header::PF_X {
  424. prot |= sys_mman::PROT_EXEC;
  425. } else if ph.p_flags & program_header::PF_W == program_header::PF_W {
  426. prot |= sys_mman::PROT_WRITE;
  427. }
  428. let res = unsafe {
  429. let ptr = if is_pie_enabled(&elf) {
  430. mmap.as_ptr().add(vaddr)
  431. } else {
  432. vaddr as *const u8
  433. };
  434. trace!(" prot {:#x}, {:#x}: {:p}, {:#x}", vaddr, vsize, ptr, prot);
  435. sys_mman::mprotect(ptr as *mut c_void, vsize, prot)
  436. };
  437. if res < 0 {
  438. return Err(Error::Malformed(format!("failed to mprotect {}", obj.name)));
  439. }
  440. }
  441. }
  442. return Ok(());
  443. }
  444. fn run_init(&self, objects: &Vec<DSO>) {
  445. use crate::platform::{self, types::*};
  446. for obj in objects.iter().rev() {
  447. if let Some((symbol, true)) = obj.get_sym("__relibc_init_environ") {
  448. unsafe {
  449. symbol
  450. .as_ptr()
  451. .cast::<*mut *mut c_char>()
  452. .write(platform::environ);
  453. }
  454. }
  455. obj.run_init();
  456. }
  457. }
  458. }