From b55e08a25a6564d5d8524f278b5dff867d95e3ae Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Sun, 4 Jul 2021 17:55:29 +0900 Subject: [PATCH 01/21] chore: add `error.rs` --- src/error.rs | 0 src/lib.rs | 1 + 2 files changed, 1 insertion(+) create mode 100644 src/error.rs diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/lib.rs b/src/lib.rs index 75dc8fe..5cd922e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,6 +26,7 @@ extern crate zero; pub mod header; pub mod sections; +pub mod error; pub mod program; pub mod symbol_table; pub mod dynamic; From b9fbcffe83a89e1822d8bf4199e060a529ac2457 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Sun, 4 Jul 2021 21:03:20 +0900 Subject: [PATCH 02/21] feat: define `Error` --- src/error.rs | 4 ++++ src/lib.rs | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/error.rs b/src/error.rs index e69de29..8756d37 100644 --- a/src/error.rs +++ b/src/error.rs @@ -0,0 +1,4 @@ +/// Errors returned by the methods and functions of this crate. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum Error{ +} diff --git a/src/lib.rs b/src/lib.rs index 5cd922e..1a4d245 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,7 +26,7 @@ extern crate zero; pub mod header; pub mod sections; -pub mod error; +mod error; pub mod program; pub mod symbol_table; pub mod dynamic; @@ -37,6 +37,8 @@ use sections::{SectionHeader, SectionIter}; use program::{ProgramHeader, ProgramIter}; use zero::{read, read_str}; +pub use error::Error; + pub type P32 = u32; pub type P64 = u64; From b49e400db079894312b1a9b9cd307d233205960a Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 2 Aug 2021 10:06:02 +0900 Subject: [PATCH 03/21] chore(parse_header): return `Error` as `Err` --- src/error.rs | 24 +++++++++++++++++++++++- src/header.rs | 14 ++++++++------ src/lib.rs | 2 +- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/error.rs b/src/error.rs index 8756d37..e88f5cf 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,4 +1,26 @@ +use core::fmt; + /// Errors returned by the methods and functions of this crate. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub enum Error{ +pub enum Error { + /// The magic number of the given ELF file is invalid. + InvalidMagic, + /// The class of the given ELF file is invalid. + InvalidClass, + /// The length of the given ELF file is too short. + FileIsTooShort, +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}", + match self { + Self::InvalidMagic => "The magic number of the given ELF file is invalid.", + Self::InvalidClass => "The class of the given ELF file is invalid.", + Self::FileIsTooShort => "The length of the given ELF file is too short.", + } + ) + } } diff --git a/src/header.rs b/src/header.rs index 6362c04..fe5fbc4 100644 --- a/src/header.rs +++ b/src/header.rs @@ -1,27 +1,29 @@ use core::fmt; use core::mem; +use crate::Error; + use {P32, P64, ElfFile}; use zero::{read, Pod}; -pub fn parse_header<'a>(input: &'a [u8]) -> Result, &'static str> { +pub fn parse_header<'a>(input: &'a [u8]) -> Result, Error> { let size_pt1 = mem::size_of::(); if input.len() < size_pt1 { - return Err("File is shorter than the first ELF header part"); + return Err(Error::FileIsTooShort); } let header_1: &'a HeaderPt1 = read(&input[..size_pt1]); if header_1.magic != MAGIC { - return Err("Did not find ELF magic number"); + return Err(Error::InvalidMagic); } let header_2 = match header_1.class() { - Class::None | Class::Other(_) => return Err("Invalid ELF class"), + Class::None | Class::Other(_) => return Err(Error::InvalidClass), Class::ThirtyTwo => { let size_pt2 = mem::size_of::>(); if input.len() < size_pt1 + size_pt2 { - return Err("File is shorter than ELF headers"); + return Err(Error::FileIsTooShort); } let header_2: &'a HeaderPt2_ = read(&input[size_pt1..size_pt1 + mem::size_of::>()]); @@ -30,7 +32,7 @@ pub fn parse_header<'a>(input: &'a [u8]) -> Result, &'static str> { Class::SixtyFour => { let size_pt2 = mem::size_of::>(); if input.len() < size_pt1 + size_pt2 { - return Err("File is shorter than ELF headers"); + return Err(Error::FileIsTooShort); } let header_2: &'a HeaderPt2_ = read(&input[size_pt1..size_pt1 + mem::size_of::>()]); diff --git a/src/lib.rs b/src/lib.rs index 1a4d245..906b04f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -49,7 +49,7 @@ pub struct ElfFile<'a> { } impl<'a> ElfFile<'a> { - pub fn new(input: &'a [u8]) -> Result, &'static str> { + pub fn new(input: &'a [u8]) -> Result, Error> { header::parse_header(input).map(|header| ElfFile {input, header}) } From d6a4bc257550c2bc4ced5aa0adeb24aa14c3ec22 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 5 Jul 2021 10:17:41 +0900 Subject: [PATCH 04/21] chore(section_header): return `Error` as `Err` --- src/lib.rs | 6 +++--- src/sections.rs | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 906b04f..ebf7d5c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,7 +53,7 @@ impl<'a> ElfFile<'a> { header::parse_header(input).map(|header| ElfFile {input, header}) } - pub fn section_header(&self, index: u16) -> Result, &'static str> { + pub fn section_header(&self, index: u16) -> Result, Error> { sections::parse_section_header(self.input, self.header, index) } @@ -75,7 +75,7 @@ impl<'a> ElfFile<'a> { } } - pub fn get_shstr(&self, index: u32) -> Result<&'a str, &'static str> { + pub fn get_shstr(&self, index: u32) -> Result<&'a str, Error> { self.get_shstr_table().map(|shstr_table| read_str(&shstr_table[(index as usize)..])) } @@ -106,7 +106,7 @@ impl<'a> ElfFile<'a> { None } - fn get_shstr_table(&self) -> Result<&'a [u8], &'static str> { + fn get_shstr_table(&self) -> Result<&'a [u8], Error> { // TODO cache this? let header = self.section_header(self.header.pt2.sh_str_index()); header.map(|h| &self.input[(h.offset() as usize)..]) diff --git a/src/sections.rs b/src/sections.rs index 3d2e33a..61948f2 100644 --- a/src/sections.rs +++ b/src/sections.rs @@ -16,11 +16,12 @@ use zero::{read, read_array, read_str, read_strs_to_null, StrReaderIterator, Pod use symbol_table; use dynamic::Dynamic; use hash::HashTable; +use crate::Error; pub fn parse_section_header<'a>(input: &'a [u8], header: Header<'a>, index: u16) - -> Result, &'static str> { + -> Result, Error> { // Trying to get index 0 (SHN_UNDEF) is also probably an error, but it is a legitimate section. assert!(index < SHN_LORESERVE, "Attempt to get section for a reserved index"); From ed4c02e1b90c06555a0e934f4505d0585c29719e Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 5 Jul 2021 14:43:05 +0900 Subject: [PATCH 05/21] chore(program_header): return `Error` as `Err` --- src/error.rs | 24 ++++++++++++++++++++++++ src/lib.rs | 12 ++++++------ src/program.rs | 5 +++-- src/sections.rs | 14 +++++++------- src/symbol_table.rs | 13 +++++++------ 5 files changed, 47 insertions(+), 21 deletions(-) diff --git a/src/error.rs b/src/error.rs index e88f5cf..32d4aa9 100644 --- a/src/error.rs +++ b/src/error.rs @@ -7,8 +7,25 @@ pub enum Error { InvalidMagic, /// The class of the given ELF file is invalid. InvalidClass, + /// The section type is invalid. + InvalidSectionType, /// The length of the given ELF file is too short. FileIsTooShort, + /// Program header is not found. + ProgramHeaderNotFound, + /// The `.symtab_shndx` section is not found. + SymtabShndxNotFound, + /// The `.strtab` section is not found. + StrtabNotFound, + /// The `.dynstr` section is not found. + DynstrNotFound, + /// The section type is `NULL`. + SectionIsNull, + /// The section header index is one of the followings: + /// - `SHN_UNDEF` + /// - `SHN_ABS` + /// - `SHN_COMMON` + SectionHeaderIndexIsReserved, } impl fmt::Display for Error { @@ -19,7 +36,14 @@ impl fmt::Display for Error { match self { Self::InvalidMagic => "The magic number of the given ELF file is invalid.", Self::InvalidClass => "The class of the given ELF file is invalid.", + Self::InvalidSectionType => "The section type is invalid.", Self::FileIsTooShort => "The length of the given ELF file is too short.", + Self::ProgramHeaderNotFound => "The program header is not found.", + Self::SymtabShndxNotFound => "The `.symtab_shndx` section is not found.", + Self::StrtabNotFound => "The `.strtab` section is not found.", + Self::DynstrNotFound => "The `.dynstr` section is not found.", + Self::SectionIsNull => "The section type is `NULL`.", + Self::SectionHeaderIndexIsReserved => "The section header index is reserved.", } ) } diff --git a/src/lib.rs b/src/lib.rs index ebf7d5c..9a330ef 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,7 +64,7 @@ impl<'a> ElfFile<'a> { } } - pub fn program_header(&self, index: u16) -> Result, &'static str> { + pub fn program_header(&self, index: u16) -> Result, Error> { program::parse_program_header(self.input, self.header, index) } @@ -79,16 +79,16 @@ impl<'a> ElfFile<'a> { self.get_shstr_table().map(|shstr_table| read_str(&shstr_table[(index as usize)..])) } - pub fn get_string(&self, index: u32) -> Result<&'a str, &'static str> { - let header = self.find_section_by_name(".strtab").ok_or("no .strtab section")?; + pub fn get_string(&self, index: u32) -> Result<&'a str, Error> { + let header = self.find_section_by_name(".strtab").ok_or(Error::StrtabNotFound)?; if header.get_type()? != sections::ShType::StrTab { - return Err("expected .strtab to be StrTab"); + unreachable!("expected .strtab to be StrTab"); } Ok(read_str(&header.raw_data(self)[(index as usize)..])) } - pub fn get_dyn_string(&self, index: u32) -> Result<&'a str, &'static str> { - let header = self.find_section_by_name(".dynstr").ok_or("no .dynstr section")?; + pub fn get_dyn_string(&self, index: u32) -> Result<&'a str, Error> { + let header = self.find_section_by_name(".dynstr").ok_or(Error::DynstrNotFound)?; Ok(read_str(&header.raw_data(self)[(index as usize)..])) } diff --git a/src/program.rs b/src/program.rs index b11cc6c..8c4b456 100644 --- a/src/program.rs +++ b/src/program.rs @@ -3,6 +3,7 @@ use zero::{read, read_array, Pod}; use header::{Class, Header}; use dynamic::Dynamic; use sections::NoteHeader; +use crate::Error; use core::mem; use core::fmt; @@ -11,10 +12,10 @@ use core::fmt; pub fn parse_program_header<'a>(input: &'a [u8], header: Header<'a>, index: u16) - -> Result, &'static str> { + -> Result, Error> { let pt2 = &header.pt2; if !(index < pt2.ph_count() && pt2.ph_offset() > 0 && pt2.ph_entry_size() > 0) { - return Err("There are no program headers in this file") + return Err(Error::ProgramHeaderNotFound) } let start = pt2.ph_offset() as usize + index as usize * pt2.ph_entry_size() as usize; diff --git a/src/sections.rs b/src/sections.rs index 61948f2..f4d6d48 100644 --- a/src/sections.rs +++ b/src/sections.rs @@ -95,18 +95,18 @@ macro_rules! getter { impl<'a> SectionHeader<'a> { // Note that this function is O(n) in the length of the name. - pub fn get_name(&self, elf_file: &ElfFile<'a>) -> Result<&'a str, &'static str> { + pub fn get_name(&self, elf_file: &ElfFile<'a>) -> Result<&'a str, Error> { self.get_type().and_then(|typ| match typ { - ShType::Null => Err("Attempt to get name of null section"), + ShType::Null => Err(Error::SectionIsNull), _ => elf_file.get_shstr(self.name()), }) } - pub fn get_type(&self) -> Result { + pub fn get_type(&self) -> Result { self.type_().as_sh_type() } - pub fn get_data(&self, elf_file: &ElfFile<'a>) -> Result, &'static str> { + pub fn get_data(&self, elf_file: &ElfFile<'a>) -> Result, Error> { macro_rules! array_data { ($data32: ident, $data64: ident) => {{ let data = self.raw_data(elf_file); @@ -291,7 +291,7 @@ pub enum ShType { } impl ShType_ { - fn as_sh_type(self) -> Result { + fn as_sh_type(self) -> Result { match self.0 { 0 => Ok(ShType::Null), 1 => Ok(ShType::ProgBits), @@ -314,7 +314,7 @@ impl ShType_ { st if (SHT_LOOS..=SHT_HIOS).contains(&st) => Ok(ShType::OsSpecific(st)), st if (SHT_LOPROC..=SHT_HIPROC).contains(&st) => Ok(ShType::ProcessorSpecific(st)), st if (SHT_LOUSER..=SHT_HIUSER).contains(&st) => Ok(ShType::User(st)), - _ => Err("Invalid sh type"), + _ => Err(Error::InvalidSectionType), } } } @@ -558,7 +558,7 @@ impl NoteHeader { } } -pub fn sanity_check<'a>(header: SectionHeader<'a>, _file: &ElfFile<'a>) -> Result<(), &'static str> { +pub fn sanity_check<'a>(header: SectionHeader<'a>, _file: &ElfFile<'a>) -> Result<(), Error> { if header.get_type()? == ShType::Null { return Ok(()); } diff --git a/src/symbol_table.rs b/src/symbol_table.rs index e4cf08d..d944b7b 100644 --- a/src/symbol_table.rs +++ b/src/symbol_table.rs @@ -1,4 +1,5 @@ use ElfFile; +use crate::Error; use sections; use zero::Pod; @@ -60,7 +61,7 @@ pub trait Entry { fn value(&self) -> u64; fn size(&self) -> u64; - fn get_name<'a>(&'a self, elf_file: &ElfFile<'a>) -> Result<&'a str, &'static str>; + fn get_name<'a>(&'a self, elf_file: &ElfFile<'a>) -> Result<&'a str, Error>; fn get_other(&self) -> Visibility { self.other().as_visibility() @@ -77,7 +78,7 @@ pub trait Entry { fn get_section_header<'a>(&'a self, elf_file: &ElfFile<'a>, self_index: usize) - -> Result, &'static str> { + -> Result, Error> { match self.shndx() { sections::SHN_XINDEX => { // TODO factor out distinguished section names into sections consts @@ -92,15 +93,15 @@ pub trait Entry { assert_ne!(index, sections::SHN_UNDEF); elf_file.section_header(index) } else { - Err("Expected SymTabShIndex") + unreachable!("Expected SymTabShIndex") } } else { - Err("no .symtab_shndx section") + Err(Error::SymtabShndxNotFound) } } sections::SHN_UNDEF | sections::SHN_ABS | - sections::SHN_COMMON => Err("Reserved section header index"), + sections::SHN_COMMON => Err(Error::SectionHeaderIndexIsReserved), i => elf_file.section_header(i), } } @@ -123,7 +124,7 @@ impl fmt::Display for dyn Entry { macro_rules! impl_entry { ($name: ident with ElfFile::$strfunc: ident) => { impl Entry for $name { - fn get_name<'a>(&'a self, elf_file: &ElfFile<'a>) -> Result<&'a str, &'static str> { + fn get_name<'a>(&'a self, elf_file: &ElfFile<'a>) -> Result<&'a str, Error> { elf_file.$strfunc(self.name()) } From 8cd87dbfd385e9e3bed173d9aee51be0bbb5f511 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 5 Jul 2021 16:07:30 +0900 Subject: [PATCH 06/21] chore: return `Error` as `Err` --- src/error.rs | 23 +++++++++++++++++++++++ src/header.rs | 21 ++++++++++----------- src/lib.rs | 9 ++------- src/program.rs | 36 +++++++++++++++--------------------- 4 files changed, 50 insertions(+), 39 deletions(-) diff --git a/src/error.rs b/src/error.rs index 32d4aa9..b9b06e6 100644 --- a/src/error.rs +++ b/src/error.rs @@ -9,6 +9,12 @@ pub enum Error { InvalidClass, /// The section type is invalid. InvalidSectionType, + /// The segment type is invalid. + InvalidSegmentType, + /// The version of the given ELF file is invalid. + InvalidVersion, + /// The data format of the given ELF file is invalid. + InvalidDataFormat, /// The length of the given ELF file is too short. FileIsTooShort, /// Program header is not found. @@ -26,6 +32,16 @@ pub enum Error { /// - `SHN_ABS` /// - `SHN_COMMON` SectionHeaderIndexIsReserved, + /// The size of each program header recorded in the file header is different from the actual + /// size. + ProgramHeaderSizeMismatch, + /// The class specified in the file header is different from the actual class. + ClassMismatch, + /// The segment whose type is `PT_SHLIB` should not be used. + UseOfShLib, + /// The alignments of the virtual address, offset, and align recorded in the program header are + /// the invalid combination. + MisalignedAddressAndOffset, } impl fmt::Display for Error { @@ -37,6 +53,9 @@ impl fmt::Display for Error { Self::InvalidMagic => "The magic number of the given ELF file is invalid.", Self::InvalidClass => "The class of the given ELF file is invalid.", Self::InvalidSectionType => "The section type is invalid.", + Self::InvalidSegmentType => "The segment type is invalid.", + Self::InvalidVersion => "The version of the given ELF file is invalid.", + Self::InvalidDataFormat => "The data format of the given ELF file is invalid.", Self::FileIsTooShort => "The length of the given ELF file is too short.", Self::ProgramHeaderNotFound => "The program header is not found.", Self::SymtabShndxNotFound => "The `.symtab_shndx` section is not found.", @@ -44,6 +63,10 @@ impl fmt::Display for Error { Self::DynstrNotFound => "The `.dynstr` section is not found.", Self::SectionIsNull => "The section type is `NULL`.", Self::SectionHeaderIndexIsReserved => "The section header index is reserved.", + Self::ProgramHeaderSizeMismatch => "The size of each program header recorded in the file header is different from the actual size.", + Self::ClassMismatch => "The class specified in the file header is different from the actual class.", + Self::UseOfShLib => "The segment whose type is `PT_SHLIB` should not be used.", + Self::MisalignedAddressAndOffset => "The alignments of the virtual address, offset, and align recorded in the program header are the invalid combination.", } ) } diff --git a/src/header.rs b/src/header.rs index fe5fbc4..a0646ec 100644 --- a/src/header.rs +++ b/src/header.rs @@ -427,27 +427,26 @@ pub enum Machine { // TODO any more constants that need to go in here? -pub fn sanity_check(file: &ElfFile) -> Result<(), &'static str> { - check!(mem::size_of::() == 16); - check!(file.header.pt1.magic == MAGIC, "bad magic number"); +pub fn sanity_check(file: &ElfFile) -> Result<(), Error> { + // check!(mem::size_of::() == 16); + check!(file.header.pt1.magic == MAGIC, Error::InvalidMagic); let pt2 = &file.header.pt2; - check!(mem::size_of::() + pt2.size() == pt2.header_size() as usize, - "header_size does not match size of header"); + check!(mem::size_of::() + pt2.size() == pt2.header_size() as usize, Error::ProgramHeaderSizeMismatch); match (&file.header.pt1.class(), &file.header.pt2) { - (&Class::None, _) => return Err("No class"), + (&Class::None, _) => return Err(Error::InvalidClass), (&Class::ThirtyTwo, &HeaderPt2::Header32(_)) | (&Class::SixtyFour, &HeaderPt2::Header64(_)) => {} - _ => return Err("Mismatch between specified and actual class"), + _ => return Err(Error::ClassMismatch), } - check!(!file.header.pt1.version.is_none(), "no version"); - check!(!file.header.pt1.data.is_none(), "no data format"); + check!(!file.header.pt1.version.is_none(), Error::InvalidVersion); + check!(!file.header.pt1.data.is_none(), Error::InvalidDataFormat); check!(pt2.ph_offset() + (pt2.ph_entry_size() as u64) * (pt2.ph_count() as u64) <= file.input.len() as u64, - "program header table out of range"); + Error::FileIsTooShort); check!(pt2.sh_offset() + (pt2.sh_entry_size() as u64) * (pt2.sh_count() as u64) <= file.input.len() as u64, - "section header table out of range"); + Error::FileIsTooShort); // TODO check that SectionHeader_ is the same size as sh_entry_size, depending on class diff --git a/src/lib.rs b/src/lib.rs index 9a330ef..2ebe379 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,14 +5,9 @@ // TODO move to a module macro_rules! check { - ($e:expr) => { + ($e:expr, $err: expr) => { if !$e { - return Err(""); - } - }; - ($e:expr, $msg: expr) => { - if !$e { - return Err($msg); + return Err($err); } }; } diff --git a/src/program.rs b/src/program.rs index 8c4b456..4ce0c78 100644 --- a/src/program.rs +++ b/src/program.rs @@ -101,14 +101,14 @@ macro_rules! getter { } impl<'a> ProgramHeader<'a> { - pub fn get_type(&self) -> Result { + pub fn get_type(&self) -> Result { match *self { ProgramHeader::Ph32(ph) => ph.get_type(), ProgramHeader::Ph64(ph) => ph.get_type(), } } - pub fn get_data(&self, elf_file: &ElfFile<'a>) -> Result, &'static str> { + pub fn get_data(&self, elf_file: &ElfFile<'a>) -> Result, Error> { match *self { ProgramHeader::Ph32(ph) => ph.get_data(elf_file), ProgramHeader::Ph64(ph) => ph.get_data(elf_file), @@ -135,11 +135,11 @@ impl<'a> fmt::Display for ProgramHeader<'a> { macro_rules! ph_impl { ($ph: ident) => { impl $ph { - pub fn get_type(&self) -> Result { + pub fn get_type(&self) -> Result { self.type_.as_type() } - pub fn get_data<'a>(&self, elf_file: &ElfFile<'a>) -> Result, &'static str> { + pub fn get_data<'a>(&self, elf_file: &ElfFile<'a>) -> Result, Error> { self.get_type().map(|typ| match typ { Type::Null => SegmentData::Empty, Type::Load | Type::Interp | Type::ShLib | Type::Phdr | Type::Tls | @@ -256,7 +256,7 @@ pub enum Type { } impl Type_ { - fn as_type(&self) -> Result { + fn as_type(&self) -> Result { match self.0 { 0 => Ok(Type::Null), 1 => Ok(Type::Load), @@ -269,7 +269,7 @@ impl Type_ { TYPE_GNU_RELRO => Ok(Type::GnuRelro), t if (TYPE_LOOS..=TYPE_HIOS).contains(&t) => Ok(Type::OsSpecific(t)), t if (TYPE_LOPROC..=TYPE_HIPROC).contains(&t) => Ok(Type::ProcessorSpecific(t)), - _ => Err("Invalid type"), + _ => Err(Error::InvalidSegmentType), } } } @@ -303,30 +303,24 @@ pub const FLAG_R: u32 = 0x4; pub const FLAG_MASKOS: u32 = 0x0ff00000; pub const FLAG_MASKPROC: u32 = 0xf0000000; -pub fn sanity_check<'a>(ph: ProgramHeader<'a>, elf_file: &ElfFile<'a>) -> Result<(), &'static str> { +pub fn sanity_check<'a>(ph: ProgramHeader<'a>, elf_file: &ElfFile<'a>) -> Result<(), Error> { let header = elf_file.header; match ph { ProgramHeader::Ph32(ph) => { - check!(mem::size_of_val(ph) == header.pt2.ph_entry_size() as usize, - "program header size mismatch"); - check!(((ph.offset + ph.file_size) as usize) < elf_file.input.len(), - "entry point out of range"); - check!(ph.get_type()? != Type::ShLib, "Shouldn't use ShLib"); + check!(mem::size_of_val(ph) == header.pt2.ph_entry_size() as usize, Error::ProgramHeaderSizeMismatch); + check!(((ph.offset + ph.file_size) as usize) < elf_file.input.len(), Error::FileIsTooShort); + check!(ph.get_type()? != Type::ShLib, Error::UseOfShLib); if ph.align > 1 { - check!(ph.virtual_addr % ph.align == ph.offset % ph.align, - "Invalid combination of virtual_addr, offset, and align"); + check!(ph.virtual_addr % ph.align == ph.offset % ph.align, Error::MisalignedAddressAndOffset); } } ProgramHeader::Ph64(ph) => { - check!(mem::size_of_val(ph) == header.pt2.ph_entry_size() as usize, - "program header size mismatch"); - check!(((ph.offset + ph.file_size) as usize) < elf_file.input.len(), - "entry point out of range"); - check!(ph.get_type()? != Type::ShLib, "Shouldn't use ShLib"); + check!(mem::size_of_val(ph) == header.pt2.ph_entry_size() as usize, Error::ProgramHeaderSizeMismatch); + check!(((ph.offset + ph.file_size) as usize) < elf_file.input.len(), Error::FileIsTooShort); + check!(ph.get_type()? != Type::ShLib, Error::UseOfShLib); if ph.align > 1 { // println!("{} {} {}", ph.virtual_addr, ph.offset, ph.align); - check!(ph.virtual_addr % ph.align == ph.offset % ph.align, - "Invalid combination of virtual_addr, offset, and align"); + check!(ph.virtual_addr % ph.align == ph.offset % ph.align, Error::MisalignedAddressAndOffset); } } } From ee5cbd26df14139a4dd7c26a5ef9d695b59c4626 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 5 Jul 2021 16:10:42 +0900 Subject: [PATCH 07/21] chore: statically check the size of `HeaderPt1` --- src/header.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/header.rs b/src/header.rs index a0646ec..5da5de6 100644 --- a/src/header.rs +++ b/src/header.rs @@ -83,6 +83,8 @@ pub struct HeaderPt1 { pub padding: [u8; 7], } +const _CONST_CHECK_HEADER_PT1_SIZE: [(); !(mem::size_of::() == 16) as usize] = []; + unsafe impl Pod for HeaderPt1 {} impl HeaderPt1 { @@ -428,7 +430,6 @@ pub enum Machine { // TODO any more constants that need to go in here? pub fn sanity_check(file: &ElfFile) -> Result<(), Error> { - // check!(mem::size_of::() == 16); check!(file.header.pt1.magic == MAGIC, Error::InvalidMagic); let pt2 = &file.header.pt2; check!(mem::size_of::() + pt2.size() == pt2.header_size() as usize, Error::ProgramHeaderSizeMismatch); From 293f91bd1a31d47b53fc3153b44b02306b13ba2e Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 5 Jul 2021 16:13:37 +0900 Subject: [PATCH 08/21] chore(get_binding): return `Error` as `Err` --- src/error.rs | 3 +++ src/symbol_table.rs | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/error.rs b/src/error.rs index b9b06e6..81c7dbe 100644 --- a/src/error.rs +++ b/src/error.rs @@ -15,6 +15,8 @@ pub enum Error { InvalidVersion, /// The data format of the given ELF file is invalid. InvalidDataFormat, + /// The symbol's binding is invalid. + InvalidSymbolBinding, /// The length of the given ELF file is too short. FileIsTooShort, /// Program header is not found. @@ -56,6 +58,7 @@ impl fmt::Display for Error { Self::InvalidSegmentType => "The segment type is invalid.", Self::InvalidVersion => "The version of the given ELF file is invalid.", Self::InvalidDataFormat => "The data format of the given ELF file is invalid.", + Self::InvalidSymbolBinding => "The symbol's binding is invalid.", Self::FileIsTooShort => "The length of the given ELF file is too short.", Self::ProgramHeaderNotFound => "The program header is not found.", Self::SymtabShndxNotFound => "The `.symtab_shndx` section is not found.", diff --git a/src/symbol_table.rs b/src/symbol_table.rs index d944b7b..7759ad9 100644 --- a/src/symbol_table.rs +++ b/src/symbol_table.rs @@ -67,7 +67,7 @@ pub trait Entry { self.other().as_visibility() } - fn get_binding(&self) -> Result { + fn get_binding(&self) -> Result { Binding_(self.info() >> 4).as_binding() } @@ -179,14 +179,14 @@ pub enum Binding { } impl Binding_ { - pub fn as_binding(self) -> Result { + pub fn as_binding(self) -> Result { match self.0 { 0 => Ok(Binding::Local), 1 => Ok(Binding::Global), 2 => Ok(Binding::Weak), b if (10..=12).contains(&b) => Ok(Binding::OsSpecific(b)), b if (13..=15).contains(&b) => Ok(Binding::ProcessorSpecific(b)), - _ => Err("Invalid value for binding"), + _ => Err(Error::InvalidSymbolBinding), } } } From e645fad4e91920295e61e13c8e68255191908d14 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 5 Jul 2021 16:17:38 +0900 Subject: [PATCH 09/21] chore(get_type): return `Error` as `Err` --- src/error.rs | 3 +++ src/symbol_table.rs | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/error.rs b/src/error.rs index 81c7dbe..45dc7ef 100644 --- a/src/error.rs +++ b/src/error.rs @@ -17,6 +17,8 @@ pub enum Error { InvalidDataFormat, /// The symbol's binding is invalid. InvalidSymbolBinding, + /// The symbol's type is invalid. + InvalidSymbolType, /// The length of the given ELF file is too short. FileIsTooShort, /// Program header is not found. @@ -59,6 +61,7 @@ impl fmt::Display for Error { Self::InvalidVersion => "The version of the given ELF file is invalid.", Self::InvalidDataFormat => "The data format of the given ELF file is invalid.", Self::InvalidSymbolBinding => "The symbol's binding is invalid.", + Self::InvalidSymbolType => "The symbol's type is invalid.", Self::FileIsTooShort => "The length of the given ELF file is too short.", Self::ProgramHeaderNotFound => "The program header is not found.", Self::SymtabShndxNotFound => "The `.symtab_shndx` section is not found.", diff --git a/src/symbol_table.rs b/src/symbol_table.rs index 7759ad9..aef3f1a 100644 --- a/src/symbol_table.rs +++ b/src/symbol_table.rs @@ -71,7 +71,7 @@ pub trait Entry { Binding_(self.info() >> 4).as_binding() } - fn get_type(&self) -> Result { + fn get_type(&self) -> Result { Type_(self.info() & 0xf).as_type() } @@ -209,7 +209,7 @@ pub enum Type { } impl Type_ { - pub fn as_type(self) -> Result { + pub fn as_type(self) -> Result { match self.0 { 0 => Ok(Type::NoType), 1 => Ok(Type::Object), @@ -220,7 +220,7 @@ impl Type_ { 6 => Ok(Type::Tls), b if (10..=12).contains(&b) => Ok(Type::OsSpecific(b)), b if (13..=15).contains(&b) => Ok(Type::ProcessorSpecific(b)), - _ => Err("Invalid value for type"), + _ => Err(Error::InvalidSymbolType), } } } From 27871f50ebfb2b1698351c8bb2b964fc8cc6a30c Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 5 Jul 2021 16:44:57 +0900 Subject: [PATCH 10/21] chore: return `Error` as `Err` --- src/error.rs | 3 +++ src/sections.rs | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/error.rs b/src/error.rs index 45dc7ef..afcfd59 100644 --- a/src/error.rs +++ b/src/error.rs @@ -19,6 +19,8 @@ pub enum Error { InvalidSymbolBinding, /// The symbol's type is invalid. InvalidSymbolType, + /// The compression type is invalid. + InvalidCompressionType, /// The length of the given ELF file is too short. FileIsTooShort, /// Program header is not found. @@ -62,6 +64,7 @@ impl fmt::Display for Error { Self::InvalidDataFormat => "The data format of the given ELF file is invalid.", Self::InvalidSymbolBinding => "The symbol's binding is invalid.", Self::InvalidSymbolType => "The symbol's type is invalid.", + Self::InvalidCompressionType => "The compression type is invalid.", Self::FileIsTooShort => "The length of the given ELF file is too short.", Self::ProgramHeaderNotFound => "The program header is not found.", Self::SymtabShndxNotFound => "The `.symtab_shndx` section is not found.", diff --git a/src/sections.rs b/src/sections.rs index f4d6d48..836bb01 100644 --- a/src/sections.rs +++ b/src/sections.rs @@ -428,14 +428,14 @@ pub enum CompressionType { } impl CompressionType_ { - fn as_compression_type(&self) -> Result { + fn as_compression_type(&self) -> Result { match self.0 { 1 => Ok(CompressionType::Zlib), ct if (COMPRESS_LOOS..=COMPRESS_HIOS).contains(&ct) => Ok(CompressionType::OsSpecific(ct)), ct if (COMPRESS_LOPROC..=COMPRESS_HIPROC).contains(&ct) => { Ok(CompressionType::ProcessorSpecific(ct)) } - _ => Err("Invalid compression type"), + _ => Err(Error::InvalidCompressionType), } } } From 0a1410d0d11863bf2275aaffb1dd1f73461d5184 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 5 Jul 2021 16:55:23 +0900 Subject: [PATCH 11/21] chore: return `Error` as `Err` --- src/error.rs | 6 ++++++ src/sections.rs | 10 +++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/error.rs b/src/error.rs index afcfd59..d95cc2a 100644 --- a/src/error.rs +++ b/src/error.rs @@ -23,6 +23,8 @@ pub enum Error { InvalidCompressionType, /// The length of the given ELF file is too short. FileIsTooShort, + /// The length of the section is too short. + SectionIsTooShort, /// Program header is not found. ProgramHeaderNotFound, /// The `.symtab_shndx` section is not found. @@ -48,6 +50,8 @@ pub enum Error { /// The alignments of the virtual address, offset, and align recorded in the program header are /// the invalid combination. MisalignedAddressAndOffset, + /// Failed to decompress the section. + DecompressionError, } impl fmt::Display for Error { @@ -66,6 +70,7 @@ impl fmt::Display for Error { Self::InvalidSymbolType => "The symbol's type is invalid.", Self::InvalidCompressionType => "The compression type is invalid.", Self::FileIsTooShort => "The length of the given ELF file is too short.", + Self::SectionIsTooShort => "The length of the section is too short.", Self::ProgramHeaderNotFound => "The program header is not found.", Self::SymtabShndxNotFound => "The `.symtab_shndx` section is not found.", Self::StrtabNotFound => "The `.strtab` section is not found.", @@ -76,6 +81,7 @@ impl fmt::Display for Error { Self::ClassMismatch => "The class specified in the file header is different from the actual class.", Self::UseOfShLib => "The segment whose type is `PT_SHLIB` should not be used.", Self::MisalignedAddressAndOffset => "The alignments of the virtual address, offset, and align recorded in the program header are the invalid combination.", + Self::DecompressionError => "Failed to decompress the section.", } ) } diff --git a/src/sections.rs b/src/sections.rs index 836bb01..924d515 100644 --- a/src/sections.rs +++ b/src/sections.rs @@ -173,7 +173,7 @@ impl<'a> SectionHeader<'a> { } #[cfg(feature = "compression")] - pub fn decompressed_data(&self, elf_file: &ElfFile<'a>) -> Result, &'static str> { + pub fn decompressed_data(&self, elf_file: &ElfFile<'a>) -> Result, Error> { let raw = self.raw_data(elf_file); Ok(if (self.flags() & SHF_COMPRESSED) == 0 { Cow::Borrowed(raw) @@ -181,14 +181,14 @@ impl<'a> SectionHeader<'a> { let (compression_type, size, compressed_data) = match elf_file.header.pt1.class() { Class::ThirtyTwo => { if raw.len() < 12 { - return Err("Unexpected EOF in compressed section"); + return Err(Error::SectionIsTooShort); } let header: &'a CompressionHeader32 = read(&raw[..12]); (header.type_.as_compression_type(), header.size as usize, &raw[12..]) }, Class::SixtyFour => { if raw.len() < 24 { - return Err("Unexpected EOF in compressed section"); + return Err(Error::SectionIsTooShort); } let header: &'a CompressionHeader64 = read(&raw[..24]); (header.type_.as_compression_type(), header.size as usize, &raw[24..]) @@ -197,14 +197,14 @@ impl<'a> SectionHeader<'a> { }; if compression_type != Ok(CompressionType::Zlib) { - return Err("Unknown compression type"); + return Err(Error::InvalidCompressionType); } let mut decompressed = Vec::with_capacity(size); let mut decompress = Decompress::new(true); if let Err(_) = decompress.decompress_vec( compressed_data, &mut decompressed, FlushDecompress::Finish) { - return Err("Decompression error"); + return Err(Error::DecompressionError); } Cow::Owned(decompressed) }) From adfcd6206c9e0dc67fd70ddb3b7c0eeac0e30de2 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 6 Jul 2021 10:30:57 +0900 Subject: [PATCH 12/21] chore: return `Error` as `Err` --- src/dynamic.rs | 15 ++++++++------- src/error.rs | 9 +++++++++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/dynamic.rs b/src/dynamic.rs index e15e200..3b061fb 100644 --- a/src/dynamic.rs +++ b/src/dynamic.rs @@ -1,6 +1,7 @@ use core::fmt; use {P32, P64}; use zero::Pod; +use crate::Error; #[derive(Debug)] #[repr(C)] @@ -58,34 +59,34 @@ pub enum Tag

