Skip to content

Commit 2cdcacc

Browse files
committed
fix(share): cap gzip media restore
1 parent 3fdf12f commit 2cdcacc

2 files changed

Lines changed: 30 additions & 3 deletions

File tree

internal/share/share.go

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ const shardFlushRows = 1024
4444

4545
var maxShardBytes int64 = 40 * 1024 * 1024
4646

47+
// The share manifest stores compressed media size, not raw size. Keep gzip
48+
// restore/hash paths bounded so a malformed snapshot cannot expand forever.
49+
var maxSharedMediaDecompressedBytes int64 = 1 << 30
50+
4751
var SnapshotTables = []string{
4852
"guilds",
4953
"channels",
@@ -1238,8 +1242,7 @@ func restoreGzipFile(target, source string) error {
12381242
}
12391243
defer func() { _ = gz.Close() }()
12401244
return writeAtomicFile(target, func(tmp *os.File) error {
1241-
_, err := io.Copy(tmp, gz)
1242-
return err
1245+
return copyWithLimit(tmp, gz, maxSharedMediaDecompressedBytes)
12431246
})
12441247
}
12451248

@@ -1268,12 +1271,26 @@ func gzipFileSHA256(path string) (string, error) {
12681271
}
12691272
defer func() { _ = gz.Close() }()
12701273
hasher := sha256.New()
1271-
if _, err := io.Copy(hasher, gz); err != nil {
1274+
if err := copyWithLimit(hasher, gz, maxSharedMediaDecompressedBytes); err != nil {
12721275
return "", err
12731276
}
12741277
return hex.EncodeToString(hasher.Sum(nil)), nil
12751278
}
12761279

1280+
func copyWithLimit(dst io.Writer, src io.Reader, limit int64) error {
1281+
if limit <= 0 {
1282+
return errors.New("media decompression limit must be positive")
1283+
}
1284+
n, err := io.Copy(dst, io.LimitReader(src, limit+1))
1285+
if err != nil {
1286+
return err
1287+
}
1288+
if n > limit {
1289+
return fmt.Errorf("media decompressed size exceeds %d bytes", limit)
1290+
}
1291+
return nil
1292+
}
1293+
12771294
func sameFileHash(path, hash string) bool {
12781295
current, err := fileSHA256(path)
12791296
return err == nil && current == hash

internal/share/share_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,16 @@ func TestMediaCopyHashHelpers(t *testing.T) {
613613
require.Error(t, copyGzipFile(filepath.Join(dir, "missing.gz"), filepath.Join(dir, "missing-source.bin")))
614614
require.Error(t, restoreGzipFile(filepath.Join(dir, "bad.bin"), source))
615615
require.Error(t, restoreGzipFile(filepath.Join(dir, "bad.bin"), filepath.Join(dir, "missing.gz")))
616+
617+
oldLimit := maxSharedMediaDecompressedBytes
618+
maxSharedMediaDecompressedBytes = 4
619+
t.Cleanup(func() { maxSharedMediaDecompressedBytes = oldLimit })
620+
_, err = gzipFileSHA256(gzipTarget)
621+
require.Error(t, err)
622+
require.Contains(t, err.Error(), "decompressed size")
623+
err = restoreGzipFile(filepath.Join(dir, "too-large.bin"), gzipTarget)
624+
require.Error(t, err)
625+
require.Contains(t, err.Error(), "decompressed size")
616626
}
617627

618628
func TestPublicPermissionHelpers(t *testing.T) {

0 commit comments

Comments
 (0)