[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1036078: marked as done (unblock: docker-registry/2.8.2+ds1-1)



Your message dated Tue, 16 May 2023 20:54:35 +0000
with message-id <E1pz1gp-003uED-4Q@respighi.debian.org>
and subject line unblock docker-registry
has caused the Debian Bug report #1036078,
regarding unblock: docker-registry/2.8.2+ds1-1
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
1036078: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1036078
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock
X-Debbugs-Cc: docker-registry@packages.debian.org, zhsj@debian.org
Control: affects -1 + src:docker-registry

Please unblock package docker-registry

[ Reason ]
Upstream micro release for CVE-2023-2253 (Catalog API endpoint can lead to OOM
via malicious user input).

[ Impact ]
Fix security issue.

[ Tests ]
New unittest is added. The package has autopkgtest.

[ Risks ]

The debdiff contains some noise code style changes, otherwise they are trivial.

[ Checklist ]
  [x] all changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in testing

[ Other info ]
I attached a filtered debdiff, with following command,

 filterdiff --exclude '*/releases/*' --exclude '*/script/*' --exclude '*/.github/*' \
   --exclude '*.hcl'  --exclude '*.yml' --exclude '*/Dockerfile' \
   --exclude '*/Makefile' --exclude '*/.mailmap'  --exclude '*_test.go'

unblock docker-registry/2.8.2+ds1-1
diff -Nru -w docker-registry-2.8.1+ds1/configuration/configuration.go docker-registry-2.8.2+ds1/configuration/configuration.go
--- docker-registry-2.8.1+ds1/configuration/configuration.go	2022-03-09 01:52:36.000000000 +0800
+++ docker-registry-2.8.2+ds1/configuration/configuration.go	2023-05-11 18:11:57.000000000 +0800
@@ -194,6 +194,7 @@
 	} `yaml:"redis,omitempty"`
 
 	Health Health `yaml:"health,omitempty"`
+	Catalog Catalog `yaml:"catalog,omitempty"`
 
 	Proxy Proxy `yaml:"proxy,omitempty"`
 
@@ -244,6 +245,16 @@
 	} `yaml:"policy,omitempty"`
 }
 
+// Catalog is composed of MaxEntries.
+// Catalog endpoint (/v2/_catalog) configuration, it provides the configuration
+// options to control the maximum number of entries returned by the catalog endpoint.
+type Catalog struct {
+	// Max number of entries returned by the catalog endpoint. Requesting n entries
+	// to the catalog endpoint will return at most MaxEntries entries.
+	// An empty or a negative value will set a default of 1000 maximum entries by default.
+	MaxEntries int `yaml:"maxentries,omitempty"`
+}
+
 // LogHook is composed of hook Level and Type.
 // After hooks configuration, it can execute the next handling automatically,
 // when defined levels of log message emitted.
@@ -670,6 +681,11 @@
 					if v0_1.Loglevel != Loglevel("") {
 						v0_1.Loglevel = Loglevel("")
 					}
+
+					if v0_1.Catalog.MaxEntries <= 0 {
+						v0_1.Catalog.MaxEntries = 1000
+					}
+
 					if v0_1.Storage.Type() == "" {
 						return nil, errors.New("no storage configuration provided")
 					}
diff -Nru -w docker-registry-2.8.1+ds1/context/doc.go docker-registry-2.8.2+ds1/context/doc.go
--- docker-registry-2.8.1+ds1/context/doc.go	2022-03-09 01:52:36.000000000 +0800
+++ docker-registry-2.8.2+ds1/context/doc.go	2023-05-11 18:11:57.000000000 +0800
@@ -15,7 +15,7 @@
 // The above will store the version in the context and will be available to
 // the logger.
 //
-// Logging
+// # Logging
 //
 // The most useful aspect of this package is GetLogger. This function takes
 // any context.Context interface and returns the current logger from the
@@ -65,7 +65,7 @@
 // added to the request context, is unique to that context and can have
 // request scoped variables.
 //
-// HTTP Requests
+// # HTTP Requests
 //
 // This package also contains several methods for working with http requests.
 // The concepts are very similar to those described above. We simply place the
