From 42a09339204915c15cf5a539418e05e5a74eb0bd Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Wed, 27 Mar 2024 20:18:35 +0100 Subject: [PATCH 1/2] relax uid restriction in fuzzer after #32 --- fuzz/src/lib.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/fuzz/src/lib.rs b/fuzz/src/lib.rs index 80c98d3..0dae460 100644 --- a/fuzz/src/lib.rs +++ b/fuzz/src/lib.rs @@ -94,11 +94,16 @@ impl Arbitrary<'_> for Timestamp { } } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, Arbitrary)] struct Uid(u32); -impl Arbitrary<'_> for Uid { - fn arbitrary(u: &mut Unstructured<'_>) -> arbitrary::Result { - u.int_in_range(0..=999_999).map(Uid) // TODO: Deal with entire range (#29) +impl PartialEq for Uid { + fn eq(&self, other: &Uid) -> bool { + truncated_ascii(self.0.to_string(), 6) == truncated_ascii(other.0.to_string(), 6) } } + +fn truncated_ascii(mut ascii: String, width: usize) -> String { + ascii.truncate(width); + ascii +} From d265dd1b8b6bfeea8adc6f0c8cf93ec649dfb7e5 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Wed, 27 Mar 2024 20:36:46 +0100 Subject: [PATCH 2/2] cap more field sizes and relax fuzzer --- fuzz/src/lib.rs | 28 ++++++++++++++-------------- src/header.rs | 21 +++++++++++++++------ 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/fuzz/src/lib.rs b/fuzz/src/lib.rs index 0dae460..ee4733a 100644 --- a/fuzz/src/lib.rs +++ b/fuzz/src/lib.rs @@ -1,4 +1,5 @@ use arbitrary::{Arbitrary, Unstructured}; +use std::cmp::min; #[derive(Clone, Default, Debug, Eq, PartialEq, Arbitrary)] pub struct Model { @@ -76,21 +77,21 @@ impl Arbitrary<'_> for Identifier { } } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, Arbitrary)] struct Mode(u32); -impl Arbitrary<'_> for Mode { - fn arbitrary(u: &mut Unstructured<'_>) -> arbitrary::Result { - u32::arbitrary(u).map(|v| Mode(v & 0o7777)) +impl PartialEq for Mode { + fn eq(&self, other: &Mode) -> bool { + self.0 & 0o7777_7777 == other.0 & 0o7777_7777 } } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, Arbitrary)] struct Timestamp(u64); -impl Arbitrary<'_> for Timestamp { - fn arbitrary(u: &mut Unstructured<'_>) -> arbitrary::Result { - u.int_in_range(0..=999_999_999_999).map(Timestamp) // TODO: Deal with entire range +impl PartialEq for Timestamp { + fn eq(&self, other: &Timestamp) -> bool { + min(self.0, 999_999_999_999) == min(other.0, 999_999_999_999) } } @@ -99,11 +100,10 @@ struct Uid(u32); impl PartialEq for Uid { fn eq(&self, other: &Uid) -> bool { - truncated_ascii(self.0.to_string(), 6) == truncated_ascii(other.0.to_string(), 6) + let mut left = self.0.to_string(); + left.truncate(6); + let mut right = other.0.to_string(); + right.truncate(6); + left == right } } - -fn truncated_ascii(mut ascii: String, width: usize) -> String { - ascii.truncate(width); - ascii -} diff --git a/src/header.rs b/src/header.rs index 9d9d556..1d1cc46 100644 --- a/src/header.rs +++ b/src/header.rs @@ -1,3 +1,4 @@ +use std::cmp::min; use std::collections::HashMap; use std::fs::Metadata; use std::io::{self, Error, ErrorKind, Read, Result, Write}; @@ -244,10 +245,10 @@ impl Header { writer, "#1/{:<13}{:<12}{:<6.6}{:<6.6}{:<8o}{:<10}`", padded_length, - self.mtime, + cap_mtime(self.mtime), self.uid.to_string(), self.gid.to_string(), - self.mode, + cap_mode(self.mode), self.size + padded_length as u64 )?; writer.write_all(&self.identifier)?; @@ -258,10 +259,10 @@ impl Header { writeln!( writer, "{:<12}{:<6.6}{:<6.6}{:<8o}{:<10}`", - self.mtime, + cap_mtime(self.mtime), self.uid.to_string(), self.gid.to_string(), - self.mode, + cap_mode(self.mode), self.size )?; } @@ -287,16 +288,24 @@ impl Header { writeln!( writer, "{:<12}{:<6.6}{:<6.6}{:<8o}{:<10}`", - self.mtime, + cap_mtime(self.mtime), self.uid.to_string(), self.gid.to_string(), - self.mode, + cap_mode(self.mode), self.size )?; Ok(()) } } +fn cap_mtime(mtime: u64) -> u64 { + min(mtime, 999_999_999_999) // Closest representable timestamp +} + +fn cap_mode(mode: u32) -> u32 { + mode & 0o7777_7777 // Preserve as many bits as possible +} + fn parse_number(field_name: &str, bytes: &[u8], radix: u32) -> Result { if let Ok(string) = str::from_utf8(bytes) { if let Ok(value) = u64::from_str_radix(string.trim_end(), radix) {