fix: reject composite CRC64NVME trailers

Apply the full-object-only rule to declared streaming checksum trailers and cover the HTTP mutation path.

Signed-off-by: Feng Ruohang <rh@vonng.com>
This commit is contained in:
Feng Ruohang
2026-08-29 18:15:51 +08:00
parent d28885d0e5
commit d4c8da162b
3 changed files with 33 additions and 1 deletions
+18
View File
@@ -58,4 +58,22 @@ func testAPIPutObjectRejectsCRC64Composite(obj ObjectLayer, instanceType, bucket
if _, err := obj.GetObjectInfo(t.Context(), bucketName, object, ObjectOptions{}); !isErrObjectNotFound(err) { if _, err := obj.GetObjectInfo(t.Context(), bucketName, object, ObjectOptions{}); !isErrObjectNotFound(err) {
t.Fatalf("%s: rejected PutObject stored an object: %v", instanceType, err) t.Fatalf("%s: rejected PutObject stored an object: %v", instanceType, err)
} }
trailerObject := "checksums/crc64-composite-trailer"
req, err = newTestSignedRequestV4(http.MethodPut, getPutObjectURL("", bucketName, trailerObject),
int64(len(data)), bytes.NewReader(data), credentials.AccessKey, credentials.SecretKey, map[string]string{
xhttp.AmzTrailer: xhttp.AmzChecksumCRC64NVME,
xhttp.AmzChecksumType: xhttp.AmzChecksumTypeComposite,
})
if err != nil {
t.Fatal(err)
}
rec = httptest.NewRecorder()
apiRouter.ServeHTTP(rec, req)
if rec.Code != http.StatusBadRequest || apiErrorCode(t, rec) != "InvalidArgument" {
t.Fatalf("%s: trailing CRC64NVME/COMPOSITE PutObject returned %d %s", instanceType, rec.Code, rec.Body.String())
}
if _, err := obj.GetObjectInfo(t.Context(), bucketName, trailerObject, ObjectOptions{}); !isErrObjectNotFound(err) {
t.Fatalf("%s: rejected trailing PutObject stored an object: %v", instanceType, err)
}
} }
+5 -1
View File
@@ -716,7 +716,11 @@ func GetContentChecksum(h http.Header) (*Checksum, error) {
return nil, ErrInvalidChecksum return nil, ErrInvalidChecksum
} }
res.Type |= ChecksumFullObject res.Type |= ChecksumFullObject
case xhttp.AmzChecksumTypeComposite, "": case xhttp.AmzChecksumTypeComposite:
if res.Type.Base().Is(ChecksumCRC64NVME) {
return nil, ErrInvalidChecksum
}
case "":
default: default:
return nil, ErrInvalidChecksum return nil, ErrInvalidChecksum
} }
+10
View File
@@ -150,6 +150,16 @@ func TestChecksumAddToHeader(t *testing.T) {
} }
} }
func TestCRC64NVMECompositeTrailerIsInvalid(t *testing.T) {
h := http.Header{}
h.Set(xhttp.AmzTrailer, ChecksumCRC64NVME.Key())
h.Set(xhttp.AmzChecksumType, xhttp.AmzChecksumTypeComposite)
_, err := GetContentChecksum(h)
if !errors.Is(err, ErrInvalidChecksum) {
t.Fatalf("CRC64NVME/COMPOSITE trailer error = %v, want ErrInvalidChecksum", err)
}
}
// TestChecksumSerializeDeserialize checks AppendTo can be reversed by ChecksumFromBytes // TestChecksumSerializeDeserialize checks AppendTo can be reversed by ChecksumFromBytes
func TestChecksumSerializeDeserialize(t *testing.T) { func TestChecksumSerializeDeserialize(t *testing.T) {
myData := []byte("this-is-a-checksum-data-test") myData := []byte("this-is-a-checksum-data-test")