Skip to content

Externally inject auditable data #29

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

Closed
Nemo157 opened this issue Dec 22, 2021 · 10 comments
Closed

Externally inject auditable data #29

Nemo157 opened this issue Dec 22, 2021 · 10 comments
Assignees

Comments

@Nemo157
Copy link

Nemo157 commented Dec 22, 2021

I was recently thinking about what it would take to integrate something like this into a cargo install process. The biggest issue I see is that it requires modifying the binary sources to have the data added. I think a potentially more useful approach is a way to inject this data into an arbitrary binary build; maybe via something like a cargo wrapper cargo auditable build.

This would also avoid issues #9, #11 and #13 (but probably introduce others 😀).

Is there a reason to prefer the current approach where each binary needs to be configured to include the data?

@Shnatsel
Copy link
Member

I've been thinking along the same lines!

Is there a reason to prefer the current approach where each binary needs to be configured to include the data?

It's mildly more portable, in the sense that we don't need extra platform-specific tools for every platform (e.g. objcopy on Linux) and can just use the linker. But given how many issues we're having with the linker, I do believe it would be better to just use a binary manipulation tool.

I have big ambitions of getting this thing into Cargo, and I'm not 100% sure what their policy on calling external tools would be. But yes, writing a Cargo wrapper that does this would be fairly trivial and I'd be happy to have a branch with that approach.

@bjorn3
Copy link

bjorn3 commented Dec 22, 2021

An option would be to compile a staticlib containing the audit data and then tell rustc to link this staticlib when building the final executable.

@Shnatsel
Copy link
Member

@bjorn3 I was not aware of that approach!

I understand that would require some sort of extra crate with crate-type = ["staticlib"] in Cargo.toml, and then passing some extra flags in the main crate build?

@Shnatsel
Copy link
Member

I fear the symbol would not survive LTO with the staticlib approach unless it's used from the main binary.

@bjorn3
Copy link

bjorn3 commented Dec 22, 2021

I just realized that rustc produces staticlibs will contain a copy of the standard library which would cause conflicts. You could copy the logic rustc itself uses to produce object files containing the crate metadata. These are normally used for dylibs, but should work fine for executables too: https://github.com/rust-lang/rust/blob/e100ec5bc7cd768ec17d75448b29c9ab4a39272b/compiler/rustc_codegen_ssa/src/back/metadata.rs#L233-L287 You can then use -Clink-arg=/path/to/audit_data.o -Clink-arg=-Wl,--require-defined=AUDITABLE_VERSION_INFO if you call the symbol AUDITABLE_VERSION_INFO. I just tested it and it works fine even with LTO enabled.

@Shnatsel
Copy link
Member

Shnatsel commented Feb 22, 2022

I have pushed a new branch, external-injection, that contains a proof-of-concept tool for externally injecting the audit data, using the mechanism suggested by @bjorn3. I can confirm that it does indeed work and even survives LTO, at least on my Linux system! 🥳

The proof-of-concept tool is called auditable-inject, you can use the rust-audit-info tool to recover the data. Make sure they're from the same branch because I changed the section name to be .dep-v0 on all platforms. No reason to have it vary.

Usage: auditable-inject target-triple /path/to/data_to_inject
Then use the following before compiling:
export RUSTFLAGS='-Clink-arg=audit_data.o -Clink-arg=-Wl,--require-defined=AUDITABLE_VERSION_INFO'

I have ignored endianness as well as some tricky special-casing for MIPS and RISC-V, because I don't know how to derive those from the target triple without having access to rustc internals. I hope Cargo has access to that stuff internally. In the meanwhile I'll probably have to get by with a hardcoded list of big-endian architectures or some such...

@Nemo157
Copy link
Author

Nemo157 commented Feb 22, 2022

Cargo uses rustc --target=... --print=cfg to get the derived cfg values.

@Shnatsel
Copy link
Member

Thanks a lot for the tip, @Nemo157 ! I have migrated to parsing rustc --target=... --print=cfg, which allowed proper handling of endianness and most of the quirks (except RISC-V). The result is available in the external-injection branch.

@Shnatsel
Copy link
Member

I think I'm going to make a cargo auditable subcommand, so that people could just alias cargo to cargo auditable and make everything installed or built on their system auditable. Plus a better extractor than just rust-audit-info; it is very minimal, and we need something like cargo audit. Thoughts?

@Shnatsel
Copy link
Member

External injection via cargo auditable is now the default. The approach with RUSTC_WRAPPER that landed in #40 made it actually viable.

I've removed mentions of the original build.rs-based approach from the README.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants