From 56b682fd70aa3c1f8965aacdc625d56be48007e0 Mon Sep 17 00:00:00 2001 From: Kitlith Date: Fri, 6 Dec 2019 15:36:49 -0800 Subject: [PATCH 1/3] WIP support for custom permissions for custom sections. --- src/artifact/decl.rs | 78 ++++++++++++++++++++++++++++++++++++++++++++ src/elf.rs | 40 +++++++++++------------ 2 files changed, 97 insertions(+), 21 deletions(-) diff --git a/src/artifact/decl.rs b/src/artifact/decl.rs index 9b101c5..2be5974 100644 --- a/src/artifact/decl.rs +++ b/src/artifact/decl.rs @@ -219,6 +219,24 @@ impl DefinedDecl { } } + /// Accessor to determine whether contents are executable + pub fn is_executable(&self) -> bool { + match self { + DefinedDecl::Section(a) => a.is_executable(), + DefinedDecl::Function(_) => true, + DefinedDecl::Data(_) => false, + } + } + + /// Accessor to determine whether contents will be loaded at runtime + pub fn is_loaded(&self) -> bool { + match self { + DefinedDecl::Section(a) => a.is_loaded(), + DefinedDecl::Function(_) => true, + DefinedDecl::Data(_) => true, + } + } + /// Accessor to determine the minimal alignment pub fn get_align(&self) -> Option { match self { @@ -500,6 +518,9 @@ pub struct SectionDecl { kind: SectionKind, datatype: DataType, align: Option, + writable: Option, + executable: Option, + loaded: bool } impl SectionDecl { @@ -512,6 +533,9 @@ impl SectionDecl { kind, datatype: DataType::Bytes, align: None, + writable: None, + executable: None, + loaded: false } } @@ -521,14 +545,68 @@ impl SectionDecl { false } + /// Setter for writability + pub fn set_writable(&mut self, writable: bool) { + self.writable = Some(writable); + } + + /// Builder for writability + pub fn with_writable(mut self, writable: bool) -> Self { + self.writable = Some(writable); + self + } + /// Accessor to determine whether contents are writable pub fn is_writable(&self) -> bool { + if let Some(writable) = self.writable { + return writable; + } + match self.kind { SectionKind::Data => true, SectionKind::Debug | SectionKind::Text => false, } } + /// Setter for executability + pub fn set_executable(&mut self, executable: bool) { + self.executable = Some(executable); + } + + /// Builder for executability + pub fn with_executable(mut self, executable: bool) -> Self { + self.executable = Some(executable); + self + } + + /// Accessor to determine whether contents are executable + pub fn is_executable(&self) -> bool { + if let Some(executable) = self.executable { + return executable; + } + + match self.kind { + SectionKind::Text => true, + SectionKind::Data | SectionKind::Debug => false, + } + } + + /// Setter for loadability + pub fn set_loaded(&mut self, loaded: bool) { + self.loaded = loaded; + } + + /// Builder for loadabliity + pub fn with_loaded(mut self, loaded: bool) -> Self { + self.loaded = loaded; + self + } + + /// Accessor to determine whether contents are loaded at runtime + pub fn is_loaded(&self) -> bool { + self.loaded + } + /// Get the kind for this `SectionDecl` pub fn kind(&self) -> SectionKind { self.kind diff --git a/src/elf.rs b/src/elf.rs index c681586..9254747 100644 --- a/src/elf.rs +++ b/src/elf.rs @@ -8,7 +8,7 @@ use crate::{ artifact::{ self, Artifact, Data, DataType, Decl, DefinedDecl, ImportKind, LinkAndDecl, Reloc, Scope, - Visibility, + SectionKind, Visibility, }, target::make_ctx, Ctx, @@ -514,33 +514,31 @@ impl<'a> Elf<'a> { (_, DefinedDecl::Section(_)) => name.to_owned(), }; - let section = match decl { - DefinedDecl::Function(d) => SectionBuilder::new(def_size as u64) - .section_type(SectionType::Bits) - .alloc() - .writable(false) - .exec(true) - .align(d.get_align()), - DefinedDecl::Data(d) => SectionBuilder::new(def_size as u64) - .section_type(Self::section_type_for_data( + let mut section = SectionBuilder::new(def_size as u64) + .writable(decl.is_writable()) + .exec(decl.is_executable()) + .align(decl.get_align()) + .section_type(match decl { + DefinedDecl::Function(_) => SectionType::Bits, + DefinedDecl::Data(d) => Self::section_type_for_data( d.get_datatype(), def.data.is_zero_init(), - )) - .alloc() - .writable(d.is_writable()) - .exec(false) - .align(d.get_align()), - DefinedDecl::Section(d) => SectionBuilder::new(def_size as u64) - .section_type( + ), + DefinedDecl::Section(d) => { // TODO: this behavior should be deprecated, but we need to warn users! if name == ".debug_str" || name == ".debug_line_str" { SectionType::String + } else if d.kind() == SectionKind::Text && d.get_datatype() == DataType::Bytes { + SectionType::Bits } else { Self::section_type_for_data(d.get_datatype(), def.data.is_zero_init()) - }, - ) - .align(d.get_align()), - }; + } + } + }); + + if decl.is_loaded() { + section = section.alloc(); + } let shndx = match def.data { Data::Blob(bytes) => self.add_progbits(section_name, section, bytes), From 446ef4f77aac9bff5a9a8089fb30da3f54bcf7f2 Mon Sep 17 00:00:00 2001 From: Kitlith Date: Sun, 8 Dec 2019 21:19:30 -0800 Subject: [PATCH 2/3] FIXUP: cargo fmt --- src/artifact/decl.rs | 4 ++-- src/elf.rs | 7 +++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/artifact/decl.rs b/src/artifact/decl.rs index 2be5974..13fd830 100644 --- a/src/artifact/decl.rs +++ b/src/artifact/decl.rs @@ -520,7 +520,7 @@ pub struct SectionDecl { align: Option, writable: Option, executable: Option, - loaded: bool + loaded: bool, } impl SectionDecl { @@ -535,7 +535,7 @@ impl SectionDecl { align: None, writable: None, executable: None, - loaded: false + loaded: false, } } diff --git a/src/elf.rs b/src/elf.rs index 9254747..d00ad51 100644 --- a/src/elf.rs +++ b/src/elf.rs @@ -520,10 +520,9 @@ impl<'a> Elf<'a> { .align(decl.get_align()) .section_type(match decl { DefinedDecl::Function(_) => SectionType::Bits, - DefinedDecl::Data(d) => Self::section_type_for_data( - d.get_datatype(), - def.data.is_zero_init(), - ), + DefinedDecl::Data(d) => { + Self::section_type_for_data(d.get_datatype(), def.data.is_zero_init()) + } DefinedDecl::Section(d) => { // TODO: this behavior should be deprecated, but we need to warn users! if name == ".debug_str" || name == ".debug_line_str" { From ff3e9469705b163f23c7418f7fe8dfc61b877483 Mon Sep 17 00:00:00 2001 From: Kitlith Date: Tue, 10 Dec 2019 15:22:45 -0800 Subject: [PATCH 3/3] Add tests, add more flags to Decl's. --- src/artifact/decl.rs | 74 +++++++++++++++++++++++++++++++++++++++++--- tests/elf.rs | 50 ++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+), 5 deletions(-) diff --git a/src/artifact/decl.rs b/src/artifact/decl.rs index 13fd830..0d1e7ee 100644 --- a/src/artifact/decl.rs +++ b/src/artifact/decl.rs @@ -214,7 +214,7 @@ impl DefinedDecl { pub fn is_writable(&self) -> bool { match self { DefinedDecl::Data(a) => a.is_writable(), - DefinedDecl::Function(_) => false, + DefinedDecl::Function(a) => a.is_writable(), DefinedDecl::Section(a) => a.is_writable(), } } @@ -224,7 +224,7 @@ impl DefinedDecl { match self { DefinedDecl::Section(a) => a.is_executable(), DefinedDecl::Function(_) => true, - DefinedDecl::Data(_) => false, + DefinedDecl::Data(a) => a.is_executable(), } } @@ -418,6 +418,7 @@ pub struct FunctionDecl { scope: Scope, visibility: Visibility, align: Option, + writable: Option, } impl Default for FunctionDecl { @@ -426,6 +427,7 @@ impl Default for FunctionDecl { scope: Scope::Local, visibility: Visibility::Default, align: None, + writable: None, } } } @@ -434,6 +436,36 @@ impl FunctionDecl { scope_methods!(); visibility_methods!(); align_methods!(); + + /// Setter for mutability + pub fn set_writable(&mut self, writable: bool) { + self.writable = Some(writable); + } + + /// Builder for mutability + pub fn with_writable(mut self, writable: bool) -> Self { + self.writable = Some(writable); + self + } + + /// Set mutability to writable + pub fn writable(self) -> Self { + self.with_writable(true) + } + + /// Set mutability to read-only + pub fn read_only(self) -> Self { + self.with_writable(false) + } + + /// Accessor to determine whether contents are writable + pub fn is_writable(&self) -> bool { + if let Some(writable) = self.writable { + return writable; + } + + false + } } impl Into for FunctionDecl { @@ -448,6 +480,7 @@ pub struct DataDecl { scope: Scope, visibility: Visibility, writable: bool, + executable: Option, datatype: DataType, align: Option, } @@ -458,6 +491,7 @@ impl Default for DataDecl { scope: Scope::Local, visibility: Visibility::Default, writable: false, + executable: None, datatype: DataType::Bytes, align: None, } @@ -470,7 +504,7 @@ impl DataDecl { datatype_methods!(); align_methods!(); - /// Builder for writability + /// Builder for mutability pub fn with_writable(mut self, writable: bool) -> Self { self.writable = writable; self @@ -491,6 +525,26 @@ impl DataDecl { pub fn is_writable(&self) -> bool { self.writable } + + /// Setter for executability + pub fn set_executable(&mut self, executable: bool) { + self.executable = Some(executable); + } + + /// Builder for executability + pub fn with_executable(mut self, executable: bool) -> Self { + self.executable = Some(executable); + self + } + + /// Accessor to determine whether contents are executable + pub fn is_executable(&self) -> bool { + if let Some(executable) = self.executable { + return executable; + } + + false + } } impl Into for DataDecl { @@ -545,17 +599,27 @@ impl SectionDecl { false } - /// Setter for writability + /// Setter for mutability pub fn set_writable(&mut self, writable: bool) { self.writable = Some(writable); } - /// Builder for writability + /// Builder for mutability pub fn with_writable(mut self, writable: bool) -> Self { self.writable = Some(writable); self } + /// Set mutability to writable + pub fn writable(self) -> Self { + self.with_writable(true) + } + + /// Set mutability to read-only + pub fn read_only(self) -> Self { + self.with_writable(false) + } + /// Accessor to determine whether contents are writable pub fn is_writable(&self) -> bool { if let Some(writable) = self.writable { diff --git a/tests/elf.rs b/tests/elf.rs index 510f471..0bf85a2 100644 --- a/tests/elf.rs +++ b/tests/elf.rs @@ -225,9 +225,59 @@ fn decl_attributes() { Ok(()) }, ), + DeclTestCase::new( + "executable_data", + Decl::data().with_executable(true), + |_sym, sect| { + ensure!(sect.is_executable(), "executable"); + Ok(()) + }, + ), + DeclTestCase::new( + "mutable_function", + Decl::function().writable(), + |_sym, sect| { + ensure!(sect.is_writable(), "writable"); + Ok(()) + }, + ), ]); } +#[test] +// Can't test with DeclTestCase, as section declarations don't generate symbols +fn section_permissions() { + let mut obj = Artifact::new(triple!("x86_64-unknown-unknown-unknown-elf"), "a".into()); + obj.declare( + "test", + Decl::section(faerie::SectionKind::Text) + .with_loaded(true) + .with_writable(true) + .with_executable(true), + ) + .expect("Can declare section with permissions"); + obj.define("test", vec![1, 2, 3, 4]) + .expect("Can define section"); + + let bytes = obj.emit().expect("can emit elf file"); + if let goblin::Object::Elf(elf) = goblin::Object::parse(&bytes).expect("can parse elf file") { + let sect = elf + .section_headers + .iter() + .find(|section| &elf.shdr_strtab[section.sh_name] == "test"); + + if let Some(section) = sect { + assert!(section.is_alloc()); + assert!(section.is_writable()); + assert!(section.is_executable()); + } else { + panic!("Could not find test section") + } + } else { + panic!("Elf file not parsed as elf file"); + } +} + /* test scaffolding: */ fn decl_tests(tests: Vec) {