File 0010-CVE-2024-29018-libnet-Don-t-forward-to-upstream-reso.patch of Package docker-stable.38056

From 60abff4c864c08b4ea05d96a304f6cf3f0cca787 Mon Sep 17 00:00:00 2001
From: Albin Kerouanton <albinker@gmail.com>
Date: Tue, 10 Oct 2023 01:13:25 +0200
Subject: [PATCH 10/13] CVE-2024-29018: libnet: Don't forward to upstream
 resolvers on internal nw

Commit cbc2a71c2 makes `connect` syscall fail fast when a container is
only attached to an internal network. Thanks to that, if such a
container tries to resolve an "external" domain, the embedded resolver
returns an error immediately instead of waiting for a timeout.

This commit makes sure the embedded resolver doesn't even try to forward
to upstream servers.

Co-authored-by: Albin Kerouanton <albinker@gmail.com>
Signed-off-by: Rob Murray <rob.murray@docker.com>
(Cherry-picked from commit 790c3039d0ca5ed86ecd099b4b571496607628bc.)
[Drop test additions and test-related patches.]
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
---
 libnetwork/endpoint.go         | 12 +++++++++++-
 libnetwork/resolver.go         | 17 +++++++++++++----
 libnetwork/sandbox_dns_unix.go |  6 +++++-
 3 files changed, 29 insertions(+), 6 deletions(-)

diff --git a/libnetwork/endpoint.go b/libnetwork/endpoint.go
index b9903bb90188..b90500ce97a1 100644
--- a/libnetwork/endpoint.go
+++ b/libnetwork/endpoint.go
@@ -520,8 +520,13 @@ func (ep *Endpoint) sbJoin(sb *Sandbox, options ...EndpointOption) (err error) {
 		return sb.setupDefaultGW()
 	}
 
-	moveExtConn := sb.getGatewayEndpoint() != extEp
+	currentExtEp := sb.getGatewayEndpoint()
+	// Enable upstream forwarding if the sandbox gained external connectivity.
+	if sb.resolver != nil {
+		sb.resolver.SetForwardingPolicy(currentExtEp != nil)
+	}
 
+	moveExtConn := currentExtEp != extEp
 	if moveExtConn {
 		if extEp != nil {
 			logrus.Debugf("Revoking external connectivity on endpoint %s (%s)", extEp.Name(), extEp.ID())
@@ -751,6 +756,11 @@ func (ep *Endpoint) sbLeave(sb *Sandbox, force bool, options ...EndpointOption)
 
 	// New endpoint providing external connectivity for the sandbox
 	extEp = sb.getGatewayEndpoint()
+	// Disable upstream forwarding if the sandbox lost external connectivity.
+	if sb.resolver != nil {
+		sb.resolver.SetForwardingPolicy(extEp != nil)
+	}
+
 	if moveExtConn && extEp != nil {
 		logrus.Debugf("Programming external connectivity on endpoint %s (%s)", extEp.Name(), extEp.ID())
 		extN, err := extEp.getNetworkFromStore()
diff --git a/libnetwork/resolver.go b/libnetwork/resolver.go
index ab19b7b08fc0..70ca33b53590 100644
--- a/libnetwork/resolver.go
+++ b/libnetwork/resolver.go
@@ -7,6 +7,7 @@ import (
 	"net"
 	"strings"
 	"sync"
+	"sync/atomic"
 	"time"
 
 	"github.com/docker/docker/libnetwork/types"
@@ -69,7 +70,7 @@ type Resolver struct {
 	tcpListen     *net.TCPListener
 	err           error
 	listenAddress string
-	proxyDNS      bool
+	proxyDNS      atomic.Bool
 	startCh       chan struct{}
 	logger        *logrus.Logger
 
@@ -79,15 +80,17 @@ type Resolver struct {
 
 // NewResolver creates a new instance of the Resolver
 func NewResolver(address string, proxyDNS bool, backend DNSBackend) *Resolver {
-	return &Resolver{
+	r := &Resolver{
 		backend:       backend,
-		proxyDNS:      proxyDNS,
 		listenAddress: address,
 		err:           fmt.Errorf("setup not done yet"),
 		startCh:       make(chan struct{}, 1),
 		fwdSem:        semaphore.NewWeighted(maxConcurrent),
 		logInverval:   rate.Sometimes{Interval: logInterval},
 	}
+	r.proxyDNS.Store(proxyDNS)
+
+	return r
 }
 
 func (r *Resolver) log() *logrus.Logger {
@@ -192,6 +195,12 @@ func (r *Resolver) SetExtServers(extDNS []extDNSEntry) {
 	}
 }
 
+// SetForwardingPolicy re-configures the embedded DNS resolver to either enable or disable forwarding DNS queries to
+// external servers.
+func (r *Resolver) SetForwardingPolicy(policy bool) {
+	r.proxyDNS.Store(policy)
+}
+
 // NameServer returns the IP of the DNS resolver for the containers.
 func (r *Resolver) NameServer() string {
 	return r.listenAddress
@@ -407,7 +416,7 @@ func (r *Resolver) serveDNS(w dns.ResponseWriter, query *dns.Msg) {
 		return
 	}
 
-	if r.proxyDNS {
+	if r.proxyDNS.Load() {
 		// If the user sets ndots > 0 explicitly and the query is
 		// in the root domain don't forward it out. We will return
 		// failure and let the client retry with the search domain
diff --git a/libnetwork/sandbox_dns_unix.go b/libnetwork/sandbox_dns_unix.go
index 2218c6960e45..e3bb9abce93b 100644
--- a/libnetwork/sandbox_dns_unix.go
+++ b/libnetwork/sandbox_dns_unix.go
@@ -28,7 +28,11 @@ const (
 func (sb *Sandbox) startResolver(restore bool) {
 	sb.resolverOnce.Do(func() {
 		var err error
-		sb.resolver = NewResolver(resolverIPSandbox, true, sb)
+		// The resolver is started with proxyDNS=false if the sandbox does not currently
+		// have a gateway. So, if the Sandbox is only connected to an 'internal' network,
+		// it will not forward DNS requests to external resolvers. The resolver's
+		// proxyDNS setting is then updated as network Endpoints are added/removed.
+		sb.resolver = NewResolver(resolverIPSandbox, sb.getGatewayEndpoint() != nil, sb)
 		defer func() {
 			if err != nil {
 				sb.resolver = nil
-- 
2.48.1

openSUSE Build Service is sponsored by