/src/tar-rs/fuzz/fuzz_targets/archive.rs
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2024 Google LLC |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | #![no_main] |
16 | | |
17 | | use arbitrary::{Arbitrary, Unstructured}; |
18 | | use cap_std::fs::Dir; |
19 | | use cap_std::ambient_authority; |
20 | | use derive_arbitrary::Arbitrary; |
21 | | use libfuzzer_sys::fuzz_target; |
22 | | use std::io::{Cursor, Write}; |
23 | | use tar::{Archive, Builder, EntryType, Header}; |
24 | | use tempfile::tempdir; |
25 | | |
26 | | // Define ArchiveEntry for arbitrary crate |
27 | 1.24M | #[derive(Debug, Arbitrary)] Unexecuted instantiation: <archive::ArchiveEntry as arbitrary::Arbitrary>::arbitrary_take_rest::{closure#0} Unexecuted instantiation: <archive::ArchiveEntry as arbitrary::Arbitrary>::arbitrary_take_rest::{closure#1} Unexecuted instantiation: <archive::ArchiveEntry as arbitrary::Arbitrary>::arbitrary_take_rest::{closure#2} Unexecuted instantiation: <archive::ArchiveEntry as arbitrary::Arbitrary>::try_size_hint::{closure#0} <archive::ArchiveEntry as arbitrary::Arbitrary>::arbitrary::{closure#0} Line | Count | Source | 27 | 158 | #[derive(Debug, Arbitrary)] |
<archive::ArchiveEntry as arbitrary::Arbitrary>::arbitrary::{closure#1} Line | Count | Source | 27 | 1.24M | #[derive(Debug, Arbitrary)] |
<archive::ArchiveEntry as arbitrary::Arbitrary>::arbitrary::{closure#2} Line | Count | Source | 27 | 158 | #[derive(Debug, Arbitrary)] |
|
28 | | struct ArchiveEntry { |
29 | | path: String, |
30 | | entry_type: u8, |
31 | | content: Vec<u8>, |
32 | | } |
33 | | |
34 | | // Define FuzzInput for arbitrary crate |
35 | 1.75k | #[derive(Debug, Arbitrary)] Unexecuted instantiation: <archive::FuzzInput as arbitrary::Arbitrary>::arbitrary_take_rest::{closure#0} Unexecuted instantiation: <archive::FuzzInput as arbitrary::Arbitrary>::arbitrary_take_rest::{closure#1} Unexecuted instantiation: <archive::FuzzInput as arbitrary::Arbitrary>::arbitrary_take_rest::{closure#2} Unexecuted instantiation: <archive::FuzzInput as arbitrary::Arbitrary>::try_size_hint::{closure#0} Unexecuted instantiation: <archive::FuzzInput as arbitrary::Arbitrary>::arbitrary::{closure#0} <archive::FuzzInput as arbitrary::Arbitrary>::arbitrary::{closure#1} Line | Count | Source | 35 | 1.75k | #[derive(Debug, Arbitrary)] |
Unexecuted instantiation: <archive::FuzzInput as arbitrary::Arbitrary>::arbitrary::{closure#2} |
36 | | struct FuzzInput { |
37 | | entries: Vec<ArchiveEntry>, |
38 | | } |
39 | | |
40 | | fuzz_target!(|data: &[u8]| { |
41 | | // Prepare FuzzInput with Arbitrary |
42 | | let mut unstructured = Unstructured::new(data); |
43 | | let input: FuzzInput = match FuzzInput::arbitrary(&mut unstructured) { |
44 | | Ok(val) => val, |
45 | | Err(_) => return, |
46 | | }; |
47 | | |
48 | | // Create a sandbox directory with cap_std |
49 | | let temp_dir = match tempdir() { |
50 | | Ok(dir) => dir, |
51 | | Err(_) => return, |
52 | | }; |
53 | | let sandbox_dir = match Dir::open_ambient_dir(temp_dir.path(), ambient_authority()) { |
54 | | Ok(dir) => dir, |
55 | | Err(_) => return, |
56 | | }; |
57 | | let temp_file_path = "archive_file.tar"; |
58 | | let mut builder = Builder::new(Vec::new()); |
59 | | |
60 | | // Iterate through the archive entries to build a tar structure |
61 | | for entry in &input.entries { |
62 | | let mut header = Header::new_gnu(); |
63 | | |
64 | | // Ensure content size is reasonable to avoid potential overflow issues |
65 | | let file_size = entry.content.len() as u64; |
66 | | if file_size > u32::MAX as u64 { |
67 | | continue; |
68 | | } |
69 | | header.set_size(file_size); |
70 | | |
71 | | // Determine the entry type from fuzzed data |
72 | | let entry_type = match entry.entry_type % 5 { |
73 | | 0 => EntryType::Regular, |
74 | | 1 => EntryType::Directory, |
75 | | 2 => EntryType::Symlink, |
76 | | 3 => EntryType::hard_link(), |
77 | | _ => EntryType::character_special(), |
78 | | }; |
79 | | header.set_entry_type(entry_type); |
80 | | |
81 | | // Process entry types using cap_std sandbox |
82 | | match entry_type { |
83 | | EntryType::Directory => { |
84 | | if let Err(_) = sandbox_dir.create_dir_all(&entry.path) { |
85 | | continue; |
86 | | } |
87 | | if builder.append_dir(&entry.path, &entry.path).is_err() { |
88 | | continue; |
89 | | } |
90 | | } |
91 | | EntryType::Regular => { |
92 | | let mut cursor = Cursor::new(entry.content.clone()); |
93 | | if builder.append_data(&mut header, entry.path.as_str(), &mut cursor).is_err() { |
94 | | continue; |
95 | | } |
96 | | } |
97 | | _ => { |
98 | | // Handle other types with appropriate mock content or skip unsupported |
99 | | let mut cursor = Cursor::new(entry.content.clone()); |
100 | | if builder.append_data(&mut header, entry.path.as_str(), &mut cursor).is_err() { |
101 | | continue; |
102 | | } |
103 | | } |
104 | | } |
105 | | } |
106 | | |
107 | | // Write the builder content to the temporary tar file within the sandbox |
108 | | if let Ok(mut temp_file) = sandbox_dir.create(temp_file_path) { |
109 | | if temp_file.write_all(&builder.into_inner().unwrap_or_default()).is_ok() { |
110 | | let mut archive = Archive::new(temp_file); |
111 | | if let Ok(entries) = archive.entries() { |
112 | | for entry in entries { |
113 | | if entry.is_err() { |
114 | | return; |
115 | | } |
116 | | } |
117 | | } |
118 | | } |
119 | | } |
120 | | |
121 | | // Cleanup temp directory and sandbox directory |
122 | | drop(sandbox_dir); |
123 | | drop(temp_dir); |
124 | | }); |