commit 0d7f5a32066200df2bb565f2fdf02b3c2b6663f4 Author: Ales Katona Date: Wed Dec 9 11:51:29 2020 -0800 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..979737f --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/target + +/assets diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..7d8745d --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,62 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "libc" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" + +[[package]] +name = "page_size" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eebde548fbbf1ea81a99b128872779c437752fb99f217c45245e1a61dcd9edcd" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "rld" +version = "0.1.0" +dependencies = [ + "page_size", + "xmas-elf", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "xmas-elf" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e74de9a366f6ab8c405fa6b371d9ac24943921fa14b3d64afcb202065c405f11" +dependencies = [ + "zero", +] + +[[package]] +name = "zero" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f1bc8a6b2005884962297587045002d8cfb8dcec9db332f4ca216ddc5de82c5" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..50686f2 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "rld" +version = "0.1.0" +authors = ["Ales Katona "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +xmas-elf = "0.7.0" +page_size = "0.4.2" \ No newline at end of file diff --git a/docs/2-study-and-analysis-of-elf-vulnerabilities-in-linux.pdf b/docs/2-study-and-analysis-of-elf-vulnerabilities-in-linux.pdf new file mode 100644 index 0000000..bca3758 Binary files /dev/null and b/docs/2-study-and-analysis-of-elf-vulnerabilities-in-linux.pdf differ diff --git a/docs/ELF_Format.pdf b/docs/ELF_Format.pdf new file mode 100644 index 0000000..34b9e8c Binary files /dev/null and b/docs/ELF_Format.pdf differ diff --git a/docs/linkers_and_loaders.pdf b/docs/linkers_and_loaders.pdf new file mode 100644 index 0000000..c82383c Binary files /dev/null and b/docs/linkers_and_loaders.pdf differ diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..e7c196a --- /dev/null +++ b/src/error.rs @@ -0,0 +1,15 @@ +#[derive(Debug)] +pub enum Error { + IOError(std::io::Error), + InvalidObjectType(u32), + StringError(&'static str), + MissingSectionHeader(&'static str), + MissingSectionData(&'static str), + InvalidSectionData, +} + +impl From for Error { + fn from(err: std::io::Error) -> Self { + Self::IOError(err) + } +} diff --git a/src/formats.rs b/src/formats.rs new file mode 100644 index 0000000..a1deb41 --- /dev/null +++ b/src/formats.rs @@ -0,0 +1,3 @@ +mod elf; + +pub use elf::*; diff --git a/src/formats/elf.rs b/src/formats/elf.rs new file mode 100644 index 0000000..6c0161a --- /dev/null +++ b/src/formats/elf.rs @@ -0,0 +1,71 @@ +use std::convert::TryFrom; + +use crate::error::Error; +use crate::parts::{Lazy, Relocatable, Symbol, Text}; +use xmas_elf::header::Type as ElfType; +use xmas_elf::sections::*; +use xmas_elf::ElfFile; + +impl<'a> Lazy<&'a str, ElfFile<'a>> for Symbol<'a> { + fn value(&self, src: &ElfFile<'a>) -> Result<&'a str, Error> { + src.get_string(self.index) + .map_err(|e| Error::StringError(e)) + } + + fn resolved(&self) -> bool { + self.str_ref.is_some() + } +} + +impl<'a> TryFrom> for Text<'a> { + type Error = Error; + + fn try_from(data: SectionData<'a>) -> Result { + match data { + SectionData::Undefined(bytes) => Ok(Text { bytes }), + _ => Err(Error::InvalidSectionData), // TODO: more context needed + } + } +} + +impl<'a> Relocatable<'a> { + pub fn from_elf(origin: &'a str, elf: &'a ElfFile) -> Result { + is_relocatable(elf)?; + let mut result = Relocatable::new(origin); + + for header in elf.section_iter() { + // .text sections > 0 only + if is_text_section(elf, &header)? { + let data = header + .get_data(&elf) + .map_err(|e| Error::MissingSectionData(e))?; + + result.texts.push(Text::try_from(data)?); + } + } + + Ok(result) + } +} + +fn is_text_section(elf: &ElfFile, header: &SectionHeader) -> Result { + let name = header.get_name(&elf).unwrap_or("null"); + let h_type = header + .get_type() + .map_err(|e| Error::MissingSectionHeader(e))?; + + Ok(h_type == ShType::ProgBits + && header.flags() == (SHF_EXECINSTR | SHF_ALLOC) + && name.starts_with(".text") + && header.size() > 0) +} + +fn is_relocatable(elf: &ElfFile) -> Result<(), Error> { + let raw_type = elf.header.pt2.type_(); + let elf_type: ElfType = raw_type.as_type(); + if elf_type != ElfType::Relocatable { + return Err(Error::InvalidObjectType(raw_type.0.into())); + } + + Ok(()) +} diff --git a/src/linker.rs b/src/linker.rs new file mode 100644 index 0000000..c1b8254 --- /dev/null +++ b/src/linker.rs @@ -0,0 +1,29 @@ +use std::fmt::Display; + +use crate::error::Error; +use crate::parts::Relocatable; + +#[derive(Default)] +pub struct LinkState<'a> { + relocatables: Vec>, +} + +impl<'a> LinkState<'a> { + pub fn add_relocatable(&mut self, relocatable: Relocatable<'a>) -> Result<(), Error> { + self.relocatables.push(relocatable); + + Ok(()) + } +} + +impl Display for LinkState<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!(f, "===Relocatables===")?; + + for r in self.relocatables.iter() { + writeln!(f, "{}", r)?; + } + + Ok(()) + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..63dc852 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,39 @@ +use std::fs; +use xmas_elf::ElfFile; + +mod error; +mod formats; +mod linker; +mod parts; + +use linker::LinkState; +use parts::Relocatable; + +fn main() { + let mut args = std::env::args().peekable(); + + // can this miss? + args.next().unwrap(); + + let mut contents: Vec<(String, Vec)> = Vec::new(); + let mut parsed: Vec<(&str, ElfFile)> = Vec::new(); + let mut linker = LinkState::default(); + + while args.peek().is_some() { + let fpath = args.next().expect("Unexpected peek-a-boo"); + let raw = fs::read(&fpath).expect("Error reading file"); + contents.push((fpath, raw)); + } + + for data in contents.iter() { + let elf = ElfFile::new(&data.1).expect("Error parsing ELF file"); + parsed.push((&data.0, elf)); + } + + for elf in parsed.iter() { + let relocatable = Relocatable::from_elf(elf.0, &elf.1).unwrap(); + linker.add_relocatable(relocatable).unwrap(); + } + + println!("{}", linker); +} diff --git a/src/parts.rs b/src/parts.rs new file mode 100644 index 0000000..d511345 --- /dev/null +++ b/src/parts.rs @@ -0,0 +1,9 @@ +mod lazy; +mod relocatable; +mod symbol; +mod segments; + +pub use lazy::*; +pub use relocatable::*; +pub use symbol::*; +pub use segments::*; diff --git a/src/parts/lazy.rs b/src/parts/lazy.rs new file mode 100644 index 0000000..77849ae --- /dev/null +++ b/src/parts/lazy.rs @@ -0,0 +1,9 @@ +use crate::error::Error; + +pub trait Lazy { + /// Resolve VALUE, blocking load from the SOURCE + fn value(&self, src: &SOURCE) -> Result; + + /// Check if already resolved + fn resolved(&self) -> bool; +} diff --git a/src/parts/relocatable.rs b/src/parts/relocatable.rs new file mode 100644 index 0000000..5feead1 --- /dev/null +++ b/src/parts/relocatable.rs @@ -0,0 +1,33 @@ +use crate::parts::{Symbol, Text, Data, Bss}; + +/// Contains all the needed references to construct a final +/// mushed and relocated executable from an object file +pub struct Relocatable<'a> { + pub origin: &'a str, + pub symbols: Vec>, + pub texts: Vec>, + pub data: Vec>, + pub bss: Vec>, +} + +impl<'a> Relocatable<'a> { + pub fn new(origin: &'a str) -> Self { + Self { + origin, + symbols: Vec::new(), + texts: Vec::new(), + data: Vec::new(), + bss: Vec::new(), + } + } +} + +impl std::fmt::Display for Relocatable<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "==={}===\nSymbols:\n{:?}\nTexts:\n??", + self.origin, self.symbols //, self.texts + ) + } +} diff --git a/src/parts/segments.rs b/src/parts/segments.rs new file mode 100644 index 0000000..15a5530 --- /dev/null +++ b/src/parts/segments.rs @@ -0,0 +1,13 @@ + + +pub struct Text<'a> { + pub bytes: &'a [u8], +} + +pub struct Data<'a> { + pub bytes: &'a [u8], +} + +pub struct Bss<'a> { + pub bytes: &'a [u8], +} diff --git a/src/parts/symbol.rs b/src/parts/symbol.rs new file mode 100644 index 0000000..3572ac0 --- /dev/null +++ b/src/parts/symbol.rs @@ -0,0 +1,14 @@ +#[derive(Debug, Default)] +pub struct Symbol<'a> { + pub index: u32, + pub str_ref: Option<&'a str>, +} + +impl Symbol<'_> { + pub fn new(index: u32) -> Self { + Self { + index, + str_ref: None, + } + } +}