From 952a5c502e032c01591d5bafd6489e482937dc24 Mon Sep 17 00:00:00 2001 From: Javan Date: Fri, 11 Sep 2026 12:03:37 -0300 Subject: [PATCH] uucore: reject over-length BLAKE2b digests when checking When verifying a checksum file, the BLAKE2b output length was inferred from the digest found in the file and handed to the hasher unchecked. A digest longer than the 64 bytes BLAKE2b maximum made blake2b_simd fail its own length assertion and abort the process, instead of the line being reported as malformed. Route that inferred length through parse_blake_length, like the --length and tagged-line paths already do, and treat a rejected length as an improperly formatted line. This matches GNU, which skips such a line and exits 1 with "no properly formatted checksum lines found". HashLength::from_bytes loses its last caller with this change, so drop it. Fixes #14487 --- src/uucore/src/lib/features/checksum/mod.rs | 6 ------ src/uucore/src/lib/features/checksum/validate.rs | 7 ++++++- tests/by-util/test_cksum.rs | 14 ++++++++++++++ 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/uucore/src/lib/features/checksum/mod.rs b/src/uucore/src/lib/features/checksum/mod.rs index 40c5bb421f9..36df7c5bc8c 100644 --- a/src/uucore/src/lib/features/checksum/mod.rs +++ b/src/uucore/src/lib/features/checksum/mod.rs @@ -260,12 +260,6 @@ pub struct HashLength { } impl HashLength { - #[must_use] - #[inline] - pub(crate) fn from_bytes(n: usize) -> Self { - Self { bit_len: n * 8 } - } - #[must_use] #[inline] pub fn from_bits(n: usize) -> Self { diff --git a/src/uucore/src/lib/features/checksum/validate.rs b/src/uucore/src/lib/features/checksum/validate.rs index 50465fbb415..f53c756d75f 100644 --- a/src/uucore/src/lib/features/checksum/validate.rs +++ b/src/uucore/src/lib/features/checksum/validate.rs @@ -791,7 +791,12 @@ fn process_non_algo_based_line( // bits except when dealing with blake2b, sha2 and sha3, where we will // detect the length. let algo_len = match cli_algo_kind { - ak::Blake2b | ak::Blake3 => Some(HashLength::from_bytes(expected_checksum.len())), + // An over-length digest makes this a malformed line for GNU, not a + // fatal error. + algo @ (ak::Blake2b | ak::Blake3) => Some( + parse_blake_length(algo, BlakeLength::Int(expected_checksum.len() * 8)) + .map_err(|_| LineCheckError::ImproperlyFormatted)?, + ), ak::Sha2 | ak::Sha3 => { // multiplication by 8 to get the number of bits Some( diff --git a/tests/by-util/test_cksum.rs b/tests/by-util/test_cksum.rs index 241777f289f..ec77c77e822 100644 --- a/tests/by-util/test_cksum.rs +++ b/tests/by-util/test_cksum.rs @@ -1676,6 +1676,20 @@ fn test_md5_bits() { .stderr_contains("f: no properly formatted checksum lines found"); } +#[test] +fn test_blake2b_check_digest_too_long() { + let (at, mut ucmd) = at_and_ucmd!(); + // The referenced file must exist: the digest length is only used once the + // line is accepted and the file is about to be hashed. + at.write("f1", "content\n"); + // 65 bytes, above the 64 bytes BLAKE2b maximum. + at.write("sums", &format!("{} f1\n", "a".repeat(130))); + + ucmd.args(&["-a", "blake2b", "-c", "sums"]) + .fails_with_code(1) + .stderr_contains("sums: no properly formatted checksum lines found"); +} + #[test] fn test_blake2b_bits() { let (at, mut ucmd) = at_and_ucmd!();