From 60abff4c864c08b4ea05d96a304f6cf3f0cca787 Mon Sep 17 00:00:00 2001 From: Albin Kerouanton 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 Signed-off-by: Rob Murray (Cherry-picked from commit 790c3039d0ca5ed86ecd099b4b571496607628bc.) [Drop test additions and test-related patches.] Signed-off-by: Aleksa Sarai --- 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