Validate blob hashes, offsets and lengths from the destination (closes #155)
A blob hash read back from the downloaded snapshot database or the store listing was trusted unchecked. A hostile remote could set a hash such as "aa/../../etc" and have a decrypted blob written outside the cache directory, or feed a short or negative value that panicked a command. blobDiskCache.path now refuses any key with a path separator, and ReadAt rejects a negative offset or length, bounding so a sum cannot overflow past the check. A new isBlobHash helper gates FetchBlob, shallow and deep verify, and restore: buildBlobIndexes rejects every hash from the snapshot database before any fetch. The blobs/ and metadata/ listings skip a non-conforming name, and short-hash prefixes in log and error text go through a panic-safe shortHash helper. Model: opus-4-8
This commit was merged in pull request #195.
This commit is contained in:
@@ -425,12 +425,12 @@ func (s *restoreSession) downloadNextBlobSet(plan *restorePlan) (bool, error) {
|
||||
|
||||
blob, ok := s.blobByHash[hash]
|
||||
if !ok {
|
||||
return false, fmt.Errorf("%w: %s", errBlobMissingFromIndex, hash[:16])
|
||||
return false, fmt.Errorf("%w: %s", errBlobMissingFromIndex, shortHash(hash))
|
||||
}
|
||||
|
||||
err := s.downloadBlobToCache(hash, blob.CompressedSize)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("downloading blob %s: %w", hash[:16], err)
|
||||
return false, fmt.Errorf("downloading blob %s: %w", shortHash(hash), err)
|
||||
}
|
||||
|
||||
s.result.BlobsDownloaded++
|
||||
@@ -474,6 +474,16 @@ func (v *Vaultik) buildBlobIndexes(
|
||||
blobByHash := make(map[string]*database.Blob, len(blobsByID))
|
||||
for id, blob := range blobsByID {
|
||||
hash := blob.Hash.String()
|
||||
|
||||
// The snapshot database is untrusted. A hash that is not 64
|
||||
// lowercase hex characters could steer a later fetch to a path
|
||||
// outside the cache directory, so reject it here, before any
|
||||
// blob is downloaded.
|
||||
if !isBlobHash(hash) {
|
||||
return nil, nil, fmt.Errorf(
|
||||
"%w: %s", errInvalidBlobHash, shortHash(hash))
|
||||
}
|
||||
|
||||
blobIDToHash[id] = hash
|
||||
blobByHash[hash] = blob
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user