From a9b119d4858a40936583262cb8d878036a0171dd Mon Sep 17 00:00:00 2001 From: root Date: Sun, 14 Apr 2024 19:46:56 +0800 Subject: [PATCH] fix cve-2024-29018 --- integration/networking/bridge_test.go | 20 +++++++++++++++----- libnetwork/endpoint.go | 8 +++++++- libnetwork/resolver.go | 21 +++++++++++++++++---- libnetwork/sandbox_dns_unix.go | 5 +---- 4 files changed, 40 insertions(+), 14 deletions(-) diff --git a/integration/networking/bridge_test.go b/integration/networking/bridge_test.go index e3d1fe2..4be3e55 100644 --- a/integration/networking/bridge_test.go +++ b/integration/networking/bridge_test.go @@ -36,7 +36,8 @@ func TestBridgeICC(t *testing.T) { name string bridgeOpts []func(*types.NetworkCreate) ctr1MacAddress string - linkLocal bool + isIPv6 bool + isLinkLocal bool pingHost string }{ { @@ -55,6 +56,7 @@ func TestBridgeICC(t *testing.T) { network.WithIPv6(), network.WithIPAM("fdf1:a844:380c:b200::/64", "fdf1:a844:380c:b200::1"), }, + isIPv6: true, }, { name: "IPv6 ULA on internal network", @@ -74,7 +76,8 @@ func TestBridgeICC(t *testing.T) { // 2. the one dynamically assigned by the IPAM driver. network.WithIPAM("fe80::/64", "fe80::1"), }, - linkLocal: true, + isLinkLocal: true, + isIPv6: true, }, { name: "IPv6 link-local address on internal network", @@ -84,7 +87,8 @@ func TestBridgeICC(t *testing.T) { // See the note above about link-local addresses. network.WithIPAM("fe80::/64", "fe80::1"), }, - linkLocal: true, + isLinkLocal: true, + isIPv6: true, }, { // As for 'LL non-internal', but ping the container by name instead of by address @@ -122,6 +126,7 @@ func TestBridgeICC(t *testing.T) { // specify one here to hardcode the SLAAC LL address below. ctr1MacAddress: "02:42:ac:11:00:02", pingHost: "fe80::42:acff:fe11:2%eth0", + isIPv6: true, }, { name: "IPv6 internal network with SLAAC LL address", @@ -133,6 +138,7 @@ func TestBridgeICC(t *testing.T) { // specify one here to hardcode the SLAAC LL address below. ctr1MacAddress: "02:42:ac:11:00:02", pingHost: "fe80::42:acff:fe11:2%eth0", + isIPv6: true, }, } @@ -162,7 +168,7 @@ func TestBridgeICC(t *testing.T) { pingHost := tc.pingHost if pingHost == "" { - if tc.linkLocal { + if tc.isLinkLocal { inspect := container.Inspect(ctx, t, c, id1) pingHost = inspect.NetworkSettings.Networks[bridgeName].GlobalIPv6Address + "%eth0" } else { @@ -170,7 +176,11 @@ func TestBridgeICC(t *testing.T) { } } - pingCmd := []string{"ping", "-c1", "-W3", pingHost} + pingCmd := []string{"ping", "-c1", "-W3"} + if tc.isIPv6 { + pingCmd = append(pingCmd, "-6") + } + pingCmd = append(pingCmd, pingHost) ctr2Name := fmt.Sprintf("ctr-icc-%d-2", tcID) attachCtx, cancel := context.WithTimeout(ctx, 5*time.Second) diff --git a/libnetwork/endpoint.go b/libnetwork/endpoint.go index d9c257d..93ddbc9 100644 --- a/libnetwork/endpoint.go +++ b/libnetwork/endpoint.go @@ -538,8 +538,11 @@ 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. + sb.resolver.SetForwardingPolicy(currentExtEp != nil) + moveExtConn := currentExtEp != extEp if moveExtConn { if extEp != nil { log.G(context.TODO()).Debugf("Revoking external connectivity on endpoint %s (%s)", extEp.Name(), extEp.ID()) @@ -735,6 +738,9 @@ 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. + sb.resolver.SetForwardingPolicy(extEp != nil) + if moveExtConn && extEp != nil { log.G(context.TODO()).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 9df2154..6da595c 100644 --- a/libnetwork/resolver.go +++ b/libnetwork/resolver.go @@ -9,6 +9,7 @@ import ( "strconv" "strings" "sync" + "sync/atomic" "time" "github.com/containerd/log" @@ -75,7 +76,7 @@ type Resolver struct { tcpListen *net.TCPListener err error listenAddress string - proxyDNS bool + proxyDNS atomic.Bool startCh chan struct{} logger *log.Entry @@ -85,15 +86,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(ctx context.Context) *log.Entry { @@ -103,6 +106,8 @@ func (r *Resolver) log(ctx context.Context) *log.Entry { return r.logger } + + // SetupFunc returns the setup function that should be run in the container's // network namespace. func (r *Resolver) SetupFunc(port int) func() { @@ -194,6 +199,14 @@ 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) { + if r != nil { + r.proxyDNS.Store(policy) + } +} + // NameServer returns the IP of the DNS resolver for the containers. func (r *Resolver) NameServer() string { return r.listenAddress @@ -421,7 +434,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 e30f394..505c5f5 100644 --- a/libnetwork/sandbox_dns_unix.go +++ b/libnetwork/sandbox_dns_unix.go @@ -30,10 +30,7 @@ const ( func (sb *Sandbox) startResolver(restore bool) { sb.resolverOnce.Do(func() { var err error - // The embedded resolver is always started with proxyDNS set as true, even when the sandbox is only attached to - // an internal network. This way, it's the driver responsibility to make sure `connect` syscall fails fast when - // no external connectivity is available (eg. by not setting a default gateway). - sb.resolver = NewResolver(resolverIPSandbox, true, sb) + sb.resolver = NewResolver(resolverIPSandbox, sb.getGatewayEndpoint() != nil, sb) defer func() { if err != nil { sb.resolver = nil -- 2.27.0