diff options
| author | 2025-11-17 00:00:00 +0000 | |
|---|---|---|
| committer | 2025-11-17 00:00:00 +0000 | |
| commit | 1dcb92427c23d0a8b23c0154b892243c749afa5a (patch) | |
| tree | 0683fa19e05d2ea0ceac324dafdcd49eb6cdb2ec | |
| parent | Add internal todo (diff) | |
| signature | ||
Compute checksum when reading packfiles
| -rw-r--r-- | pack_idx.go | 17 | ||||
| -rw-r--r-- | pack_midx.go | 18 | ||||
| -rw-r--r-- | pack_pack.go | 24 | ||||
| -rw-r--r-- | repo.go | 2 |
4 files changed, 58 insertions, 3 deletions
diff --git a/pack_idx.go b/pack_idx.go index 03397286..3cb89701 100644 --- a/pack_idx.go +++ b/pack_idx.go @@ -196,6 +196,23 @@ func (pi *packIndex) parse(buf []byte) error { pi.numObjects = nobj pi.names = buf[namesStart:namesEnd] pi.crcs = buf[crcStart:crcEnd] + + if len(buf) < 2*pi.repo.hashSize { + return ErrInvalidObject + } + idxChecksumStart := len(buf) - pi.repo.hashSize + idxChecksumInFile := buf[idxChecksumStart:] + + hashFn, ok := hashFuncs[pi.repo.hashSize] + if !ok { + return fmt.Errorf("furgit: unsupported hash size %d", pi.repo.hashSize) + } + + computedHash := hashFn(buf[:idxChecksumStart]) + if !bytes.Equal(computedHash.data[:pi.repo.hashSize], idxChecksumInFile) { + return fmt.Errorf("furgit: index checksum mismatch in %s", pi.idxRel) + } + return nil } diff --git a/pack_midx.go b/pack_midx.go index 748bdaf6..04151dfe 100644 --- a/pack_midx.go +++ b/pack_midx.go @@ -1,6 +1,7 @@ package furgit import ( + "bytes" "fmt" "os" "path/filepath" @@ -235,6 +236,23 @@ func (midx *multiPackIndex) parse(buf []byte) error { midx.oids = oids midx.offsets = offsets midx.largeOffs = largeOffs + + if len(buf) < midx.repo.hashSize { + return ErrInvalidObject + } + midxChecksumStart := len(buf) - midx.repo.hashSize + midxChecksumInFile := buf[midxChecksumStart:] + + hashFn, ok := hashFuncs[midx.repo.hashSize] + if !ok { + return fmt.Errorf("furgit: unsupported hash size %d", midx.repo.hashSize) + } + + computedHash := hashFn(buf[:midxChecksumStart]) + if !bytes.Equal(computedHash.data[:midx.repo.hashSize], midxChecksumInFile) { + return fmt.Errorf("furgit: multi-pack-index checksum mismatch") + } + return nil } diff --git a/pack_pack.go b/pack_pack.go index 5c2c8628..6d740b73 100644 --- a/pack_pack.go +++ b/pack_pack.go @@ -487,7 +487,7 @@ type packFile struct { closeMu sync.Once } -func openPackFile(absPath, rel string) (*packFile, error) { +func openPackFile(absPath, rel string, hashSize int) (*packFile, error) { f, err := os.Open(absPath) if err != nil { return nil, err @@ -498,7 +498,7 @@ func openPackFile(absPath, rel string) (*packFile, error) { _ = f.Close() return nil, err } - if stat.Size() < 12 { + if stat.Size() < 12+int64(hashSize) { _ = f.Close() return nil, ErrInvalidObject } @@ -532,6 +532,26 @@ func openPackFile(absPath, rel string) (*packFile, error) { _ = syscall.Munmap(region) return nil, err } + + if len(region) < hashSize { + _ = syscall.Munmap(region) + return nil, ErrInvalidObject + } + dataEnd := len(region) - hashSize + checksumInFile := region[dataEnd:] + + hashFn, ok := hashFuncs[hashSize] + if !ok { + _ = syscall.Munmap(region) + return nil, fmt.Errorf("furgit: unsupported hash size %d", hashSize) + } + + computedHash := hashFn(region[:dataEnd]) + if !bytes.Equal(computedHash.data[:hashSize], checksumInFile) { + _ = syscall.Munmap(region) + return nil, fmt.Errorf("furgit: pack checksum mismatch in %s", rel) + } + return &packFile{ relPath: rel, size: stat.Size(), @@ -132,7 +132,7 @@ func (repo *Repository) packFile(rel string) (*packFile, error) { if pf, ok := repo.packFiles.Load(rel); ok { return pf.(*packFile), nil } - pf, err := openPackFile(repo.repoPath(rel), rel) + pf, err := openPackFile(repo.repoPath(rel), rel, repo.hashSize) if err != nil { return nil, err } |