{ macro_rules! impls { ($p: ident) => { impl Dynamic<$p> { - pub fn get_tag(&self) -> Result, &'static str> { + pub fn get_tag(&self) -> Result, Error> { self.tag.as_tag() } - pub fn get_val(&self) -> Result<$p, &'static str> { + pub fn get_val(&self) -> Result<$p, Error> { match self.get_tag()? { Tag::Needed | Tag::PltRelSize | Tag::RelaSize | Tag::RelaEnt | Tag::StrSize | Tag::SymEnt | Tag::SoName | Tag::RPath | Tag::RelSize | Tag::RelEnt | Tag::PltRel | Tag::InitArraySize | Tag::FiniArraySize | Tag::RunPath | Tag::Flags | Tag::PreInitArraySize | Tag::Flags1 | Tag::OsSpecific(_) | Tag::ProcessorSpecific(_) => Ok(self.un), - _ => Err("Invalid value"), + _ => Err(Error::ValueIsNotContained), } } - pub fn get_ptr(&self) -> Result<$p, &'static str> { + pub fn get_ptr(&self) -> Result<$p, Error> { match self.get_tag()? { Tag::Pltgot | Tag::Hash | Tag::StrTab | Tag::SymTab | Tag::Rela | Tag::Init | Tag::Fini | Tag::Rel | Tag::Debug | Tag::JmpRel | Tag::InitArray | Tag::FiniArray | Tag::PreInitArray | Tag::SymTabShIndex | Tag::OsSpecific(_) | Tag::ProcessorSpecific(_) => Ok(self.un), - _ => Err("Invalid ptr"), + _ => Err(Error::PointerIsNotContained), } } } impl Tag_<$p> { - fn as_tag(self) -> Result, &'static str> { + fn as_tag(self) -> Result, Error> { match self.0 { 0 => Ok(Tag::Null), 1 => Ok(Tag::Needed), @@ -124,7 +125,7 @@ macro_rules! impls { 0x6ffffffb => Ok(Tag::Flags1), t if (0x6000000D..0x70000000).contains(&t) => Ok(Tag::OsSpecific(t)), t if (0x70000000..0x80000000).contains(&t) => Ok(Tag::ProcessorSpecific(t)), - _ => Err("Invalid tag value"), + _ => Err(Error::InvalidTag), } } } diff --git a/src/error.rs b/src/error.rs index d95cc2a..9c2c7d4 100644 --- a/src/error.rs +++ b/src/error.rs @@ -21,6 +21,8 @@ pub enum Error { InvalidSymbolType, /// The compression type is invalid. InvalidCompressionType, + /// The tag of this dynamic link information is invalid. + InvalidTag, /// The length of the given ELF file is too short. FileIsTooShort, /// The length of the section is too short. @@ -52,6 +54,10 @@ pub enum Error { MisalignedAddressAndOffset, /// Failed to decompress the section. DecompressionError, + /// This dynamic link information does not contain a value, but a pointer. + ValueIsNotContained, + /// This dynamic link information does not contain a pointer, but a value. + PointerIsNotContained, } impl fmt::Display for Error { @@ -69,6 +75,7 @@ impl fmt::Display for Error { Self::InvalidSymbolBinding => "The symbol's binding is invalid.", Self::InvalidSymbolType => "The symbol's type is invalid.", Self::InvalidCompressionType => "The compression type is invalid.", + Self::InvalidTag => "The tag of this dynamic link information is invalid.", Self::FileIsTooShort => "The length of the given ELF file is too short.", Self::SectionIsTooShort => "The length of the section is too short.", Self::ProgramHeaderNotFound => "The program header is not found.", @@ -82,6 +89,8 @@ impl fmt::Display for Error { Self::UseOfShLib => "The segment whose type is `PT_SHLIB` should not be used.", Self::MisalignedAddressAndOffset => "The alignments of the virtual address, offset, and align recorded in the program header are the invalid combination.", Self::DecompressionError => "Failed to decompress the section.", + Self::ValueIsNotContained => "This dynamic link information does not contain a value, but a pointer.", + Self::PointerIsNotContained => "This dynamic link information does not contain a pointer, but a value.", } ) } From c585123e500c3b2ddb39d709bd88368679f5d791 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 6 Jul 2021 10:35:13 +0900 Subject: [PATCH 13/21] chore: remove `is` from error types --- src/error.rs | 24 ++++++++++++------------ src/header.rs | 10 +++++----- src/program.rs | 4 ++-- src/sections.rs | 2 +- src/symbol_table.rs | 2 +- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/error.rs b/src/error.rs index 9c2c7d4..6912c6b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -24,9 +24,9 @@ pub enum Error { /// The tag of this dynamic link information is invalid. InvalidTag, /// The length of the given ELF file is too short. - FileIsTooShort, + FileTooShort, /// The length of the section is too short. - SectionIsTooShort, + SectionTooShort, /// Program header is not found. ProgramHeaderNotFound, /// The `.symtab_shndx` section is not found. @@ -36,12 +36,12 @@ pub enum Error { /// The `.dynstr` section is not found. DynstrNotFound, /// The section type is `NULL`. - SectionIsNull, + NullSection, /// The section header index is one of the followings: /// - `SHN_UNDEF` /// - `SHN_ABS` /// - `SHN_COMMON` - SectionHeaderIndexIsReserved, + ReservedSectionHeaderIndex, /// The size of each program header recorded in the file header is different from the actual /// size. ProgramHeaderSizeMismatch, @@ -55,9 +55,9 @@ pub enum Error { /// Failed to decompress the section. DecompressionError, /// This dynamic link information does not contain a value, but a pointer. - ValueIsNotContained, + ValueNotContained, /// This dynamic link information does not contain a pointer, but a value. - PointerIsNotContained, + PointerNotContained, } impl fmt::Display for Error { @@ -76,21 +76,21 @@ impl fmt::Display for Error { Self::InvalidSymbolType => "The symbol's type is invalid.", Self::InvalidCompressionType => "The compression type is invalid.", Self::InvalidTag => "The tag of this dynamic link information is invalid.", - Self::FileIsTooShort => "The length of the given ELF file is too short.", - Self::SectionIsTooShort => "The length of the section is too short.", + Self::FileTooShort => "The length of the given ELF file is too short.", + Self::SectionTooShort => "The length of the section is too short.", Self::ProgramHeaderNotFound => "The program header is not found.", Self::SymtabShndxNotFound => "The `.symtab_shndx` section is not found.", Self::StrtabNotFound => "The `.strtab` section is not found.", Self::DynstrNotFound => "The `.dynstr` section is not found.", - Self::SectionIsNull => "The section type is `NULL`.", - Self::SectionHeaderIndexIsReserved => "The section header index is reserved.", + Self::NullSection => "The section type is `NULL`.", + Self::ReservedSectionHeaderIndex => "The section header index is reserved.", Self::ProgramHeaderSizeMismatch => "The size of each program header recorded in the file header is different from the actual size.", Self::ClassMismatch => "The class specified in the file header is different from the actual class.", Self::UseOfShLib => "The segment whose type is `PT_SHLIB` should not be used.", Self::MisalignedAddressAndOffset => "The alignments of the virtual address, offset, and align recorded in the program header are the invalid combination.", Self::DecompressionError => "Failed to decompress the section.", - Self::ValueIsNotContained => "This dynamic link information does not contain a value, but a pointer.", - Self::PointerIsNotContained => "This dynamic link information does not contain a pointer, but a value.", + Self::ValueNotContained => "This dynamic link information does not contain a value, but a pointer.", + Self::PointerNotContained => "This dynamic link information does not contain a pointer, but a value.", } ) } diff --git a/src/header.rs b/src/header.rs index 5da5de6..4dd826e 100644 --- a/src/header.rs +++ b/src/header.rs @@ -10,7 +10,7 @@ use zero::{read, Pod}; pub fn parse_header<'a>(input: &'a [u8]) -> Result, Error> { let size_pt1 = mem::size_of::(); if input.len() < size_pt1 { - return Err(Error::FileIsTooShort); + return Err(Error::FileTooShort); } let header_1: &'a HeaderPt1 = read(&input[..size_pt1]); @@ -23,7 +23,7 @@ pub fn parse_header<'a>(input: &'a [u8]) -> Result, Error> { Class::ThirtyTwo => { let size_pt2 = mem::size_of::>(); if input.len() < size_pt1 + size_pt2 { - return Err(Error::FileIsTooShort); + return Err(Error::FileTooShort); } let header_2: &'a HeaderPt2_ = read(&input[size_pt1..size_pt1 + mem::size_of::>()]); @@ -32,7 +32,7 @@ pub fn parse_header<'a>(input: &'a [u8]) -> Result, Error> { Class::SixtyFour => { let size_pt2 = mem::size_of::>(); if input.len() < size_pt1 + size_pt2 { - return Err(Error::FileIsTooShort); + return Err(Error::FileTooShort); } let header_2: &'a HeaderPt2_ = read(&input[size_pt1..size_pt1 + mem::size_of::>()]); @@ -444,10 +444,10 @@ pub fn sanity_check(file: &ElfFile) -> Result<(), Error> { check!(pt2.ph_offset() + (pt2.ph_entry_size() as u64) * (pt2.ph_count() as u64) <= file.input.len() as u64, - Error::FileIsTooShort); + Error::FileTooShort); check!(pt2.sh_offset() + (pt2.sh_entry_size() as u64) * (pt2.sh_count() as u64) <= file.input.len() as u64, - Error::FileIsTooShort); + Error::FileTooShort); // TODO check that SectionHeader_ is the same size as sh_entry_size, depending on class diff --git a/src/program.rs b/src/program.rs index 4ce0c78..571eb4d 100644 --- a/src/program.rs +++ b/src/program.rs @@ -308,7 +308,7 @@ pub fn sanity_check<'a>(ph: ProgramHeader<'a>, elf_file: &ElfFile<'a>) -> Result match ph { ProgramHeader::Ph32(ph) => { check!(mem::size_of_val(ph) == header.pt2.ph_entry_size() as usize, Error::ProgramHeaderSizeMismatch); - check!(((ph.offset + ph.file_size) as usize) < elf_file.input.len(), Error::FileIsTooShort); + check!(((ph.offset + ph.file_size) as usize) < elf_file.input.len(), Error::FileTooShort); check!(ph.get_type()? != Type::ShLib, Error::UseOfShLib); if ph.align > 1 { check!(ph.virtual_addr % ph.align == ph.offset % ph.align, Error::MisalignedAddressAndOffset); @@ -316,7 +316,7 @@ pub fn sanity_check<'a>(ph: ProgramHeader<'a>, elf_file: &ElfFile<'a>) -> Result } ProgramHeader::Ph64(ph) => { check!(mem::size_of_val(ph) == header.pt2.ph_entry_size() as usize, Error::ProgramHeaderSizeMismatch); - check!(((ph.offset + ph.file_size) as usize) < elf_file.input.len(), Error::FileIsTooShort); + check!(((ph.offset + ph.file_size) as usize) < elf_file.input.len(), Error::FileTooShort); check!(ph.get_type()? != Type::ShLib, Error::UseOfShLib); if ph.align > 1 { // println!("{} {} {}", ph.virtual_addr, ph.offset, ph.align); diff --git a/src/sections.rs b/src/sections.rs index 924d515..c4f4f8e 100644 --- a/src/sections.rs +++ b/src/sections.rs @@ -97,7 +97,7 @@ impl<'a> SectionHeader<'a> { // Note that this function is O(n) in the length of the name. pub fn get_name(&self, elf_file: &ElfFile<'a>) -> Result<&'a str, Error> { self.get_type().and_then(|typ| match typ { - ShType::Null => Err(Error::SectionIsNull), + ShType::Null => Err(Error::NullSection), _ => elf_file.get_shstr(self.name()), }) } diff --git a/src/symbol_table.rs b/src/symbol_table.rs index aef3f1a..bfdca38 100644 --- a/src/symbol_table.rs +++ b/src/symbol_table.rs @@ -101,7 +101,7 @@ pub trait Entry { } sections::SHN_UNDEF | sections::SHN_ABS | - sections::SHN_COMMON => Err(Error::SectionHeaderIndexIsReserved), + sections::SHN_COMMON => Err(Error::ReservedSectionHeaderIndex), i => elf_file.section_header(i), } } From 69fdd043736447ca880ec9ef07b117334ca1c175 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 6 Jul 2021 10:37:04 +0900 Subject: [PATCH 14/21] fix: forgot to remove `is` --- src/dynamic.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dynamic.rs b/src/dynamic.rs index 3b061fb..9631eb1 100644 --- a/src/dynamic.rs +++ b/src/dynamic.rs @@ -70,7 +70,7 @@ macro_rules! impls { Tag::InitArraySize | Tag::FiniArraySize | Tag::RunPath | Tag::Flags | Tag::PreInitArraySize | Tag::Flags1 | Tag::OsSpecific(_) | Tag::ProcessorSpecific(_) => Ok(self.un), - _ => Err(Error::ValueIsNotContained), + _ => Err(Error::ValueNotContained), } } @@ -80,7 +80,7 @@ macro_rules! impls { Tag::Rel | Tag::Debug | Tag::JmpRel | Tag::InitArray | Tag::FiniArray | Tag::PreInitArray | Tag::SymTabShIndex | Tag::OsSpecific(_) | Tag::ProcessorSpecific(_) => Ok(self.un), - _ => Err(Error::PointerIsNotContained), + _ => Err(Error::PointerNotContained), } } } From baaae0ba06e055a129f0528c4435113bb7ae9b78 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 6 Jul 2021 10:38:03 +0900 Subject: [PATCH 15/21] fix: forgot to remove `is` --- src/sections.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sections.rs b/src/sections.rs index c4f4f8e..2782017 100644 --- a/src/sections.rs +++ b/src/sections.rs @@ -181,14 +181,14 @@ impl<'a> SectionHeader<'a> { let (compression_type, size, compressed_data) = match elf_file.header.pt1.class() { Class::ThirtyTwo => { if raw.len() < 12 { - return Err(Error::SectionIsTooShort); + return Err(Error::SectionTooShort); } let header: &'a CompressionHeader32 = read(&raw[..12]); (header.type_.as_compression_type(), header.size as usize, &raw[12..]) }, Class::SixtyFour => { if raw.len() < 24 { - return Err(Error::SectionIsTooShort); + return Err(Error::SectionTooShort); } let header: &'a CompressionHeader64 = read(&raw[..24]); (header.type_.as_compression_type(), header.size as usize, &raw[24..]) From 085ba60771ed75f214278f8abb52fb35f616cc70 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 6 Jul 2021 11:07:04 +0900 Subject: [PATCH 16/21] docs: use `the` instead of `this` --- src/error.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/error.rs b/src/error.rs index 6912c6b..dab7cf3 100644 --- a/src/error.rs +++ b/src/error.rs @@ -21,7 +21,7 @@ pub enum Error { InvalidSymbolType, /// The compression type is invalid. InvalidCompressionType, - /// The tag of this dynamic link information is invalid. + /// The tag of the dynamic link information is invalid. InvalidTag, /// The length of the given ELF file is too short. FileTooShort, @@ -54,9 +54,9 @@ pub enum Error { MisalignedAddressAndOffset, /// Failed to decompress the section. DecompressionError, - /// This dynamic link information does not contain a value, but a pointer. + /// The dynamic link information does not contain a value, but a pointer. ValueNotContained, - /// This dynamic link information does not contain a pointer, but a value. + /// The dynamic link information does not contain a pointer, but a value. PointerNotContained, } @@ -75,7 +75,7 @@ impl fmt::Display for Error { Self::InvalidSymbolBinding => "The symbol's binding is invalid.", Self::InvalidSymbolType => "The symbol's type is invalid.", Self::InvalidCompressionType => "The compression type is invalid.", - Self::InvalidTag => "The tag of this dynamic link information is invalid.", + Self::InvalidTag => "The tag of the dynamic link information is invalid.", Self::FileTooShort => "The length of the given ELF file is too short.", Self::SectionTooShort => "The length of the section is too short.", Self::ProgramHeaderNotFound => "The program header is not found.", @@ -89,8 +89,8 @@ impl fmt::Display for Error { Self::UseOfShLib => "The segment whose type is `PT_SHLIB` should not be used.", Self::MisalignedAddressAndOffset => "The alignments of the virtual address, offset, and align recorded in the program header are the invalid combination.", Self::DecompressionError => "Failed to decompress the section.", - Self::ValueNotContained => "This dynamic link information does not contain a value, but a pointer.", - Self::PointerNotContained => "This dynamic link information does not contain a pointer, but a value.", + Self::ValueNotContained => "The dynamic link information does not contain a value, but a pointer.", + Self::PointerNotContained => "The dynamic link information does not contain a pointer, but a value.", } ) } From ed45cd91d98fe8301605d6f014cac2fb1e56b387 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 6 Jul 2021 11:47:41 +0900 Subject: [PATCH 17/21] chore(get_string): use `assert_eq!` `get_section_header` does the same thing. --- src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2ebe379..fabb1be 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -76,9 +76,9 @@ impl<'a> ElfFile<'a> { pub fn get_string(&self, index: u32) -> Result<&'a str, Error> { let header = self.find_section_by_name(".strtab").ok_or(Error::StrtabNotFound)?; - if header.get_type()? != sections::ShType::StrTab { - unreachable!("expected .strtab to be StrTab"); - } + + assert_eq!(header.get_type()?, sections::ShType::StrTab); + Ok(read_str(&header.raw_data(self)[(index as usize)..])) } From dcea4ec010ee030d9b27d87dfa4500b7696ecbb8 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 6 Jul 2021 11:49:04 +0900 Subject: [PATCH 18/21] chore: add a panic message --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index fabb1be..1e85453 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -77,7 +77,7 @@ impl<'a> ElfFile<'a> { pub fn get_string(&self, index: u32) -> Result<&'a str, Error> { let header = self.find_section_by_name(".strtab").ok_or(Error::StrtabNotFound)?; - assert_eq!(header.get_type()?, sections::ShType::StrTab); + assert_eq!(header.get_type()?, sections::ShType::StrTab, "expected .strtab to be StrTab"); Ok(read_str(&header.raw_data(self)[(index as usize)..])) } From 121da958cbcd473c724df1a064b4b4638470a4d7 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Tue, 6 Jul 2021 11:55:24 +0900 Subject: [PATCH 19/21] chore(Error): implement `PartialOrd` and `Ord` --- src/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/error.rs b/src/error.rs index dab7cf3..9212a33 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,7 +1,7 @@ use core::fmt; /// Errors returned by the methods and functions of this crate. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Error { /// The magic number of the given ELF file is invalid. InvalidMagic, From 18d0c74d8380627364e14bfbb218ddb85e70b568 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 2 Aug 2021 10:10:50 +0900 Subject: [PATCH 20/21] chore(sections): return `Error` as `Err` --- src/error.rs | 3 +++ src/sections.rs | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/error.rs b/src/error.rs index 9212a33..e8d5f45 100644 --- a/src/error.rs +++ b/src/error.rs @@ -58,6 +58,8 @@ pub enum Error { ValueNotContained, /// The dynamic link information does not contain a pointer, but a value. PointerNotContained, + /// 32-bit binaries are not supported. + Binary32BitNotSupported, } impl fmt::Display for Error { @@ -91,6 +93,7 @@ impl fmt::Display for Error { Self::DecompressionError => "Failed to decompress the section.", Self::ValueNotContained => "The dynamic link information does not contain a value, but a pointer.", Self::PointerNotContained => "The dynamic link information does not contain a pointer, but a value.", + Self::Binary32BitNotSupported => "The 32-bit binaries are not supported.", } ) } diff --git a/src/sections.rs b/src/sections.rs index 2782017..d6dd22b 100644 --- a/src/sections.rs +++ b/src/sections.rs @@ -151,13 +151,13 @@ impl<'a> SectionHeader<'a> { ShType::Note => { let data = self.raw_data(elf_file); match elf_file.header.pt1.class() { - Class::ThirtyTwo => return Err("32-bit binaries not implemented"), + Class::ThirtyTwo => return Err(Error::Binary32BitNotSupported), Class::SixtyFour => { let header: &'a NoteHeader = read(&data[0..12]); let index = &data[12..]; SectionData::Note64(header, index) } - Class::None | Class::Other(_) => return Err("Unknown ELF class"), + Class::None | Class::Other(_) => return Err(Error::InvalidClass), } } ShType::Hash => { From 1a74804d96b361ea6cbfe818c2e2de94f1cc408e Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Mon, 2 Aug 2021 10:12:14 +0900 Subject: [PATCH 21/21] chore(error): add `The` --- src/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/error.rs b/src/error.rs index e8d5f45..582e9ad 100644 --- a/src/error.rs +++ b/src/error.rs @@ -58,7 +58,7 @@ pub enum Error { ValueNotContained, /// The dynamic link information does not contain a pointer, but a value. PointerNotContained, - /// 32-bit binaries are not supported. + /// The 32-bit binaries are not supported. Binary32BitNotSupported, }