Coverage Report

Created: 2025-07-12 06:48

/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
});