Rewrite read_encoded_pointer
conforming to strict provenance
* Entries in the callsite table now use a dedicated function for reading an offset rather than a pointer * `read_encoded_pointer` uses that new function for reading offsets when the "application" part of the encoding indicates an offset (relative to some pointer) * It now errors out on nonsensical "application" and "value encoding" combinations Inspired by @eddyb's comment on zulip about this: <https://rust-lang.zulipchat.com/#narrow/stream/136281-t-opsem/topic/strict.20provenance.20in.20dwarf.3A.3Aeh/near/276197290>
This commit is contained in:
parent
e7a3c341dd
commit
b48039f6fe
1 changed files with 69 additions and 28 deletions
|
@ -84,10 +84,12 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>) -> Result
|
||||||
let ip = context.ip;
|
let ip = context.ip;
|
||||||
|
|
||||||
if !USING_SJLJ_EXCEPTIONS {
|
if !USING_SJLJ_EXCEPTIONS {
|
||||||
|
// read the callsite table
|
||||||
while reader.ptr < action_table {
|
while reader.ptr < action_table {
|
||||||
let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding)?.addr();
|
// these are offsets rather than pointers;
|
||||||
let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding)?.addr();
|
let cs_start = read_encoded_offset(&mut reader, call_site_encoding)?;
|
||||||
let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding)?.addr();
|
let cs_len = read_encoded_offset(&mut reader, call_site_encoding)?;
|
||||||
|
let cs_lpad = read_encoded_offset(&mut reader, call_site_encoding)?;
|
||||||
let cs_action_entry = reader.read_uleb128();
|
let cs_action_entry = reader.read_uleb128();
|
||||||
// Callsite table is sorted by cs_start, so if we've passed the ip, we
|
// Callsite table is sorted by cs_start, so if we've passed the ip, we
|
||||||
// may stop searching.
|
// may stop searching.
|
||||||
|
@ -161,23 +163,24 @@ fn round_up(unrounded: usize, align: usize) -> Result<usize, ()> {
|
||||||
if align.is_power_of_two() { Ok((unrounded + align - 1) & !(align - 1)) } else { Err(()) }
|
if align.is_power_of_two() { Ok((unrounded + align - 1) & !(align - 1)) } else { Err(()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn read_encoded_pointer(
|
/// Read a offset (`usize`) from `reader` whose encoding is described by `encoding`.
|
||||||
reader: &mut DwarfReader,
|
///
|
||||||
context: &EHContext<'_>,
|
/// `encoding` must be a [DWARF Exception Header Encoding as described by the LSB spec][LSB-dwarf-ext].
|
||||||
encoding: u8,
|
/// In addition the upper ("application") part must be zero.
|
||||||
) -> Result<*const u8, ()> {
|
///
|
||||||
if encoding == DW_EH_PE_omit {
|
/// # Errors
|
||||||
|
/// Returns `Err` if `encoding`
|
||||||
|
/// * is not a valid DWARF Exception Header Encoding,
|
||||||
|
/// * is `DW_EH_PE_omit`, or
|
||||||
|
/// * has a non-zero application part.
|
||||||
|
///
|
||||||
|
/// [LSB-dwarf-ext]: https://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/dwarfext.html
|
||||||
|
unsafe fn read_encoded_offset(reader: &mut DwarfReader, encoding: u8) -> Result<usize, ()> {
|
||||||
|
if encoding == DW_EH_PE_omit || encoding & 0xF0 != 0 {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
|
let result = match encoding & 0x0F {
|
||||||
// DW_EH_PE_aligned implies it's an absolute pointer value
|
// despite the name, LLVM also uses absptr for offsets instead of pointers
|
||||||
if encoding == DW_EH_PE_aligned {
|
|
||||||
reader.ptr =
|
|
||||||
reader.ptr.with_addr(round_up(reader.ptr.addr(), mem::size_of::<*const u8>())?);
|
|
||||||
return Ok(reader.read::<*const u8>());
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut result = match encoding & 0x0F {
|
|
||||||
DW_EH_PE_absptr => reader.read::<usize>(),
|
DW_EH_PE_absptr => reader.read::<usize>(),
|
||||||
DW_EH_PE_uleb128 => reader.read_uleb128() as usize,
|
DW_EH_PE_uleb128 => reader.read_uleb128() as usize,
|
||||||
DW_EH_PE_udata2 => reader.read::<u16>() as usize,
|
DW_EH_PE_udata2 => reader.read::<u16>() as usize,
|
||||||
|
@ -189,28 +192,66 @@ unsafe fn read_encoded_pointer(
|
||||||
DW_EH_PE_sdata8 => reader.read::<i64>() as usize,
|
DW_EH_PE_sdata8 => reader.read::<i64>() as usize,
|
||||||
_ => return Err(()),
|
_ => return Err(()),
|
||||||
};
|
};
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
result += match encoding & 0x70 {
|
/// Read a pointer from `reader` whose encoding is described by `encoding`.
|
||||||
DW_EH_PE_absptr => 0,
|
///
|
||||||
|
/// `encoding` must be a [DWARF Exception Header Encoding as described by the LSB spec][LSB-dwarf-ext].
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// Returns `Err` if `encoding`
|
||||||
|
/// * is not a valid DWARF Exception Header Encoding,
|
||||||
|
/// * is `DW_EH_PE_omit`, or
|
||||||
|
/// * combines `DW_EH_PE_absptr` or `DW_EH_PE_aligned` application part with an integer encoding
|
||||||
|
/// (not `DW_EH_PE_absptr`) in the value format part.
|
||||||
|
///
|
||||||
|
/// [LSB-dwarf-ext]: https://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/dwarfext.html
|
||||||
|
unsafe fn read_encoded_pointer(
|
||||||
|
reader: &mut DwarfReader,
|
||||||
|
context: &EHContext<'_>,
|
||||||
|
encoding: u8,
|
||||||
|
) -> Result<*const u8, ()> {
|
||||||
|
if encoding == DW_EH_PE_omit {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let base_ptr = match encoding & 0x70 {
|
||||||
|
DW_EH_PE_absptr => core::ptr::null(),
|
||||||
// relative to address of the encoded value, despite the name
|
// relative to address of the encoded value, despite the name
|
||||||
DW_EH_PE_pcrel => reader.ptr.expose_addr(),
|
DW_EH_PE_pcrel => reader.ptr,
|
||||||
DW_EH_PE_funcrel => {
|
DW_EH_PE_funcrel => {
|
||||||
if context.func_start.is_null() {
|
if context.func_start.is_null() {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
context.func_start.expose_addr()
|
context.func_start
|
||||||
|
}
|
||||||
|
DW_EH_PE_textrel => (*context.get_text_start)(),
|
||||||
|
DW_EH_PE_datarel => (*context.get_data_start)(),
|
||||||
|
// aligned means the value is aligned to the size of a pointer
|
||||||
|
DW_EH_PE_aligned => {
|
||||||
|
reader.ptr =
|
||||||
|
reader.ptr.with_addr(round_up(reader.ptr.addr(), mem::size_of::<*const u8>())?);
|
||||||
|
core::ptr::null()
|
||||||
}
|
}
|
||||||
DW_EH_PE_textrel => (*context.get_text_start)().expose_addr(),
|
|
||||||
DW_EH_PE_datarel => (*context.get_data_start)().expose_addr(),
|
|
||||||
_ => return Err(()),
|
_ => return Err(()),
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME(strict provenance)
|
let mut ptr = if base_ptr.is_null() {
|
||||||
let mut result: *const u8 = ptr::from_exposed_addr::<u8>(result);
|
// any value encoding other than absptr would be nonsensical here;
|
||||||
|
// there would be no source of pointer provenance
|
||||||
|
if encoding & 0x0F != DW_EH_PE_absptr {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
reader.read::<*const u8>()
|
||||||
|
} else {
|
||||||
|
let offset = read_encoded_offset(reader, encoding & 0x0F)?;
|
||||||
|
base_ptr.wrapping_add(offset)
|
||||||
|
};
|
||||||
|
|
||||||
if encoding & DW_EH_PE_indirect != 0 {
|
if encoding & DW_EH_PE_indirect != 0 {
|
||||||
result = *(result.cast::<*const u8>());
|
ptr = *(ptr.cast::<*const u8>());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(result)
|
Ok(ptr)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue