Skip to content

Initial fuzzer integration#961

Merged
olix0r merged 18 commits intolinkerd:mainfrom
DavidKorczynski:main
Apr 5, 2021
Merged

Initial fuzzer integration#961
olix0r merged 18 commits intolinkerd:mainfrom
DavidKorczynski:main

Conversation

@DavidKorczynski
Copy link
Contributor

Adds a set of fuzzers for various of the linkerd crates.

The goal of this PR is to create an initial fuzzer infrastructure as well as fuzzers that can be integrated with OSS-Fuzz for continuous fuzzing.

The way I set it up was to place the fuzzers for a given crate within the crate folder itself. I then put in a fuzz_logic module in the source code that is to be fuzzed, thus following the low of how the existing tests are written. The majority of additions in this PR are independent of the linkerd2-proxy source code, but there are a few changes.

@DavidKorczynski DavidKorczynski requested a review from a team March 30, 2021 21:22

[patch.crates-io]
webpki = { git = "https://github.com/linkerd/webpki", branch = "cert-dns-names-0.21", rev = "b2c3bb3" }
webpki = { git = "https://github.com/linkerd/webpki", branch = "cert-dns-names-0.21" }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did the pinned revision cause problems?

Copy link
Contributor Author

@DavidKorczynski DavidKorczynski Mar 31, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I get the following issue:

linkerd2-proxy/linkerd/proxy/http$ cargo +nightly fuzz build
error: failed to parse manifest at `/linkerd2-proxy-6/linkerd2-proxy/Cargo.toml`

Caused by:
  dependency (webpki) specification is ambiguous. Only one of `branch`, `tag` or `rev` is allowed.
