diff --git a/1013-Don-t-enforce-new-validation-rules-for-existing-netw.patch b/1013-Don-t-enforce-new-validation-rules-for-existing-netw.patch new file mode 100644 index 0000000000000000000000000000000000000000..83b41fae26ce02e86d50487e7b57d97fcc4dd8e7 --- /dev/null +++ b/1013-Don-t-enforce-new-validation-rules-for-existing-netw.patch @@ -0,0 +1,63 @@ +From 1ae019fca2a6c7874afe2b54b7261dbf9a7d8efc Mon Sep 17 00:00:00 2001 +From: Rob Murray +Date: Thu, 8 Feb 2024 17:40:54 +0000 +Subject: [PATCH 004/172] Don't enforce new validation rules for existing + networks + +Non-swarm networks created before network-creation-time validation +was added in 25.0.0 continued working, because the checks are not +re-run. + +But, swarm creates networks when needed (with 'agent=true'), to +ensure they exist on each agent - ignoring the NetworkNameError +that says the network already existed. + +By ignoring validation errors on creation of a network with +agent=true, pre-existing swarm networks with IPAM config that would +fail the new checks will continue to work too. + +New swarm (overlay) networks are still validated, because they are +initially created with 'agent=false'. + +Signed-off-by: Rob Murray +(cherry picked from commit 571af915d59d2fa68eb10cf0ec3cf9cd85b1eef2) +Signed-off-by: Albin Kerouanton +--- + daemon/network.go | 22 +++++++++++++++++++++- + 1 file changed, 21 insertions(+), 1 deletion(-) + +diff --git a/daemon/network.go b/daemon/network.go +index d2d9dd27fc..9fcf6b1fd6 100644 +--- a/daemon/network.go ++++ b/daemon/network.go +@@ -332,7 +332,27 @@ func (daemon *Daemon) createNetwork(cfg *config.Config, create types.NetworkCrea + } + + if err := network.ValidateIPAM(create.IPAM, create.EnableIPv6); err != nil { +- return nil, errdefs.InvalidParameter(err) ++ if agent { ++ // This function is called with agent=false for all networks. For swarm-scoped ++ // networks, the configuration is validated but ManagerRedirectError is returned ++ // and the network is not created. Then, each time a swarm-scoped network is ++ // needed, this function is called again with agent=true. ++ // ++ // Non-swarm networks created before ValidateIPAM was introduced continue to work ++ // as they did before-upgrade, even if they would fail the new checks on creation ++ // (for example, by having host-bits set in their subnet). Those networks are not ++ // seen again here. ++ // ++ // By dropping errors for agent networks, existing swarm-scoped networks also ++ // continue to behave as they did before upgrade - but new networks are still ++ // validated. ++ log.G(context.TODO()).WithFields(log.Fields{ ++ "error": err, ++ "network": create.Name, ++ }).Warn("Continuing with validation errors in agent IPAM") ++ } else { ++ return nil, errdefs.InvalidParameter(err) ++ } + } + + if create.IPAM != nil { +-- +2.27.0 \ No newline at end of file diff --git a/1014-daemon-overlay2-remove-world-writable-permission-fro.patch b/1014-daemon-overlay2-remove-world-writable-permission-fro.patch new file mode 100644 index 0000000000000000000000000000000000000000..9f85361d191e30d2bfbc7e9e2592b3a16b1658b2 --- /dev/null +++ b/1014-daemon-overlay2-remove-world-writable-permission-fro.patch @@ -0,0 +1,42 @@ +From d0d85f6438af71ddd15d0441ec219daba192d4e5 Mon Sep 17 00:00:00 2001 +From: Jaroslav Jindrak +Date: Tue, 5 Mar 2024 14:25:50 +0100 +Subject: [PATCH 022/172] daemon: overlay2: remove world writable permission + from the lower file +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +In de2447c, the creation of the 'lower' file was changed from using +os.Create to using ioutils.AtomicWriteFile, which ignores the system's +umask. This means that even though the requested permission in the +source code was always 0666, it was 0644 on systems with default +umask of 0022 prior to de2447c, so the move to AtomicFile potentially +increased the file's permissions. + +This is not a security issue because the parent directory does not +allow writes into the file, but it can confuse security scanners on +Linux-based systems into giving false positives. + +Signed-off-by: Jaroslav Jindrak +(cherry picked from commit cadb124ab679f7e48c917473e28ff7f270d27dd9) +Signed-off-by: Paweł Gronowski +--- + daemon/graphdriver/overlay2/overlay.go | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/daemon/graphdriver/overlay2/overlay.go b/daemon/graphdriver/overlay2/overlay.go +index 4f61ac8c08..4cf157e90f 100644 +--- a/daemon/graphdriver/overlay2/overlay.go ++++ b/daemon/graphdriver/overlay2/overlay.go +@@ -406,7 +406,7 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts) (retErr + return err + } + if lower != "" { +- if err := ioutils.AtomicWriteFile(path.Join(dir, lowerFile), []byte(lower), 0o666); err != nil { ++ if err := ioutils.AtomicWriteFile(path.Join(dir, lowerFile), []byte(lower), 0o644); err != nil { + return err + } + } +-- +2.27.0 diff --git a/1015-rootless-fix-open-etc-docker-plugins-permission-deni.patch b/1015-rootless-fix-open-etc-docker-plugins-permission-deni.patch new file mode 100644 index 0000000000000000000000000000000000000000..c0b1c90b43a55ee60aca7d5ad2a97e6651b91398 --- /dev/null +++ b/1015-rootless-fix-open-etc-docker-plugins-permission-deni.patch @@ -0,0 +1,52 @@ +From 81ad7062f0299c4ebc9ac3f576a2c0c67d8b6ff8 Mon Sep 17 00:00:00 2001 +From: Akihiro Suda +Date: Thu, 14 Mar 2024 14:32:01 +0900 +Subject: [PATCH 026/172] rootless: fix `open /etc/docker/plugins: permission + denied` +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fix issue 47436 + +Signed-off-by: Akihiro Suda +(cherry picked from commit d742659877d9bf0bfe64b97e529bc28667974607) +Signed-off-by: Paweł Gronowski +--- + pkg/plugins/discovery.go | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/pkg/plugins/discovery.go b/pkg/plugins/discovery.go +index 37316ed482..503ac574a9 100644 +--- a/pkg/plugins/discovery.go ++++ b/pkg/plugins/discovery.go +@@ -10,6 +10,8 @@ import ( + "strings" + "sync" + ++ "github.com/containerd/containerd/pkg/userns" ++ "github.com/containerd/log" + "github.com/pkg/errors" + ) + +@@ -56,10 +58,16 @@ func (l *LocalRegistry) Scan() ([]string, error) { + + for _, p := range l.specsPaths { + dirEntries, err = os.ReadDir(p) +- if err != nil && !os.IsNotExist(err) { ++ if err != nil { ++ if os.IsNotExist(err) { ++ continue ++ } ++ if os.IsPermission(err) && userns.RunningInUserNS() { ++ log.L.Debug(err.Error()) ++ continue ++ } + return nil, errors.Wrap(err, "error reading dir entries") + } +- + for _, entry := range dirEntries { + if entry.IsDir() { + infos, err := os.ReadDir(filepath.Join(p, entry.Name())) +-- +2.27.0 diff --git a/1016-Fix-cases-where-we-are-wrapping-a-nil-error.patch b/1016-Fix-cases-where-we-are-wrapping-a-nil-error.patch new file mode 100644 index 0000000000000000000000000000000000000000..ec7fe177a259e1aff2fa8d4c835707d52db544ce --- /dev/null +++ b/1016-Fix-cases-where-we-are-wrapping-a-nil-error.patch @@ -0,0 +1,36 @@ +From e2e670299f83699094c28add5a4366749d9bd34c Mon Sep 17 00:00:00 2001 +From: Brian Goff +Date: Mon, 1 Apr 2024 21:30:43 +0000 +Subject: Fix cases where we are wrapping a nil error +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This was using `errors.Wrap` when there was no error to wrap, meanwhile +we are supposed to be creating a new error. + +Found this while investigating some log corruption issues and +unexpectedly getting a nil reader and a nil error from `getTailReader`. + +Signed-off-by: Brian Goff +(cherry picked from commit 0a48d26fbcb33a84da7f767c2a62cae362df9505) +Signed-off-by: Paweł Gronowski +--- + daemon/logger/local/read.go | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/daemon/logger/local/read.go b/daemon/logger/local/read.go +index 6a0b166103..cb5f9f0cd3 100644 +--- a/daemon/logger/local/read.go ++++ b/daemon/logger/local/read.go +@@ -66,7 +66,7 @@ func getTailReader(ctx context.Context, r loggerutils.SizeReaderAt, req int) (io + } + + if msgLen != binary.BigEndian.Uint32(buf) { +- return nil, 0, errdefs.DataLoss(errors.Wrap(err, "log message header and footer indicate different message sizes")) ++ return nil, 0, errdefs.DataLoss(errors.New("log message header and footer indicate different message sizes")) + } + + found++ +-- +2.27.0 \ No newline at end of file diff --git a/1017-libnetwork-fix-non-constant-format-string-in-call-go.patch b/1017-libnetwork-fix-non-constant-format-string-in-call-go.patch new file mode 100644 index 0000000000000000000000000000000000000000..e467b036d9e099113f7554057072b853ba3d2fde --- /dev/null +++ b/1017-libnetwork-fix-non-constant-format-string-in-call-go.patch @@ -0,0 +1,61 @@ +From 81053917083b7776ec39172823f7a4f954363ec1 Mon Sep 17 00:00:00 2001 +From: Sebastiaan van Stijn +Date: Wed, 21 Aug 2024 15:38:52 +0200 +Subject: [PATCH 107/172] libnetwork: fix non-constant format string in call + (govet) + + libnetwork/controller.go:1054:32: printf: non-constant format string in call to github.com/docker/docker/libnetwork/types.NotFoundErrorf (govet) + return types.NotFoundErrorf(err.Error()) + ^ + libnetwork/controller.go:1073:32: printf: non-constant format string in call to github.com/docker/docker/libnetwork/types.NotFoundErrorf (govet) + return types.NotFoundErrorf(err.Error()) + ^ + libnetwork/sandbox_externalkey_unix.go:113:21: printf: non-constant format string in call to fmt.Errorf (govet) + return fmt.Errorf(string(buf[0:n])) + ^ + +Signed-off-by: Sebastiaan van Stijn +(cherry picked from commit 6008c42ca2903467964c430c0030a29ae4cc858e) +Signed-off-by: Austin Vazquez +--- + libnetwork/controller.go | 4 ++-- + libnetwork/sandbox_externalkey_unix.go | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/libnetwork/controller.go b/libnetwork/controller.go +index bcbbdd06ca..8341946756 100644 +--- a/libnetwork/controller.go ++++ b/libnetwork/controller.go +@@ -1045,7 +1045,7 @@ func (c *Controller) loadDriver(networkType string) error { + + if err != nil { + if errors.Cause(err) == plugins.ErrNotFound { +- return types.NotFoundErrorf(err.Error()) ++ return types.NotFoundErrorf("%v", err) + } + return err + } +@@ -1064,7 +1064,7 @@ func (c *Controller) loadIPAMDriver(name string) error { + + if err != nil { + if errors.Cause(err) == plugins.ErrNotFound { +- return types.NotFoundErrorf(err.Error()) ++ return types.NotFoundErrorf("%v", err) + } + return err + } +diff --git a/libnetwork/sandbox_externalkey_unix.go b/libnetwork/sandbox_externalkey_unix.go +index 7534421141..32b1027bb4 100644 +--- a/libnetwork/sandbox_externalkey_unix.go ++++ b/libnetwork/sandbox_externalkey_unix.go +@@ -94,7 +94,7 @@ func processReturn(r io.Reader) error { + return fmt.Errorf("failed to read buf in processReturn : %v", err) + } + if string(buf[0:n]) != success { +- return fmt.Errorf(string(buf[0:n])) ++ return fmt.Errorf("%s", buf[0:n]) + } + return nil + } +-- +2.27.0 diff --git a/1018-Fix-setup-user-chains-even-if-there-are-running-cont.patch b/1018-Fix-setup-user-chains-even-if-there-are-running-cont.patch new file mode 100644 index 0000000000000000000000000000000000000000..2ad7b8da1584604a6c05544f7c41d0297d33241b --- /dev/null +++ b/1018-Fix-setup-user-chains-even-if-there-are-running-cont.patch @@ -0,0 +1,122 @@ +From 60eece38cd2c5f41f948cd463a6ee0f0ad2f9d99 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Andr=C3=A9s=20Maldonado?= +Date: Fri, 4 Oct 2024 01:53:46 +0200 +Subject: Fix: setup user chains even if there are running containers + +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Currently, the DOCKER-USER chains are set up on firewall reload or network +creation. If there are running containers at startup, configureNetworking won't +be called (daemon/daemon_unix.go), so the user chains won't be setup. + +This commit puts the setup logic on a separate function, and calls it on the +original place and on initNetworkController. + +Signed-off-by: Andrés Maldonado +(cherry picked from commit a8bfa83667fb7c31e7274dc83a2aa9c98ace2af2) +Signed-off-by: Justin Alvarez +--- + daemon/daemon_unix.go | 4 ++++ + integration/daemon/daemon_test.go | 29 +++++++++++++++++++++++++++++ + libnetwork/controller.go | 17 ++++++++++++----- + 3 files changed, 45 insertions(+), 5 deletions(-) + +diff --git a/daemon/daemon_unix.go b/daemon/daemon_unix.go +index 1143dda063..f6704df752 100644 +--- a/daemon/daemon_unix.go ++++ b/daemon/daemon_unix.go +@@ -852,6 +852,10 @@ func (daemon *Daemon) initNetworkController(cfg *config.Config, activeSandboxes + return err + } + ++ if err := daemon.netController.SetupUserChains(); err != nil { ++ log.G(context.TODO()).WithError(err).Warnf("initNetworkController") ++ } ++ + // Set HostGatewayIP to the default bridge's IP if it is empty + setHostGatewayIP(daemon.netController, cfg) + return nil +diff --git a/integration/daemon/daemon_test.go b/integration/daemon/daemon_test.go +index a6436ae7da..045f9bed4f 100644 +--- a/integration/daemon/daemon_test.go ++++ b/integration/daemon/daemon_test.go +@@ -388,6 +388,7 @@ func TestLiveRestore(t *testing.T) { + + t.Run("volume references", testLiveRestoreVolumeReferences) + t.Run("autoremove", testLiveRestoreAutoRemove) ++ t.Run("user chains", testLiveRestoreUserChainsSetup) + } + + func testLiveRestoreAutoRemove(t *testing.T) { +@@ -606,6 +607,34 @@ func testLiveRestoreVolumeReferences(t *testing.T) { + }) + } + ++func testLiveRestoreUserChainsSetup(t *testing.T) { ++ skip.If(t, testEnv.IsRootless(), "rootless daemon uses it's own network namespace") ++ ++ t.Parallel() ++ ctx := testutil.StartSpan(baseContext, t) ++ ++ t.Run("user chains should be inserted", func(t *testing.T) { ++ d := daemon.New(t) ++ d.StartWithBusybox(ctx, t, "--live-restore") ++ t.Cleanup(func() { ++ d.Stop(t) ++ d.Cleanup(t) ++ }) ++ ++ c := d.NewClientT(t) ++ ++ cID := container.Run(ctx, t, c, container.WithCmd("top")) ++ defer c.ContainerRemove(ctx, cID, containertypes.RemoveOptions{Force: true}) ++ ++ d.Stop(t) ++ icmd.RunCommand("iptables", "--flush", "FORWARD").Assert(t, icmd.Success) ++ d.Start(t, "--live-restore") ++ ++ result := icmd.RunCommand("iptables", "-S", "FORWARD", "1") ++ assert.Check(t, is.Equal(strings.TrimSpace(result.Stdout()), "-A FORWARD -j DOCKER-USER"), "the jump to DOCKER-USER should be the first rule in the FORWARD chain") ++ }) ++} ++ + func TestDaemonDefaultBridgeWithFixedCidrButNoBip(t *testing.T) { + skip.If(t, runtime.GOOS == "windows") + +diff --git a/libnetwork/controller.go b/libnetwork/controller.go +index 8341946756..9c066d238e 100644 +--- a/libnetwork/controller.go ++++ b/libnetwork/controller.go +@@ -707,15 +707,22 @@ addToStore: + c.mu.Unlock() + } + +- // Sets up the DOCKER-USER chain for each iptables version (IPv4, IPv6) +- // that's enabled in the controller's configuration. ++ if err := c.SetupUserChains(); err != nil { ++ log.G(context.TODO()).WithError(err).Warnf("Controller.NewNetwork %s:", name) ++ } ++ ++ return nw, nil ++} ++ ++// Sets up the DOCKER-USER chain for each iptables version (IPv4, IPv6) that's ++// enabled in the controller's configuration. ++func (c *Controller) SetupUserChains() error { + for _, ipVersion := range c.enabledIptablesVersions() { + if err := setupUserChain(ipVersion); err != nil { +- log.G(context.TODO()).WithError(err).Warnf("Controller.NewNetwork %s:", name) ++ return err + } + } +- +- return nw, nil ++ return nil + } + + var joinCluster NetworkWalker = func(nw *Network) bool { +-- +2.27.0 + diff --git a/1019-Dockerd-rootless-make-etc-var-run-cdi-available.patch b/1019-Dockerd-rootless-make-etc-var-run-cdi-available.patch new file mode 100644 index 0000000000000000000000000000000000000000..4e6bd56df9f9d2b6bb18b05709ca3f4311695b52 --- /dev/null +++ b/1019-Dockerd-rootless-make-etc-var-run-cdi-available.patch @@ -0,0 +1,99 @@ +From ddc8a15eb54f0f8911e463ce2694521dc4531b0f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafael=20Fern=C3=A1ndez=20L=C3=B3pez?= + +Date: Mon, 23 Sep 2024 10:39:30 +0200 +Subject: Dockerd rootless: make {/etc,/var/run}/cdi available +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When dockerd is executed with the `dockerd-rootless.sh` script, make +/etc/cdi and /var/run/cdi available to the daemon if they exist. + +This makes it possible to enable the CDI integration in rootless mode. + +Fixes: #47676 + +Signed-off-by: Rafael Fernández López +(cherry picked from commit 4e30acb63ffa085e54576361814f417db8c84645) +Signed-off-by: Sebastiaan van Stijn +--- + contrib/dockerd-rootless.sh | 48 +++++++++++++++++++++++++++++++++---- + 1 file changed, 44 insertions(+), 4 deletions(-) + +diff --git a/contrib/dockerd-rootless.sh b/contrib/dockerd-rootless.sh +index 0baa112e2c..6c0775ec65 100755 +--- a/contrib/dockerd-rootless.sh ++++ b/contrib/dockerd-rootless.sh +@@ -53,6 +53,30 @@ if ! [ -d "$HOME" ]; then + exit 1 + fi + ++mount_directory() { ++ if [ -z "$_DOCKERD_ROOTLESS_CHILD" ]; then ++ echo "mount_directory should be called from the child context. Otherwise data loss is at risk" >&2 ++ exit 1 ++ fi ++ ++ DIRECTORY="$1" ++ if [ ! -d "$DIRECTORY" ]; then ++ return ++ fi ++ ++ # Bind mount directory: this makes this directory visible to ++ # Dockerd, even if it is originally a symlink, given Dockerd does ++ # not always follow symlinks. Some directories might also be ++ # "copied-up", meaning that they will also be writable on the child ++ # namespace; this will be the case only if they are provided as ++ # --copy-up to the rootlesskit. ++ DIRECTORY_REALPATH=$(realpath "$DIRECTORY") ++ MOUNT_OPTIONS="${2:---bind}" ++ rm -rf "$DIRECTORY" ++ mkdir -p "$DIRECTORY" ++ mount $MOUNT_OPTIONS "$DIRECTORY_REALPATH" "$DIRECTORY" ++} ++ + rootlesskit="" + for f in docker-rootlesskit rootlesskit; do + if command -v $f > /dev/null 2>&1; then +@@ -132,6 +156,25 @@ if [ -z "$_DOCKERD_ROOTLESS_CHILD" ]; then + "$0" "$@" + else + [ "$_DOCKERD_ROOTLESS_CHILD" = 1 ] ++ ++ # The Container Device Interface (CDI) specs can be found by default ++ # under {/etc,/var/run}/cdi. More information at: ++ # https://github.com/cncf-tags/container-device-interface ++ # ++ # In order to use the Container Device Interface (CDI) integration, ++ # the CDI paths need to exist before the Docker daemon is started in ++ # order for it to read the CDI specification files. Otherwise, a ++ # Docker daemon restart will be required for the daemon to discover ++ # them. ++ # ++ # If another set of CDI paths (other than the default /etc/cdi and ++ # /var/run/cdi) are configured through the Docker configuration file ++ # (using "cdi-spec-dirs"), they need to be bind mounted in rootless ++ # mode; otherwise the Docker daemon won't have access to the CDI ++ # specification files. ++ mount_directory /etc/cdi ++ mount_directory /var/run/cdi ++ + # remove the symlinks for the existing files in the parent namespace if any, + # so that we can create our own files in our mount namespace. + rm -f /run/docker /run/containerd /run/xtables.lock +@@ -146,10 +189,7 @@ else + if [ "$(stat -c %T -f /etc)" = "tmpfs" ] && [ -L "/etc/ssl" ]; then + # Workaround for "x509: certificate signed by unknown authority" on openSUSE Tumbleweed. + # https://github.com/rootless-containers/rootlesskit/issues/225 +- realpath_etc_ssl=$(realpath /etc/ssl) +- rm -f /etc/ssl +- mkdir /etc/ssl +- mount --rbind ${realpath_etc_ssl} /etc/ssl ++ mount_directory /etc/ssl "--rbind" + fi + + exec "$dockerd" "$@" +-- +2.27.0 + diff --git a/moby.spec b/moby.spec index 4ae3f7f5ead21e4149988baa687fec0e37c7c9b9..b2926d3ca5739bc9ea49fb8862945f3d2b6515c4 100644 --- a/moby.spec +++ b/moby.spec @@ -7,7 +7,7 @@ Name: moby Version: 25.0.3 -Release: 24 +Release: 31 Summary: The open-source application container engine License: Apache-2.0 URL: https://www.docker.com @@ -36,6 +36,13 @@ Patch1009: 1009-mounts-validate-Don-t-check-source-exists-with-Creat.patch Patch1010: 1010-fix-CVE-2024-36621.patch Patch1011: 1011-fix-CVE-2024-36620.patch Patch1012: 1012-fix-CVE-2024-36623.patch +Patch1013: 1013-Don-t-enforce-new-validation-rules-for-existing-netw.patch +Patch1014: 1014-daemon-overlay2-remove-world-writable-permission-fro.patch +Patch1015: 1015-rootless-fix-open-etc-docker-plugins-permission-deni.patch +Patch1016: 1016-Fix-cases-where-we-are-wrapping-a-nil-error.patch +Patch1017: 1017-libnetwork-fix-non-constant-format-string-in-call-go.patch +Patch1018: 1018-Fix-setup-user-chains-even-if-there-are-running-cont.patch +Patch1019: 1019-Dockerd-rootless-make-etc-var-run-cdi-available.patch # Patch 2001-2999 for tini Patch2001: 2001-tini.c-a-function-declaration-without-a-prototype-is.patch Requires(meta): %{name}-engine = %{version}-%{release} @@ -227,6 +234,27 @@ fi %systemd_postun_with_restart docker.service %changelog +* Mon Apr 21 2025 shechenglong - 25.0.3-31 +- Dockerd rootless: make {/etc,/var/run}/cdi available + +* Mon Apr 21 2025 shechenglong - 25.0.3-30 +- Fix: setup user chains even if there are running containers + +* Sun Apr 20 2025 shechenglong - 25.0.3-29 +- libnetwork: fix non-constant format string in call (govet) + +* Sat Apr 19 2025 shechenglong - 25.0.3-28 +- rootless: Fix cases where we are wrapping a nil error + +* Thu Apr 17 2025 shechenglong - 25.0.3-27 +- rootless: fix `open /etc/docker/plugins: permission denied` + +* Thu Apr 17 2025 shechenglong - 25.0.3-26 +- daemon: overlay2: remove world writable permission from the lower file + +* Thu Apr 17 2025 shechenglong - 25.0.3-25 +- Don't enforce new validation rules for existing networks + * Wed Apr 16 2025 Wenlong Zhang - 25.0.3-24 - fix build error on loongarch64