-
Notifications
You must be signed in to change notification settings - Fork 271
Remove some unsafe code; fix a soundness hole #721
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
use core::fmt::{self, Write}; | ||
use core::mem::{size_of, transmute}; | ||
use core::slice::from_raw_parts; | ||
use libc::c_char; | ||
use zerocopy::FromBytes; | ||
|
||
unsafe extern "C" { | ||
// dl_iterate_phdr takes a callback that will receive a dl_phdr_info pointer | ||
|
@@ -181,15 +181,12 @@ fn take_bytes_align4<'a>(num: usize, bytes: &mut &'a [u8]) -> Option<&'a [u8]> { | |
// architectures correctness). The values in the Elf_Nhdr fields might | ||
// be nonsense but this function ensures no such thing. | ||
fn take_nhdr<'a>(bytes: &mut &'a [u8]) -> Option<&'a Elf_Nhdr> { | ||
if size_of::<Elf_Nhdr>() > bytes.len() { | ||
return None; | ||
} | ||
// This is safe as long as there is enough space and we just confirmed that | ||
// in the if statement above so this should not be unsafe. | ||
let out = unsafe { transmute::<*const u8, &'a Elf_Nhdr>(bytes.as_ptr()) }; | ||
// Note that sice_of::<Elf_Nhdr>() is always 4-byte aligned. | ||
*bytes = &bytes[size_of::<Elf_Nhdr>()..]; | ||
Some(out) | ||
let (hdr, suffix) = <[u32; 3]>::ref_from_prefix(*bytes).ok()?; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not deeply familiar with the internals of zerocopy and its API surface, so I am afraid adding its API surface does not improve the ease of verifying the code correctness for me. I know you work very hard on it, but it is very general, whereas backtrace-rs only has one task. Well, two, as symbolization and recovering a trace are different, but it tends to collapse them, for better or worse. Fixing this soundness problem here by expanding the trusted computing base (TCB) of backtrace means now someone has to verify zerocopy. It may improve things if the zerocopy inclusion was done systematically, but here it is only as a spot-fix, and does not address other locations in the code which could instead use zerocopy's APIs. I would like to separate out discussion of using a new dependency from any such fixes for any soundness problems, and certainly to separate soundness problems from any cleanup. |
||
*bytes = suffix; | ||
|
||
let hdr: *const [u32; 3] = hdr; | ||
// SAFETY: `[u32; 3]` and `Elf_Nhdr` have the same layout and bit validity. | ||
Some(unsafe { &*hdr.cast::<Elf_Nhdr>() }) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this fix anything, or only replace one If it fixes something, how simple would it be to fix that without the dependency? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yeah, it fixes a soundness hole in the original – in particular, that alignment isn't checked. This comment in the original is misleading: // Note that sice_of::<Elf_Nhdr>() is always 4-byte aligned.
*bytes = &bytes[size_of::<Elf_Nhdr>()..]; While it's true that
The That said, the new
It wouldn't be hard in principle. The concern is more that it'd be brittle - it would be easy for a future developer who doesn't understand the subtleties we're discussing here to re-introduce a soundness bug. IMO the biggest clue to this is the " There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I don't think that comment is so badly wrong. It could be clearer, but I take that comment to mean that it preserves the 4-byte alignment required by ELF, which is what is important for that line. The thing that is wrong is that the function doesn't check the 4-byte alignment to start with, and the comment prior to this function thinks that this requirement is optional. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Backtrace's maintenance is not idyllic. If it was anyone's first priority, maybe I would be paid to do it, yet I'm not. Even experienced programmers do not fire on all cylinders at all times. Certainly not all maintainers are willing to be insufferable exacting pedants, with borderline-antisocial disregard for whether someone needs the code to be merged for someone's job requirements, instead caring only about the code quality and correctness. As you seem to want the code to be reviewed by that kind of demon, here I am! But I have not retrospectively audited every last line of every last platform, to be sure. Improvements to their condition are certainly welcome. Based on the conversation so far, it seems the soundness requirements have not been properly documented. Certainly, I am not yet convinced the current version of the code as present in this PR documents them. I would like to have the requirements properly documented first, so for all comments to be updated appropriately in this file, at the very least. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The backtrace crate already indirectly depends on object, right? Maybe you could use the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That seems easy enough, see #725. object is already a direct dependency. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh cool, TIL about |
||
} | ||
|
||
impl<'a> Iterator for NoteIter<'a> { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,6 @@ use super::{Library, LibrarySegment}; | |
use alloc::borrow::ToOwned; | ||
use alloc::vec::Vec; | ||
use core::ffi::CStr; | ||
use core::mem; | ||
use object::NativeEndian; | ||
|
||
#[cfg(target_pointer_width = "64")] | ||
|
@@ -38,8 +37,8 @@ pub(super) fn native_libraries() -> Vec<Library> { | |
let mut libs = Vec::new(); | ||
|
||
// Request the current link map from the runtime linker: | ||
let mut map: *const LinkMap = core::ptr::null(); | ||
let map = unsafe { | ||
let mut map: *const LinkMap = mem::zeroed(); | ||
Comment on lines
+40
to
-42
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While I do find this an improvement, this is pure style. All changes like this, that only improve the readability, or otherwise "simply" replace Consider it a parallel to my other "TCB"-related concerns, albeit distributed throughout history. Ignorable changes should be ignorable, and non-ignorable ones should be non-ignorable, throughout. |
||
if dlinfo( | ||
RTLD_SELF, | ||
RTLD_DI_LINKMAP, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If kept, this could be restricted to
target_os = "fuchsia"
.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also can you please check that zerocopy-derive doesn't end up in the lockfile? If it does end up in there, that will cause a tidy lint checking that the standard library doesn't depend on proc-macros to fail.
Edit: It does end up in the lockfile.