Error: failed to build fuzz script: "cargo" "build" "--manifest-path" "linkerd2-proxy/linkerd/proxy/http/fuzz/Cargo.toml" "--target" "x86_64-unknown-linux-gnu" "--release" "--bins"```

Copy link
Contributor

@hawkw hawkw Mar 31, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, maybe we should prefer the pinned revision over the pinned branch, since the rev is more specific? but i don't have a strong opinion on this one (and the branch is much more nicely human readable!)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

out of curiosity, is there a reason we don't use the latest of the branch?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, huh, are we not? :)

Copy link
Contributor Author

@DavidKorczynski DavidKorczynski Apr 2, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

welp, maybe we should fix this...but it's a job for another PR :)

@olix0r olix0r requested a review from hawkw March 31, 2021 19:05
Copy link
Contributor

@hawkw hawkw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had some largely procedural questions about how the fuzz tests are organized.

Copy link
Contributor

@hawkw hawkw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gave this a closer read and I had some additional suggestions. Let me know if any of these don't or you have follow-up questions?

Comment on lines 262 to 269
pub fn fuzz_entry(fuzz_data: &str) {
if let Ok(_name) = Name::from_str(fuzz_data) {
let _fcon = FuzzConfig {};
let _resolver = Resolver::from_system_config_with(&_fcon).unwrap();
let a1 = async {
let _w = _resolver.resolve_a(&_name).await;
};
futures::executor::block_on(a1);
let a2 = async {
let _w2 = _resolver.resolve_srv(&_name).await;
};
futures::executor::block_on(a2);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using futures::executor::block_on will block the current thread on the returned futures, not allowing any background tasks spawned by trust-dns etc to proceed. I don't know if this will correctly exercise the resolver code. Could we maybe change this so that fuzz_entry is an async fn that's passed to Runtime::block_on in fuzz_target_1, rather than using futures::executor::block_on? That would look something like this:

Suggested change
pub fn fuzz_entry(fuzz_data: &str) {
if let Ok(_name) = Name::from_str(fuzz_data) {
let _fcon = FuzzConfig {};
let _resolver = Resolver::from_system_config_with(&_fcon).unwrap();
let a1 = async {
let _w = _resolver.resolve_a(&_name).await;
};
futures::executor::block_on(a1);
let a2 = async {
let _w2 = _resolver.resolve_srv(&_name).await;
};
futures::executor::block_on(a2);
}
}
pub async fn fuzz_entry(fuzz_data: &str) {
if let Ok(_name) = Name::from_str(fuzz_data) {
let _fcon = FuzzConfig {};
let _resolver = Resolver::from_system_config_with(&_fcon).unwrap();
let _w = _resolver.resolve_a(&_name).await;
let _w2 = _resolver.resolve_srv(&_name).await;
}
}

I think this code may happen to work as-is if the Tokio runtime is configured in multithreaded mode (by another crate enabling the "rt-multi-thread" feature). But, I think we should remove the use of futures::executor::block_on regardless, since it's adding additional complexity that isn't actually part of the code we want to fuzz here, and it's never used in the actual proxy binary...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you're right entirely - it also seems the fuzzer is running much better with your suggestions. Please check the new set up!


[dependencies]
libfuzzer-sys = "0.4"
tokio = { version = "1", features = ["rt", "sync", "time"] }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we may need to also enable tokio's "io" feature flag --- I believe constructing the resolver here

// This function is synchronous, but needs to be called within the Tokio
// 0.2 runtime context, since it gets a handle.
let dns = AsyncResolver::tokio(config, opts).expect("system DNS config must be valid");

will try to bind a UDP socket to the Tokio event loop, which will fail without the "io" feature flag enabled?

I'm surprised we need the "sync" feature, also --- AFAICT, the fuzz targets don't use tokio's synchronization primitives?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think Tokio has an "io" flag? Do you perhaps mean io-util?

We have to build fuzzers with Cargo nightly, which complains about
having both the branch and rev tag. Only one can be used.

Signed-off-by: davkor <[email protected]>
Creates a set up for fuzzing Addr. This fuzzer is minor but nice to
have.

Signed-off-by: davkor <[email protected]>
Integrates a fuzzer for DNS.

Signed-off-by: davkor <[email protected]>
@DavidKorczynski
Copy link
Contributor Author

DavidKorczynski commented Apr 2, 2021

@hawkw please check my replies to your review. There are a few ones still ones I didn't resolves as they can perhaps be up for debate.

This is an attempt to fix CI issue by removing cfg(fuzzing) feature.
This simplifies things and if it works we should use the same fix
elsewhere.

Signed-off-by: davkor <[email protected]>
Signed-off-by: davkor <[email protected]>
Copy link
Contributor

@hawkw hawkw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for making the changes we discussed, this looks great. I had a few more comments, but none of them are critical --- I think this is close to ready to merge!


[patch.crates-io]
webpki = { git = "https://github.com/linkerd/webpki", branch = "cert-dns-names-0.21", rev = "b2c3bb3" }
webpki = { git = "https://github.com/linkerd/webpki", branch = "cert-dns-names-0.21" }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

welp, maybe we should fix this...but it's a job for another PR :)

use libfuzzer_sys::arbitrary::Arbitrary;

#[derive(Debug, Arbitrary)]
pub struct AllocatorMethod {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if I understand the naming "AllocatorMethod"?

Comment on lines 6 to 10
pub struct AllocatorMethod {
pub data: Vec<u8>,
pub port: u16,
pub protocol: bool,
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, not important: I don't think any of this needs to be pub?

Suggested change
pub struct AllocatorMethod {
pub data: Vec<u8>,
pub port: u16,
pub protocol: bool,
}
struct AllocatorMethod {
data: Vec<u8>,
port: u16,
protocol: bool,
}

Copy link
Contributor

@hawkw hawkw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding the new fuzzer for invalid input to TransportHeader::read_prefaced! I think this PR looks great now --- it looks like cargo fmt needs to be run before it'll pass CI, but then I'm happy to merge it!

@hawkw hawkw requested a review from olix0r April 5, 2021 22:53
@olix0r olix0r merged commit b401746 into linkerd:main Apr 5, 2021
olix0r added a commit to linkerd/linkerd2 that referenced this pull request Apr 7, 2021
This release fixes a caching issue in the outbound proxy's "ingress
mode" that could cause the incorrect client to be used for requests.
This caching has been fixed so that clients cannot be incorrectly reused
across logical destinations.

---

* transport: introduce Bind trait and move orig dst to the type level (linkerd/linkerd2-proxy#957)
* Initial fuzzer integration (linkerd/linkerd2-proxy#961)
* Fix caching in ingress mode (linkerd/linkerd2-proxy#965)
olix0r added a commit to linkerd/linkerd2 that referenced this pull request Apr 7, 2021
This release fixes a caching issue in the outbound proxy's "ingress
mode" that could cause the incorrect client to be used for requests.
This caching has been fixed so that clients cannot be incorrectly reused
across logical destinations.

---

* transport: introduce Bind trait and move orig dst to the type level (linkerd/linkerd2-proxy#957)
* Initial fuzzer integration (linkerd/linkerd2-proxy#961)
* Fix caching in ingress mode (linkerd/linkerd2-proxy#965)
Pothulapati pushed a commit to linkerd/linkerd2 that referenced this pull request Apr 14, 2021
This release fixes a caching issue in the outbound proxy's "ingress
mode" that could cause the incorrect client to be used for requests.
This caching has been fixed so that clients cannot be incorrectly reused
across logical destinations.

---

* transport: introduce Bind trait and move orig dst to the type level (linkerd/linkerd2-proxy#957)
* Initial fuzzer integration (linkerd/linkerd2-proxy#961)
* Fix caching in ingress mode (linkerd/linkerd2-proxy#965)
jijeesh pushed a commit to jijeesh/linkerd2 that referenced this pull request Apr 21, 2021
This release fixes a caching issue in the outbound proxy's "ingress
mode" that could cause the incorrect client to be used for requests.
This caching has been fixed so that clients cannot be incorrectly reused
across logical destinations.

---

* transport: introduce Bind trait and move orig dst to the type level (linkerd/linkerd2-proxy#957)
* Initial fuzzer integration (linkerd/linkerd2-proxy#961)
* Fix caching in ingress mode (linkerd/linkerd2-proxy#965)

Signed-off-by: Jijeesh <[email protected]>
kleimkuhler pushed a commit to linkerd/linkerd2 that referenced this pull request May 12, 2021
This release fixes a caching issue in the outbound proxy's "ingress
mode" that could cause the incorrect client to be used for requests.
This caching has been fixed so that clients cannot be incorrectly reused
across logical destinations.

---

* transport: introduce Bind trait and move orig dst to the type level (linkerd/linkerd2-proxy#957)
* Initial fuzzer integration (linkerd/linkerd2-proxy#961)
* Fix caching in ingress mode (linkerd/linkerd2-proxy#965)
kleimkuhler pushed a commit to linkerd/linkerd2 that referenced this pull request May 12, 2021
This release fixes a caching issue in the outbound proxy's "ingress
mode" that could cause the incorrect client to be used for requests.
This caching has been fixed so that clients cannot be incorrectly reused
across logical destinations.

---

* transport: introduce Bind trait and move orig dst to the type level (linkerd/linkerd2-proxy#957)
* Initial fuzzer integration (linkerd/linkerd2-proxy#961)
* Fix caching in ingress mode (linkerd/linkerd2-proxy#965)
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

Successfully merging this pull request may close these issues.

3 participants