fix(storage): validate internode paths and erasure payloads

Storage REST request bodies and Grid RPC frames bypass the HTTP validity middleware, allowing wire-supplied paths and malformed FileInfo values to reach xlStorage unchecked.

Wrap the remotely exposed StorageAPI with a guard that covers every path-bearing method, including nested metadata fields. Reject traversal and destructive volume-root aliases before path cleaning can erase them, and validate erasure geometry and part sizes at the same wire boundary. Keep a raw-volume check in getVolDir for peer-S3 calls that bypass the wrapper.

Reflection, fuzz, traversal, peer-S3, compatibility, and malformed-erasure tests pin the complete method surface and prove that legal object names remain accepted.

Co-authored-by: ChatGPT <noreply@openai.com>
Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Feng Ruohang
2026-08-04 22:40:43 +08:00
parent a36fd8fffb
commit ca7baa670d
6 changed files with 1370 additions and 1 deletions
+16
View File
@@ -788,6 +788,22 @@ func (s *xlStorage) getVolDir(volume string) (string, error) {
if volume == "" || volume == "." || volume == ".." {
return "", errVolumeNotFound
}
// Reject traversal smuggled inside the volume name itself, e.g. "../" or
// "..\", which the equality checks above do not catch.
//
// This must be evaluated on the raw argument and never on the joined
// result: pathJoin() below runs path.Clean() against an absolute
// drivePath, and Clean() *erases* leading ".." on an absolute path
// ("/drive/../../etc" becomes "/etc"), so a check placed after the join
// would silently accept an escaped path.
//
// This is also the only containment control covering callers that never
// reach storageRESTServer.getStorage() - notably the peer-S3 bucket RPCs
// (MakeBucket/HeadBucket/DeleteBucket/HealBucket), which drive
// MakeVol/StatVol/DeleteVol straight off globalLocalDrivesMap.
if hasBadPathComponent(volume) {
return "", errVolumeNotFound
}
volumeDir := pathJoin(s.drivePath, volume)
return volumeDir, nil
}