diff options
author | Florian Klink <flokli@flokli.de> | 2024-01-31T17·03+0200 |
---|---|---|
committer | clbot <clbot@tvl.fyi> | 2024-02-02T16·26+0000 |
commit | 9504015031a7299f22a9827ff0eded74a95c66f8 (patch) | |
tree | 279d5e62003b31731c531336b076be8cdeeab229 /tvix/castore | |
parent | 5ad5a0da00622beb713fb85520821212416b02f9 (diff) |
feat(tvix/castore/blobsvc): validate StatBlobResponse r/7470
All chunks must have valid blake3 digests. It is allowed to send an empty list, if no more granular chunking is available. Change-Id: I7ecb53579cdf40fd938bb68a85685751b4d3626f Reviewed-on: https://cl.tvl.fyi/c/depot/+/10726 Tested-by: BuildkiteCI Reviewed-by: Connor Brewster <cbrewster@hey.com> Autosubmit: flokli <flokli@flokli.de>
Diffstat (limited to 'tvix/castore')
-rw-r--r-- | tvix/castore/src/blobservice/grpc.rs | 4 | ||||
-rw-r--r-- | tvix/castore/src/proto/mod.rs | 25 |
2 files changed, 29 insertions, 0 deletions
diff --git a/tvix/castore/src/blobservice/grpc.rs b/tvix/castore/src/blobservice/grpc.rs index acc0125c82ed..d98a9b517724 100644 --- a/tvix/castore/src/blobservice/grpc.rs +++ b/tvix/castore/src/blobservice/grpc.rs @@ -129,6 +129,10 @@ impl BlobService for GRPCBlobService { Err(e) => Err(io::Error::new(io::ErrorKind::Other, e)), Ok(resp) => { let resp = resp.into_inner(); + + resp.validate() + .map_err(|e| std::io::Error::new(io::ErrorKind::InvalidData, e))?; + if resp.chunks.is_empty() { warn!("chunk list is empty"); } diff --git a/tvix/castore/src/proto/mod.rs b/tvix/castore/src/proto/mod.rs index edf042e3dfa6..59f5c1fdf3f6 100644 --- a/tvix/castore/src/proto/mod.rs +++ b/tvix/castore/src/proto/mod.rs @@ -56,6 +56,14 @@ pub enum ValidateNodeError { InvalidSymlinkTarget(Vec<u8>), } +/// Errors that occur during StatBlobResponse validation +#[derive(Debug, PartialEq, Eq, thiserror::Error)] +pub enum ValidateStatBlobResponseError { + /// Invalid digest length encountered + #[error("Invalid digest length {0} for chunk #{1}")] + InvalidDigestLen(usize, usize), +} + /// Checks a Node name for validity as an intermediate node. /// We disallow slashes, null bytes, '.', '..' and the empty string. fn validate_node_name(name: &[u8]) -> Result<(), ValidateNodeError> { @@ -299,6 +307,23 @@ impl Directory { } } +impl StatBlobResponse { + /// Validates a StatBlobResponse. All chunks must have valid blake3 digests. + /// It is allowed to send an empty list, if no more granular chunking is + /// available. + pub fn validate(&self) -> Result<(), ValidateStatBlobResponseError> { + for (i, chunk) in self.chunks.iter().enumerate() { + if chunk.digest.len() != blake3::KEY_LEN { + return Err(ValidateStatBlobResponseError::InvalidDigestLen( + chunk.digest.len(), + i, + )); + } + } + Ok(()) + } +} + /// Struct to hold the state of an iterator over all nodes of a Directory. /// /// Internally, this keeps peekable Iterators over all three lists of a |