diff -Nru -w docker-registry-2.8.1+ds1/context/http.go docker-registry-2.8.2+ds1/context/http.go
--- docker-registry-2.8.1+ds1/context/http.go	2022-03-09 01:52:36.000000000 +0800
+++ docker-registry-2.8.2+ds1/context/http.go	2023-05-11 18:11:57.000000000 +0800
@@ -246,11 +246,7 @@
 			return ctx.vars
 		}
 
-		if strings.HasPrefix(keyStr, "vars.") {
-			keyStr = strings.TrimPrefix(keyStr, "vars.")
-		}
-
-		if v, ok := ctx.vars[keyStr]; ok {
+		if v, ok := ctx.vars[strings.TrimPrefix(keyStr, "vars.")]; ok {
 			return v
 		}
 	}
diff -Nru -w docker-registry-2.8.1+ds1/debian/changelog docker-registry-2.8.2+ds1/debian/changelog
--- docker-registry-2.8.1+ds1/debian/changelog	2022-06-29 20:32:34.000000000 +0800
+++ docker-registry-2.8.2+ds1/debian/changelog	2023-05-13 23:21:12.000000000 +0800
@@ -1,3 +1,14 @@
+docker-registry (2.8.2+ds1-1) unstable; urgency=medium
+
+  * Team upload
+  * New upstream version 2.8.2+ds1
+    + CVE-2023-2253: Catalog API endpoint can lead to OOM via malicious user
+      input (Closes: #1035956)
+  * Drop patch merged by upstream
+    + 0009-Fix-panic-in-inmemory-driver.patch
+
+ -- Shengjing Zhu <zhsj@debian.org>  Sat, 13 May 2023 23:21:12 +0800
+
 docker-registry (2.8.1+ds1-2) unstable; urgency=medium
 
   [ Debian Janitor ]
diff -Nru -w docker-registry-2.8.1+ds1/debian/patches/0007-Skip-TestRegistryAsCacheMutationAPIs.patch docker-registry-2.8.2+ds1/debian/patches/0007-Skip-TestRegistryAsCacheMutationAPIs.patch
--- docker-registry-2.8.1+ds1/debian/patches/0007-Skip-TestRegistryAsCacheMutationAPIs.patch	2022-06-29 20:32:34.000000000 +0800
+++ docker-registry-2.8.2+ds1/debian/patches/0007-Skip-TestRegistryAsCacheMutationAPIs.patch	2023-05-13 23:21:12.000000000 +0800
@@ -12,10 +12,10 @@
  1 file changed, 1 insertion(+)
 
 diff --git a/registry/handlers/api_test.go b/registry/handlers/api_test.go
-index 2d3edc7..a07184b 100644
+index bf037d4..207e167 100644
 --- a/registry/handlers/api_test.go
 +++ b/registry/handlers/api_test.go
-@@ -2468,6 +2468,7 @@ func createRepository(env *testEnv, t *testing.T, imageName string, tag string)
+@@ -2728,6 +2728,7 @@ func createRepository(env *testEnv, t *testing.T, imageName string, tag string)
  // Test mutation operations on a registry configured as a cache.  Ensure that they return
  // appropriate errors.
  func TestRegistryAsCacheMutationAPIs(t *testing.T) {
diff -Nru -w docker-registry-2.8.1+ds1/debian/patches/0009-Fix-panic-in-inmemory-driver.patch docker-registry-2.8.2+ds1/debian/patches/0009-Fix-panic-in-inmemory-driver.patch
--- docker-registry-2.8.1+ds1/debian/patches/0009-Fix-panic-in-inmemory-driver.patch	2022-06-29 20:32:34.000000000 +0800
+++ docker-registry-2.8.2+ds1/debian/patches/0009-Fix-panic-in-inmemory-driver.patch	1970-01-01 08:00:00.000000000 +0800
@@ -1,23 +0,0 @@
-From: Shengjing Zhu <zhsj@debian.org>
-Date: Sun, 27 Mar 2022 19:38:07 +0800
-Subject: Fix panic in inmemory driver
-
-Forwarded: https://github.com/distribution/distribution/pull/3615
----
- registry/storage/driver/inmemory/mfs.go | 3 +++
- 1 file changed, 3 insertions(+)
-
-diff --git a/registry/storage/driver/inmemory/mfs.go b/registry/storage/driver/inmemory/mfs.go
-index 9a2865f..24eeef9 100644
---- a/registry/storage/driver/inmemory/mfs.go
-+++ b/registry/storage/driver/inmemory/mfs.go
-@@ -279,6 +279,9 @@ func (f *file) sectionReader(offset int64) io.Reader {
- }
- 
- func (f *file) ReadAt(p []byte, offset int64) (n int, err error) {
-+	if offset >= int64(len(f.data)) {
-+		return 0, io.EOF
-+	}
- 	return copy(p, f.data[offset:]), nil
- }
- 
diff -Nru -w docker-registry-2.8.1+ds1/debian/patches/series docker-registry-2.8.2+ds1/debian/patches/series
--- docker-registry-2.8.1+ds1/debian/patches/series	2022-06-29 20:32:34.000000000 +0800
+++ docker-registry-2.8.2+ds1/debian/patches/series	2023-05-13 23:21:12.000000000 +0800
@@ -6,4 +6,3 @@
 0006-Skip-TestHTTPChecker.patch
 0007-Skip-TestRegistryAsCacheMutationAPIs.patch
 0008-Skip-flaky-TestGracefulShutdown-and-TestRegistrySupp.patch
-0009-Fix-panic-in-inmemory-driver.patch
diff -Nru -w docker-registry-2.8.1+ds1/.dockerignore docker-registry-2.8.2+ds1/.dockerignore
--- docker-registry-2.8.1+ds1/.dockerignore	1970-01-01 08:00:00.000000000 +0800
+++ docker-registry-2.8.2+ds1/.dockerignore	2023-05-11 18:11:57.000000000 +0800
@@ -0,0 +1 @@
+bin/
diff -Nru -w docker-registry-2.8.1+ds1/health/doc.go docker-registry-2.8.2+ds1/health/doc.go
--- docker-registry-2.8.1+ds1/health/doc.go	2022-03-09 01:52:36.000000000 +0800
+++ docker-registry-2.8.2+ds1/health/doc.go	2023-05-11 18:11:57.000000000 +0800
@@ -13,7 +13,7 @@
 // particularly useful for checks that verify upstream connectivity or
 // database status, since they might take a long time to return/timeout.
 //
-// Installing
+// # Installing
 //
 // To install health, just import it in your application:
 //
@@ -35,7 +35,7 @@
 // After importing these packages to your main application, you can start
 // registering checks.
 //
-// Registering Checks
+// # Registering Checks
 //
 // The recommended way of registering checks is using a periodic Check.
 // PeriodicChecks run on a certain schedule and asynchronously update the
@@ -84,7 +84,7 @@
 //   return Errors.new("This is an error!")
 //  }))
 //
-// Examples
+// # Examples
 //
 // You could also use the health checker mechanism to ensure your application
 // only comes up if certain conditions are met, or to allow the developer to
diff -Nru -w docker-registry-2.8.1+ds1/registry/api/v2/descriptors.go docker-registry-2.8.2+ds1/registry/api/v2/descriptors.go
--- docker-registry-2.8.1+ds1/registry/api/v2/descriptors.go	2022-03-09 01:52:36.000000000 +0800
+++ docker-registry-2.8.2+ds1/registry/api/v2/descriptors.go	2023-05-11 18:11:57.000000000 +0800
@@ -134,6 +134,19 @@
 		},
 	}
 
