Skip to content

Commit

Permalink
Merge #228
Browse files Browse the repository at this point in the history
228: Libunwind update + toolchain verification r=pagten a=AdrianCX

Changes are needed to:

1. Allow libunwind update.
- We now have 4 symbols to reference start and size of sections .eh_frame and .eh_frame_hdr
- We need to support previous versions as well.
- Symbols are not reused from previous version to cause failure at compile time if old tool is used with new libunwind. (also added version check code to prevent this issue in the future and provide nice messages)

2. Fail gracefully if toolchain version is unsupported (give user a nice message telling to update tools)



Co-authored-by: Adrian Cruceru <cruceruadrian@gmail.com>
  • Loading branch information
bors[bot] and AdrianCX committed May 4, 2020
2 parents e763ba6 + f999fd0 commit 01d1d94
Showing 1 changed file with 115 additions and 29 deletions.
144 changes: 115 additions & 29 deletions fortanix-sgx-tools/src/bin/ftxsgx-elf2sgxs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use failure::{err_msg, Error, ResultExt};
use xmas_elf::dynamic::{Dynamic as DynEntry, Tag as DynTag};
use xmas_elf::header::Class as HeaderClass;
use xmas_elf::program::{SegmentData, Type as PhType};
use xmas_elf::sections::{SectionData, SHN_UNDEF};
use xmas_elf::sections::{SectionData, SHN_UNDEF, ShType};
use xmas_elf::symbol_table::{DynEntry64 as DynSymEntry, Entry};
use xmas_elf::ElfFile;

Expand All @@ -33,6 +33,7 @@ use sgxs_crate::sgxs::{self, CanonicalSgxsWriter, SecinfoTruncated, SgxsWrite};
use sgxs_crate::util::{size_fit_natural, size_fit_page};

use clap::ArgMatches;
use std::convert::TryInto;

#[allow(non_snake_case)]
struct Symbols<'a> {
Expand All @@ -44,10 +45,14 @@ struct Symbols<'a> {
ENCLAVE_SIZE: &'a DynSymEntry,
CFGDATA_BASE: &'a DynSymEntry,
DEBUG: &'a DynSymEntry,
EH_FRM_HDR_BASE: &'a DynSymEntry,
EH_FRM_HDR_SIZE: &'a DynSymEntry,
EH_FRM_HDR_BASE: Option<&'a DynSymEntry>,
EH_FRM_HDR_SIZE: Option<&'a DynSymEntry>,
TEXT_BASE: &'a DynSymEntry,
TEXT_SIZE: &'a DynSymEntry,
EH_FRM_OFFSET: Option<&'a DynSymEntry>,
EH_FRM_LEN: Option<&'a DynSymEntry>,
EH_FRM_HDR_OFFSET: Option<&'a DynSymEntry>,
EH_FRM_HDR_LEN: Option<&'a DynSymEntry>,
}
struct SectionRange {
offset: u64,
Expand Down Expand Up @@ -112,30 +117,38 @@ pub struct LayoutInfo<'a> {
library: bool,
sized: bool,
ehfrm: SectionRange,
ehfrm_hdr: SectionRange,
text: SectionRange,
}

macro_rules! read_syms {
($($name:ident),* in $syms:ident : $elf:ident) => {{
$(let mut $name=None;)*
(mandatory: $($mandatory_name:ident),* optional: $($optional_name:ident),* in $syms:ident : $elf:ident) => {{
$(let mut $mandatory_name=None;)*
$(let mut $optional_name=None;)*
for sym in $syms.iter().skip(1) {
if sym.shndx()==SHN_UNDEF {
bail!("Found undefined dynamic symbol: {}", sym.get_name(&$elf).map_err(err_msg)?);
} $(else if sym.get_name(&$elf).map_err(err_msg)?==stringify!($name) {
if replace(&mut $name,Some(sym)).is_some() {
bail!("Found symbol twice: {}", stringify!($name));
} $(else if sym.get_name(&$elf).map_err(err_msg)?==stringify!($mandatory_name) {
if replace(&mut $mandatory_name,Some(sym)).is_some() {
bail!("Found symbol twice: {}", stringify!($mandatory_name));
}
})*
$(else if sym.get_name(&$elf).map_err(err_msg)?==stringify!($optional_name) {
if replace(&mut $optional_name,Some(sym)).is_some() {
bail!("Found symbol twice: {}", stringify!($optional_name));
}
})*
}
if let ($(Some($name)),*)=($($name),*) {
Symbols{$($name:$name),*}
if let ($(Some($mandatory_name)),*)=($($mandatory_name),*) {
Symbols{$($mandatory_name:$mandatory_name),*,
$($optional_name:$optional_name),*}
} else {
let mut missing = String::new();
$(if $name.is_none() {
$(if $mandatory_name.is_none() {
if !missing.is_empty() {
missing += ", ";
}
missing += stringify!($name);
missing += stringify!($mandatory_name);
})*
bail!("These dynamic symbols are missing: {}", missing)
}
Expand All @@ -154,11 +167,62 @@ macro_rules! check_size {
);
}
}};
($name:ident == $size:expr) => {{
let size = $name.size();
if size != $size {
bail!(
"Dynamic symbol {} doesn't have the right size. Expected size {}, got {}.",
stringify!($name),
$size,
size
);
}
}};
}

impl<'a> LayoutInfo<'a> {

// Check version defined in rust-lang assembly code is supported, see .note.x86_64-fortanix-unknown-sgx section in https://github.com/rust-lang/rust/blob/master/src/libstd/sys/sgx/abi/entry.S
fn check_toolchain_version(elf: &ElfFile<'a>) -> Result<(), Error> {
let note_header = elf.find_section_by_name(".note.x86_64-fortanix-unknown-sgx").ok_or_else(|| format_err!("Could not find .note.x86_64-fortanix-unknown-sgx header!"))?;

if note_header.get_type() != Ok(ShType::Note) {
bail!("Invalid type {:?} for section: .note.x86_64-fortanix-unknown-sgx", note_header.get_type());
}

match note_header.get_data(&elf) {
Ok(SectionData::Note64(header, ptr)) => {
if header.name(ptr) != "toolchain-version" {
bail!("Expecting 'toolchain-version' as name for .note.x86_64-fortanix-unknown-sgx");
}

let desc = header.desc(ptr);

if desc.len() != 4 {
bail!("Expecting 32 bit 'toolchain-version' in .note.x86_64-fortanix-unknown-sgx");
}

// According to entry.S in rust-lang 'desc - toolchain version number, 32-bit LE'
let version : u32 = u32::from_le_bytes(desc.try_into().unwrap());

let max_supported_version = 1;

if version > max_supported_version {
bail!("Update required for 'fortanix-sgx-tools'. ELF file has toolchain version {}, installed tools supports up to version {}", version, max_supported_version);
}
},
Ok(_) => bail!("Section data for .note.x86_64-fortanix-unknown-sgx is not a note."),
Err(_) => bail!("Failed fetching data for section .note.x86_64-fortanix-unknown-sgx.")
}

Ok(())
}

#[allow(non_snake_case)]
fn check_symbols(elf: &ElfFile<'a>) -> Result<Symbols<'a>, Error> {

Self::check_toolchain_version(&elf)?;

let dynsym = elf
.find_section_by_name(".dynsym")
.ok_or_else(|| format_err!("Could not find dynamic symbol table!"))?;
Expand All @@ -170,18 +234,14 @@ impl<'a> LayoutInfo<'a> {
bail!(".dynsym section is not a dynamic symbol table!");
};

let syms = read_syms!(sgx_entry,
HEAP_BASE,
HEAP_SIZE,
RELA,
RELACOUNT,
ENCLAVE_SIZE,
CFGDATA_BASE,
DEBUG,
EH_FRM_HDR_BASE,
EH_FRM_HDR_SIZE,
TEXT_BASE,
TEXT_SIZE in syms : elf);
// Optional symbols used for compatibility. Old versions use 'EH_FRM_HDR_BASE, EH_FRM_HDR_SIZE', new versions use 'EH_FRM_OFFSET, EH_FRM_LEN, EH_FRM_HDR_OFFSET, EH_FRM_HDR_LEN.
// Tool must support both variants for backwards compatibility at least until 'https://github.com/fortanix/rust-sgx/issues/174' is merged into rust-lang.
//
// Variables have been renamed due to missing 'toolchain' version checks. Rename will cause compile-time failure if using old tool with new toolchain assembly code.
let syms = read_syms!(mandatory: sgx_entry, HEAP_BASE, HEAP_SIZE, RELA, RELACOUNT, ENCLAVE_SIZE, CFGDATA_BASE, DEBUG, TEXT_BASE, TEXT_SIZE
optional: EH_FRM_HDR_BASE, EH_FRM_HDR_SIZE, EH_FRM_OFFSET, EH_FRM_LEN, EH_FRM_HDR_OFFSET, EH_FRM_HDR_LEN
in syms : elf);


check_size!(syms.HEAP_BASE == 8);
check_size!(syms.HEAP_SIZE == 8);
Expand All @@ -190,8 +250,6 @@ impl<'a> LayoutInfo<'a> {
check_size!(syms.ENCLAVE_SIZE == 8);
check_size!(syms.CFGDATA_BASE == 8);
check_size!(syms.DEBUG == 1);
check_size!(syms.EH_FRM_HDR_BASE == 8);
check_size!(syms.EH_FRM_HDR_SIZE == 8);
check_size!(syms.TEXT_BASE == 8);
check_size!(syms.TEXT_SIZE == 8);

Expand All @@ -201,6 +259,18 @@ impl<'a> LayoutInfo<'a> {
bail!("ENCLAVE_SIZE symbol is not naturally aligned")
}

if let (Some(EH_FRM_HDR_BASE), Some(EH_FRM_HDR_SIZE)) = (syms.EH_FRM_HDR_BASE, syms.EH_FRM_HDR_SIZE) {
check_size!(EH_FRM_HDR_BASE == 8);
check_size!(EH_FRM_HDR_SIZE == 8);
} else if let (Some(EH_FRM_OFFSET), Some(EH_FRM_LEN), Some(EH_FRM_HDR_OFFSET), Some(EH_FRM_HDR_LEN)) = (syms.EH_FRM_OFFSET, syms.EH_FRM_LEN, syms.EH_FRM_HDR_OFFSET, syms.EH_FRM_HDR_LEN) {
check_size!(EH_FRM_OFFSET == 8);
check_size!(EH_FRM_LEN == 8);
check_size!(EH_FRM_HDR_OFFSET == 8);
check_size!(EH_FRM_HDR_LEN == 8);
} else {
bail!("Missing EH Frame header symbols, application must either have (EH_FRM_HDR_BASE/EH_FRM_HDR_SIZE) or (EH_FRM_OFFSET, EH_FRM_LEN, EH_FRM_HDR_OFFSET, EH_FRM_HDR_LEN");
}

Ok(syms)
}

Expand Down Expand Up @@ -333,7 +403,8 @@ impl<'a> LayoutInfo<'a> {
let sym = Self::check_symbols(&elf)?;
let dyn = Self::check_dynamic(&elf)?;
Self::check_relocs(&elf, dyn.as_ref())?;
let ehfrm = Self::check_section(&elf, ".eh_frame_hdr")?;
let ehfrm = Self::check_section(&elf, ".eh_frame")?;
let ehfrm_hdr = Self::check_section(&elf, ".eh_frame_hdr")?;
let text = Self::check_section(&elf, ".text")?;

Ok(LayoutInfo {
Expand All @@ -347,11 +418,13 @@ impl<'a> LayoutInfo<'a> {
debug,
library,
ehfrm,
ehfrm_hdr,
text,
sized,
})
}

#[allow(non_snake_case)]
pub fn write_elf_segments<W: SgxsWrite>(
&self,
writer: &mut CanonicalSgxsWriter<W>,
Expand Down Expand Up @@ -379,11 +452,24 @@ impl<'a> LayoutInfo<'a> {
),
Splice::for_sym_u64(self.sym.CFGDATA_BASE, memory_size),
Splice::for_sym_u8(self.sym.DEBUG, self.debug as _),
Splice::for_sym_u64(self.sym.EH_FRM_HDR_BASE, self.ehfrm.offset),
Splice::for_sym_u64(self.sym.EH_FRM_HDR_SIZE, self.ehfrm.size),
Splice::for_sym_u64(self.sym.TEXT_BASE, self.text.offset),
Splice::for_sym_u64(self.sym.TEXT_SIZE, self.text.size),
];

if let (Some(EH_FRM_HDR_BASE), Some(EH_FRM_HDR_SIZE)) = (self.sym.EH_FRM_HDR_BASE, self.sym.EH_FRM_HDR_SIZE) {
splices.push(Splice::for_sym_u64(EH_FRM_HDR_BASE, self.ehfrm_hdr.offset));
splices.push(Splice::for_sym_u64(EH_FRM_HDR_SIZE, self.ehfrm_hdr.size));
}
else if let (Some(EH_FRM_OFFSET), Some(EH_FRM_LEN), Some(EH_FRM_HDR_OFFSET), Some(EH_FRM_HDR_LEN)) = (self.sym.EH_FRM_OFFSET, self.sym.EH_FRM_LEN, self.sym.EH_FRM_HDR_OFFSET, self.sym.EH_FRM_HDR_LEN) {
splices.push(Splice::for_sym_u64(EH_FRM_OFFSET, self.ehfrm.offset));
splices.push(Splice::for_sym_u64(EH_FRM_LEN, self.ehfrm.size));
splices.push(Splice::for_sym_u64(EH_FRM_HDR_OFFSET, self.ehfrm_hdr.offset));
splices.push(Splice::for_sym_u64(EH_FRM_HDR_LEN, self.ehfrm_hdr.size));
}
else {
bail!("Missing .eh_frame header symbols, application must have symbols exported by rust x86_64_fortanix_unknown_sgx toolchain, either (EH_FRM_HDR_BASE/EH_FRM_HDR_SIZE) or (EH_FRM_OFFSET, EH_FRM_LEN, EH_FRM_HDR_OFFSET, EH_FRM_HDR_LEN");
}

if let Some(enclave_size) = enclave_size {
splices.push(Splice::for_sym_u64(self.sym.ENCLAVE_SIZE, enclave_size));
}
Expand Down

0 comments on commit 01d1d94

Please sign in to comment.