From 32b2aa49f160b4a5e706b7d7d7ad12c5b4f49091 Mon Sep 17 00:00:00 2001 From: Feng Ruohang Date: Sat, 29 Aug 2026 18:36:02 +0800 Subject: [PATCH] fix: reject composite CRC64NVME completion Remove the remaining type-only canonicalization at CompleteMultipartUpload while preserving legacy uploads stored as FULL_OBJECT. Signed-off-by: Feng Ruohang --- cmd/erasure-multipart-fullobject_test.go | 9 ++++++--- cmd/erasure-multipart.go | 8 +------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/cmd/erasure-multipart-fullobject_test.go b/cmd/erasure-multipart-fullobject_test.go index b9d71aa21..c8f3dde11 100644 --- a/cmd/erasure-multipart-fullobject_test.go +++ b/cmd/erasure-multipart-fullobject_test.go @@ -516,7 +516,7 @@ func testAPICompleteMultipartChecksumTypeMismatch(obj ObjectLayer, instanceType, } }) - t.Run("crc64nvme-composite-remains-canonicalized", func(t *testing.T) { + t.Run("crc64nvme-composite-completion-is-rejected", func(t *testing.T) { crc64Type := hash.ChecksumCRC64NVME objectName := "type-mismatch/crc64nvme-composite" uploadID := newMultipartUploadHTTP(t, apiRouter, credentials, bucketName, objectName, @@ -527,8 +527,11 @@ func testAPICompleteMultipartChecksumTypeMismatch(obj ObjectLayer, instanceType, crc64Type.Key(): mustChecksum(t, crc64Type, full), xhttp.AmzChecksumType: xhttp.AmzChecksumTypeComposite, }) - if rec.Code != http.StatusOK { - t.Fatalf("%s: CRC64NVME canonicalization changed: %d %s", instanceType, rec.Code, rec.Body.String()) + if rec.Code != http.StatusBadRequest || apiErrorCode(t, rec) != "BadDigest" { + t.Fatalf("%s: CRC64NVME composite completion returned %d %s", instanceType, rec.Code, rec.Body.String()) + } + if _, err := obj.GetObjectInfo(t.Context(), bucketName, objectName, ObjectOptions{}); err == nil { + t.Fatalf("%s: object was created despite a rejected CRC64NVME checksum type", instanceType) } }) } diff --git a/cmd/erasure-multipart.go b/cmd/erasure-multipart.go index d99492368..be5afb7c6 100644 --- a/cmd/erasure-multipart.go +++ b/cmd/erasure-multipart.go @@ -1185,13 +1185,7 @@ func (er erasureObjects) CompleteMultipartUpload(ctx context.Context, bucket str } } if opts.wantChecksumType != "" { - providedObjectType := opts.wantChecksumType - // CRC64NVME is always canonicalized to FULL_OBJECT. Preserve this - // behavior until its exact AWS wire semantics have been probed. - if checksumType.Base().Is(hash.ChecksumCRC64NVME) { - providedObjectType = xhttp.AmzChecksumTypeFullObject - } - if providedObjectType != expectedType.ObjType() { + if opts.wantChecksumType != expectedType.ObjType() { return oi, completeMultipartChecksumTypeMismatch(opts.wantChecksumType, expectedType.ObjType()) } }