+	invalidPaginationResponseDescriptor = ResponseDescriptor{
+		Name:        "Invalid pagination number",
+		Description: "The received parameter n was invalid in some way, as described by the error code. The client should resolve the issue and retry the request.",
+		StatusCode:  http.StatusBadRequest,
+		Body: BodyDescriptor{
+			ContentType: "application/json",
+			Format:      errorsBody,
+		},
+		ErrorCodes: []errcode.ErrorCode{
+			ErrorCodePaginationNumberInvalid,
+		},
+	}
+
 	repositoryNotFoundResponseDescriptor = ResponseDescriptor{
 		Name:        "No Such Repository Error",
 		StatusCode:  http.StatusNotFound,
@@ -490,6 +503,7 @@
 							},
 						},
 						Failures: []ResponseDescriptor{
+							invalidPaginationResponseDescriptor,
 							unauthorizedResponseDescriptor,
 							repositoryNotFoundResponseDescriptor,
 							deniedResponseDescriptor,
@@ -1578,6 +1592,9 @@
 								},
 							},
 						},
+						Failures: []ResponseDescriptor{
+							invalidPaginationResponseDescriptor,
+						},
 					},
 				},
 			},
diff -Nru -w docker-registry-2.8.1+ds1/registry/api/v2/errors.go docker-registry-2.8.2+ds1/registry/api/v2/errors.go
--- docker-registry-2.8.1+ds1/registry/api/v2/errors.go	2022-03-09 01:52:36.000000000 +0800
+++ docker-registry-2.8.2+ds1/registry/api/v2/errors.go	2023-05-11 18:11:57.000000000 +0800
@@ -133,4 +133,13 @@
 		longer proceed.`,
 		HTTPStatusCode: http.StatusNotFound,
 	})
+
+	ErrorCodePaginationNumberInvalid = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:   "PAGINATION_NUMBER_INVALID",
+		Message: "invalid number of results requested",
+		Description: `Returned when the "n" parameter (number of results
+		to return) is not an integer, "n" is negative or "n" is bigger than
+		the maximum allowed.`,
+		HTTPStatusCode: http.StatusBadRequest,
+	})
 )
diff -Nru -w docker-registry-2.8.1+ds1/registry/auth/auth.go docker-registry-2.8.2+ds1/registry/auth/auth.go
--- docker-registry-2.8.1+ds1/registry/auth/auth.go	2022-03-09 01:52:36.000000000 +0800
+++ docker-registry-2.8.2+ds1/registry/auth/auth.go	2023-05-11 18:11:57.000000000 +0800
@@ -29,7 +29,6 @@
 //				}
 //			}
 // 		}
-//
 package auth
 
 import (
diff -Nru -w docker-registry-2.8.1+ds1/registry/auth/token/token.go docker-registry-2.8.2+ds1/registry/auth/token/token.go
--- docker-registry-2.8.1+ds1/registry/auth/token/token.go	2022-03-09 01:52:36.000000000 +0800
+++ docker-registry-2.8.2+ds1/registry/auth/token/token.go	2023-05-11 18:11:57.000000000 +0800
@@ -185,6 +185,7 @@
 
 // VerifySigningKey attempts to get the key which was used to sign this token.
 // The token header should contain either of these 3 fields:
+//
 //      `x5c` - The x509 certificate chain for the signing key. Needs to be
 //              verified.
 //      `jwk` - The JSON Web Key representation of the signing key.
@@ -192,6 +193,7 @@
 //      `kid` - The unique identifier for the key. This library interprets it
 //              as a libtrust fingerprint. The key itself can be looked up in
 //              the trustedKeys field of the given verify options.
+//
 // Each of these methods are tried in that order of preference until the
 // signing key is found or an error is returned.
 func (t *Token) VerifySigningKey(verifyOpts VerifyOptions) (signingKey libtrust.PublicKey, err error) {
diff -Nru -w docker-registry-2.8.1+ds1/registry/client/errors.go docker-registry-2.8.2+ds1/registry/client/errors.go
--- docker-registry-2.8.1+ds1/registry/client/errors.go	2022-03-09 01:52:36.000000000 +0800
+++ docker-registry-2.8.2+ds1/registry/client/errors.go	2023-05-11 18:11:57.000000000 +0800
@@ -55,6 +55,8 @@
 		switch statusCode {
 		case http.StatusUnauthorized:
 			return errcode.ErrorCodeUnauthorized.WithMessage(detailsErr.Details)
+		case http.StatusForbidden:
+			return errcode.ErrorCodeDenied.WithMessage(detailsErr.Details)
 		case http.StatusTooManyRequests:
 			return errcode.ErrorCodeTooManyRequests.WithMessage(detailsErr.Details)
 		default:
diff -Nru -w docker-registry-2.8.1+ds1/registry/client/repository.go docker-registry-2.8.2+ds1/registry/client/repository.go
--- docker-registry-2.8.1+ds1/registry/client/repository.go	2022-03-09 01:52:36.000000000 +0800
+++ docker-registry-2.8.2+ds1/registry/client/repository.go	2023-05-11 18:11:57.000000000 +0800
@@ -114,9 +114,7 @@
 			return 0, err
 		}
 
-		for cnt := range ctlg.Repositories {
-			entries[cnt] = ctlg.Repositories[cnt]
-		}
+		copy(entries, ctlg.Repositories)
 		numFilled = len(ctlg.Repositories)
 
 		link := resp.Header.Get("Link")
diff -Nru -w docker-registry-2.8.1+ds1/registry/client/transport/http_reader.go docker-registry-2.8.2+ds1/registry/client/transport/http_reader.go
--- docker-registry-2.8.1+ds1/registry/client/transport/http_reader.go	2022-03-09 01:52:36.000000000 +0800
+++ docker-registry-2.8.2+ds1/registry/client/transport/http_reader.go	2023-05-11 18:11:57.000000000 +0800
@@ -180,7 +180,6 @@
 		// context.GetLogger(hrs.context).Infof("Range: %s", req.Header.Get("Range"))
 	}
 
-	req.Header.Add("Accept-Encoding", "identity")
 	resp, err := hrs.client.Do(req)
 	if err != nil {
 		return nil, err
diff -Nru -w docker-registry-2.8.1+ds1/registry/handlers/basicauth.go docker-registry-2.8.2+ds1/registry/handlers/basicauth.go
--- docker-registry-2.8.1+ds1/registry/handlers/basicauth.go	2022-03-09 01:52:36.000000000 +0800
+++ docker-registry-2.8.2+ds1/registry/handlers/basicauth.go	2023-05-11 18:11:57.000000000 +0800
@@ -1,3 +1,4 @@
+//go:build go1.4
 // +build go1.4
 
 package handlers
diff -Nru -w docker-registry-2.8.1+ds1/registry/handlers/basicauth_prego14.go docker-registry-2.8.2+ds1/registry/handlers/basicauth_prego14.go
--- docker-registry-2.8.1+ds1/registry/handlers/basicauth_prego14.go	2022-03-09 01:52:36.000000000 +0800
+++ docker-registry-2.8.2+ds1/registry/handlers/basicauth_prego14.go	2023-05-11 18:11:57.000000000 +0800
@@ -1,3 +1,4 @@
+//go:build !go1.4
 // +build !go1.4
 
 package handlers
diff -Nru -w docker-registry-2.8.1+ds1/registry/handlers/catalog.go docker-registry-2.8.2+ds1/registry/handlers/catalog.go
--- docker-registry-2.8.1+ds1/registry/handlers/catalog.go	2022-03-09 01:52:36.000000000 +0800
+++ docker-registry-2.8.2+ds1/registry/handlers/catalog.go	2023-05-11 18:11:57.000000000 +0800
@@ -9,11 +9,13 @@
 	"strconv"
 
 	"github.com/docker/distribution/registry/api/errcode"
+	v2 "github.com/docker/distribution/registry/api/v2"
 	"github.com/docker/distribution/registry/storage/driver"
+
 	"github.com/gorilla/handlers"
 )
 
-const maximumReturnedEntries = 100
+const defaultReturnedEntries = 100
 
 func catalogDispatcher(ctx *Context, r *http.Request) http.Handler {
 	catalogHandler := &catalogHandler{
@@ -38,29 +40,55 @@
 
 	q := r.URL.Query()
 	lastEntry := q.Get("last")
-	maxEntries, err := strconv.Atoi(q.Get("n"))
-	if err != nil || maxEntries < 0 {
-		maxEntries = maximumReturnedEntries
+
+	entries := defaultReturnedEntries
+	maximumConfiguredEntries := ch.App.Config.Catalog.MaxEntries
+
+	// parse n, if n unparseable, or negative assign it to defaultReturnedEntries
+	if n := q.Get("n"); n != "" {
+		parsedMax, err := strconv.Atoi(n)
+		if err == nil {
+			if parsedMax > maximumConfiguredEntries {
+				ch.Errors = append(ch.Errors, v2.ErrorCodePaginationNumberInvalid.WithDetail(map[string]int{"n": parsedMax}))
+				return
+			} else if parsedMax >= 0 {
+				entries = parsedMax
+			}
+		}
 	}
 
-	repos := make([]string, maxEntries)
+	// then enforce entries to be between 0 & maximumConfiguredEntries
+	// max(0, min(entries, maximumConfiguredEntries))
+	if entries < 0 || entries > maximumConfiguredEntries {
+		entries = maximumConfiguredEntries
+	}
 
-	filled, err := ch.App.registry.Repositories(ch.Context, repos, lastEntry)
-	_, pathNotFound := err.(driver.PathNotFoundError)
+	repos := make([]string, entries)
+	filled := 0
 
-	if err == io.EOF || pathNotFound {
+	// entries is guaranteed to be >= 0 and < maximumConfiguredEntries
+	if entries == 0 {
 		moreEntries = false
-	} else if err != nil {
+	} else {
+		returnedRepositories, err := ch.App.registry.Repositories(ch.Context, repos, lastEntry)
+		if err != nil {
+			_, pathNotFound := err.(driver.PathNotFoundError)
+			if err != io.EOF && !pathNotFound {
 		ch.Errors = append(ch.Errors, errcode.ErrorCodeUnknown.WithDetail(err))
 		return
 	}
+			// err is either io.EOF or not PathNotFoundError
+			moreEntries = false
+		}
+		filled = returnedRepositories
+	}
 
 	w.Header().Set("Content-Type", "application/json; charset=utf-8")
 
 	// Add a link header if there are more entries to retrieve
 	if moreEntries {
-		lastEntry = repos[len(repos)-1]
-		urlStr, err := createLinkEntry(r.URL.String(), maxEntries, lastEntry)
+		lastEntry = repos[filled-1]
+		urlStr, err := createLinkEntry(r.URL.String(), entries, lastEntry)
 		if err != nil {
 			ch.Errors = append(ch.Errors, errcode.ErrorCodeUnknown.WithDetail(err))
 			return
diff -Nru -w docker-registry-2.8.1+ds1/registry/storage/blobwriter_nonresumable.go docker-registry-2.8.2+ds1/registry/storage/blobwriter_nonresumable.go
--- docker-registry-2.8.1+ds1/registry/storage/blobwriter_nonresumable.go	2022-03-09 01:52:36.000000000 +0800
+++ docker-registry-2.8.2+ds1/registry/storage/blobwriter_nonresumable.go	2023-05-11 18:11:57.000000000 +0800
@@ -1,3 +1,4 @@
+//go:build noresumabledigest
 // +build noresumabledigest
 
 package storage
diff -Nru -w docker-registry-2.8.1+ds1/registry/storage/blobwriter_resumable.go docker-registry-2.8.2+ds1/registry/storage/blobwriter_resumable.go
--- docker-registry-2.8.1+ds1/registry/storage/blobwriter_resumable.go	2022-03-09 01:52:36.000000000 +0800
+++ docker-registry-2.8.2+ds1/registry/storage/blobwriter_resumable.go	2023-05-11 18:11:57.000000000 +0800
@@ -1,3 +1,4 @@
+//go:build !noresumabledigest
 // +build !noresumabledigest
 
 package storage
diff -Nru -w docker-registry-2.8.1+ds1/registry/storage/driver/gcs/gcs.go docker-registry-2.8.2+ds1/registry/storage/driver/gcs/gcs.go
--- docker-registry-2.8.1+ds1/registry/storage/driver/gcs/gcs.go	2022-03-09 01:52:36.000000000 +0800
+++ docker-registry-2.8.2+ds1/registry/storage/driver/gcs/gcs.go	2023-05-11 18:11:57.000000000 +0800
@@ -10,6 +10,7 @@
 // Note that the contents of incomplete uploads are not accessible even though
 // Stat returns their length
 //
+//go:build include_gcs
 // +build include_gcs
 
 package gcs
diff -Nru -w docker-registry-2.8.1+ds1/registry/storage/driver/inmemory/mfs.go docker-registry-2.8.2+ds1/registry/storage/driver/inmemory/mfs.go
--- docker-registry-2.8.1+ds1/registry/storage/driver/inmemory/mfs.go	2022-03-09 01:52:36.000000000 +0800
+++ docker-registry-2.8.2+ds1/registry/storage/driver/inmemory/mfs.go	2023-05-11 18:11:57.000000000 +0800
@@ -279,6 +279,9 @@
 }
 
 func (f *file) ReadAt(p []byte, offset int64) (n int, err error) {
+	if offset >= int64(len(f.data)) {
+		return 0, io.EOF
+	}
 	return copy(p, f.data[offset:]), nil
 }
 
diff -Nru -w docker-registry-2.8.1+ds1/registry/storage/driver/middleware/cloudfront/middleware.go docker-registry-2.8.2+ds1/registry/storage/driver/middleware/cloudfront/middleware.go
--- docker-registry-2.8.1+ds1/registry/storage/driver/middleware/cloudfront/middleware.go	2022-03-09 01:52:36.000000000 +0800
+++ docker-registry-2.8.2+ds1/registry/storage/driver/middleware/cloudfront/middleware.go	2023-05-11 18:11:57.000000000 +0800
@@ -1,6 +1,5 @@
 // Package middleware - cloudfront wrapper for storage libs
 // N.B. currently only works with S3, not arbitrary sites
-//
 package middleware
 
 import (
@@ -38,7 +37,9 @@
 
 // Optional options: ipFilteredBy, awsregion
 // ipfilteredby: valid value "none|aws|awsregion". "none", do not filter any IP, default value. "aws", only aws IP goes
+//
 //               to S3 directly. "awsregion", only regions listed in awsregion options goes to S3 directly
+//
 // awsregion: a comma separated string of AWS regions.
 func newCloudFrontStorageMiddleware(storageDriver storagedriver.StorageDriver, options map[string]interface{}) (storagedriver.StorageDriver, error) {
 	// parse baseurl
diff -Nru -w docker-registry-2.8.1+ds1/registry/storage/driver/oss/oss.go docker-registry-2.8.2+ds1/registry/storage/driver/oss/oss.go
--- docker-registry-2.8.1+ds1/registry/storage/driver/oss/oss.go	2022-03-09 01:52:36.000000000 +0800
+++ docker-registry-2.8.2+ds1/registry/storage/driver/oss/oss.go	2023-05-11 18:11:57.000000000 +0800
@@ -7,6 +7,7 @@
 // Because OSS is a key, value store the Stat call does not support last modification
 // time for directories (directories are an abstraction for key, value stores)
 //
+//go:build include_oss
 // +build include_oss
 
 package oss
diff -Nru -w docker-registry-2.8.1+ds1/registry/storage/driver/s3-aws/s3.go docker-registry-2.8.2+ds1/registry/storage/driver/s3-aws/s3.go
--- docker-registry-2.8.1+ds1/registry/storage/driver/s3-aws/s3.go	2022-03-09 01:52:36.000000000 +0800
+++ docker-registry-2.8.2+ds1/registry/storage/driver/s3-aws/s3.go	2023-05-11 18:11:57.000000000 +0800
@@ -549,9 +549,9 @@
 
 // Writer returns a FileWriter which will store the content written to it
 // at the location designated by "path" after the call to Commit.
-func (d *driver) Writer(ctx context.Context, path string, append bool) (storagedriver.FileWriter, error) {
+func (d *driver) Writer(ctx context.Context, path string, appendParam bool) (storagedriver.FileWriter, error) {
 	key := d.s3Path(path)
-	if !append {
+	if !appendParam {
 		// TODO (brianbland): cancel other uploads at this path
 		resp, err := d.S3.CreateMultipartUpload(&s3.CreateMultipartUploadInput{
 			Bucket:               aws.String(d.Bucket),
@@ -574,7 +574,7 @@
 	if err != nil {
 		return nil, parseError(path, err)
 	}
-
+	var allParts []*s3.Part
 	for _, multi := range resp.Uploads {
 		if key != *multi.Key {
 			continue
@@ -587,11 +587,20 @@
 		if err != nil {
 			return nil, parseError(path, err)
 		}
-		var multiSize int64
-		for _, part := range resp.Parts {
-			multiSize += *part.Size
+		allParts = append(allParts, resp.Parts...)
+		for *resp.IsTruncated {
+			resp, err = d.S3.ListParts(&s3.ListPartsInput{
+				Bucket:           aws.String(d.Bucket),
+				Key:              aws.String(key),
+				UploadId:         multi.UploadId,
+				PartNumberMarker: resp.NextPartNumberMarker,
+			})
+			if err != nil {
+				return nil, parseError(path, err)
+			}
+			allParts = append(allParts, resp.Parts...)
 		}
-		return d.newWriter(key, *multi.UploadId, resp.Parts), nil
+		return d.newWriter(key, *multi.UploadId, allParts), nil
 	}
 	return nil, storagedriver.PathNotFoundError{Path: path}
 }
diff -Nru -w docker-registry-2.8.1+ds1/registry/storage/paths.go docker-registry-2.8.2+ds1/registry/storage/paths.go
--- docker-registry-2.8.1+ds1/registry/storage/paths.go	2022-03-09 01:52:36.000000000 +0800
+++ docker-registry-2.8.2+ds1/registry/storage/paths.go	2023-05-11 18:11:57.000000000 +0800
@@ -435,7 +435,6 @@
 // groups of digest folder. It will be as follows:
 //
 // 	<algorithm>/<first two bytes of digest>/<full digest>
-//
 func digestPathComponents(dgst digest.Digest, multilevel bool) ([]string, error) {
 	if err := dgst.Validate(); err != nil {
 		return nil, err
diff -Nru -w docker-registry-2.8.1+ds1/version/print.go docker-registry-2.8.2+ds1/version/print.go
--- docker-registry-2.8.1+ds1/version/print.go	2022-03-09 01:52:36.000000000 +0800
+++ docker-registry-2.8.2+ds1/version/print.go	2023-05-11 18:11:57.000000000 +0800
@@ -15,7 +15,6 @@
 // with version "v2.0" would print the following:
 //
 // 	registry github.com/docker/distribution v2.0
-//
 func FprintVersion(w io.Writer) {
 	fmt.Fprintln(w, os.Args[0], Package, Version)
 }
diff -Nru -w docker-registry-2.8.1+ds1/version/version.go docker-registry-2.8.2+ds1/version/version.go
--- docker-registry-2.8.1+ds1/version/version.go	2022-03-09 01:52:36.000000000 +0800
+++ docker-registry-2.8.2+ds1/version/version.go	2023-05-11 18:11:57.000000000 +0800
@@ -8,7 +8,7 @@
 // the latest release tag by hand, always suffixed by "+unknown". During
 // build, it will be replaced by the actual version. The value here will be
 // used if the registry is run after a go get based install.
-var Version = "v2.8.1+unknown"
+var Version = "v2.8.2+unknown"
 
 // Revision is filled with the VCS (e.g. git) revision being used to build
 // the program at linking time.
diff -Nru -w docker-registry-2.8.1+ds1/version/version.sh docker-registry-2.8.2+ds1/version/version.sh
--- docker-registry-2.8.1+ds1/version/version.sh	2022-03-09 01:52:36.000000000 +0800
+++ docker-registry-2.8.2+ds1/version/version.sh	2023-05-11 18:11:57.000000000 +0800
@@ -17,7 +17,7 @@
 // Version indicates which version of the binary is running. This is set to
 // the latest release tag by hand, always suffixed by "+unknown". During
 // build, it will be replaced by the actual version. The value here will be
-// used if the registry is run after a go get based install.
+// used if the registry is run after a go install based install.
 var Version = "$(git describe --match 'v[0-9]*' --dirty='.m' --always)+unknown"
 
 // Revision is filled with the VCS (e.g. git) revision being used to build

--- End Message ---
--- Begin Message ---
Unblocked.

--- End Message ---

Reply to: