summaryrefslogtreecommitdiffstats
path: root/recipes-containers/docker/files/CVE-2024-29018.patch
diff options
context:
space:
mode:
Diffstat (limited to 'recipes-containers/docker/files/CVE-2024-29018.patch')
-rw-r--r--recipes-containers/docker/files/CVE-2024-29018.patch344
1 files changed, 0 insertions, 344 deletions
diff --git a/recipes-containers/docker/files/CVE-2024-29018.patch b/recipes-containers/docker/files/CVE-2024-29018.patch
deleted file mode 100644
index f3c800ff..00000000
--- a/recipes-containers/docker/files/CVE-2024-29018.patch
+++ /dev/null
@@ -1,344 +0,0 @@
1From 20c205fd3a0081d005958eff690e2b34df1c5e5e Mon Sep 17 00:00:00 2001
2From: Rob Murray <rob.murray@docker.com>
3Date: Tue, 19 Mar 2024 11:19:30 +0000
4Subject: [PATCH 1/2] Environment variable to override resolv.conf path.
5
6If env var DOCKER_TEST_RESOLV_CONF_PATH is set, treat it as an override
7for the 'resolv.conf' path.
8
9Added as part of resolv.conf refactoring, but needed by back-ported test
10TestInternalNetworkDNS.
11
12Signed-off-by: Rob Murray <rob.murray@docker.com>
13
14CVE: CVE-2024-29018
15Upstream-Status: Backport [https://github.com/moby/moby/commit/e63daec8672d77ac0b2b5c262ef525c7cf17fd20]
16Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
17---
18 daemon/container_operations_unix.go | 20 +--
19 integration/networking/resolvconf_test.go | 142 ++++++++++++++++++++++
20 libnetwork/endpoint.go | 12 +-
21 libnetwork/resolver.go | 17 ++-
22 libnetwork/sandbox_dns_unix.go | 9 +-
23 5 files changed, 182 insertions(+), 18 deletions(-)
24 create mode 100644 integration/networking/resolvconf_test.go
25
26diff --git a/daemon/container_operations_unix.go b/daemon/container_operations_unix.go
27index 6a23a4ca92..e9be1b4e72 100644
28--- a/daemon/container_operations_unix.go
29+++ b/daemon/container_operations_unix.go
30@@ -380,6 +380,7 @@ func serviceDiscoveryOnDefaultNetwork() bool {
31
32 func setupPathsAndSandboxOptions(container *container.Container, cfg *config.Config, sboxOptions *[]libnetwork.SandboxOption) error {
33 var err error
34+ var originResolvConfPath string
35
36 // Set the correct paths for /etc/hosts and /etc/resolv.conf, based on the
37 // networking-mode of the container. Note that containers with "container"
38@@ -393,8 +394,8 @@ func setupPathsAndSandboxOptions(container *container.Container, cfg *config.Con
39 *sboxOptions = append(
40 *sboxOptions,
41 libnetwork.OptionOriginHostsPath("/etc/hosts"),
42- libnetwork.OptionOriginResolvConfPath("/etc/resolv.conf"),
43 )
44+ originResolvConfPath = "/etc/resolv.conf"
45 case container.HostConfig.NetworkMode.IsUserDefined():
46 // The container uses a user-defined network. We use the embedded DNS
47 // server for container name resolution and to act as a DNS forwarder
48@@ -407,10 +408,7 @@ func setupPathsAndSandboxOptions(container *container.Container, cfg *config.Con
49 // If systemd-resolvd is used, the "upstream" DNS servers can be found in
50 // /run/systemd/resolve/resolv.conf. We do not query those DNS servers
51 // directly, as they can be dynamically reconfigured.
52- *sboxOptions = append(
53- *sboxOptions,
54- libnetwork.OptionOriginResolvConfPath("/etc/resolv.conf"),
55- )
56+ originResolvConfPath = "/etc/resolv.conf"
57 default:
58 // For other situations, such as the default bridge network, container
59 // discovery / name resolution is handled through /etc/hosts, and no
60@@ -423,11 +421,15 @@ func setupPathsAndSandboxOptions(container *container.Container, cfg *config.Con
61 // DNS servers on the host can be dynamically updated.
62 //
63 // Copy the host's resolv.conf for the container (/run/systemd/resolve/resolv.conf or /etc/resolv.conf)
64- *sboxOptions = append(
65- *sboxOptions,
66- libnetwork.OptionOriginResolvConfPath(cfg.GetResolvConf()),
67- )
68+ originResolvConfPath = cfg.GetResolvConf()
69+ }
70+
71+ // Allow tests to point at their own resolv.conf file.
72+ if envPath := os.Getenv("DOCKER_TEST_RESOLV_CONF_PATH"); envPath != "" {
73+ log.G(context.TODO()).Infof("Using OriginResolvConfPath from env: %s", envPath)
74+ originResolvConfPath = envPath
75 }
76+ *sboxOptions = append(*sboxOptions, libnetwork.OptionOriginResolvConfPath(originResolvConfPath))
77
78 container.HostsPath, err = container.GetRootResourcePath("hosts")
79 if err != nil {
80diff --git a/integration/networking/resolvconf_test.go b/integration/networking/resolvconf_test.go
81new file mode 100644
82index 0000000000..60c8b1bc9a
83--- /dev/null
84+++ b/integration/networking/resolvconf_test.go
85@@ -0,0 +1,142 @@
86+package networking
87+
88+import (
89+ "net"
90+ "os"
91+ "testing"
92+
93+ containertypes "github.com/docker/docker/api/types/container"
94+ "github.com/docker/docker/integration/internal/container"
95+ "github.com/docker/docker/integration/internal/network"
96+ "github.com/docker/docker/testutil/daemon"
97+ "github.com/miekg/dns"
98+ "gotest.tools/v3/assert"
99+ is "gotest.tools/v3/assert/cmp"
100+ "gotest.tools/v3/skip"
101+)
102+
103+// writeTempResolvConf writes a resolv.conf that only contains a single
104+// nameserver line, with address addr.
105+// It returns the name of the temp file.
106+func writeTempResolvConf(t *testing.T, addr string) string {
107+ t.Helper()
108+ // Not using t.TempDir() here because in rootless mode, while the temporary
109+ // directory gets mode 0777, it's a subdir of an 0700 directory owned by root.
110+ // So, it's not accessible by the daemon.
111+ f, err := os.CreateTemp("", "resolv.conf")
112+ assert.NilError(t, err)
113+ t.Cleanup(func() { os.Remove(f.Name()) })
114+ err = f.Chmod(0644)
115+ assert.NilError(t, err)
116+ f.Write([]byte("nameserver " + addr + "\n"))
117+ return f.Name()
118+}
119+
120+const dnsRespAddr = "10.11.12.13"
121+
122+// startDaftDNS starts and returns a really, really daft DNS server that only
123+// responds to type-A requests, and always with address dnsRespAddr.
124+func startDaftDNS(t *testing.T, addr string) *dns.Server {
125+ serveDNS := func(w dns.ResponseWriter, query *dns.Msg) {
126+ if query.Question[0].Qtype == dns.TypeA {
127+ resp := &dns.Msg{}
128+ resp.SetReply(query)
129+ answer := &dns.A{
130+ Hdr: dns.RR_Header{
131+ Name: query.Question[0].Name,
132+ Rrtype: dns.TypeA,
133+ Class: dns.ClassINET,
134+ Ttl: 600,
135+ },
136+ }
137+ answer.A = net.ParseIP(dnsRespAddr)
138+ resp.Answer = append(resp.Answer, answer)
139+ _ = w.WriteMsg(resp)
140+ }
141+ }
142+
143+ conn, err := net.ListenUDP("udp", &net.UDPAddr{
144+ IP: net.ParseIP(addr),
145+ Port: 53,
146+ })
147+ assert.NilError(t, err)
148+
149+ server := &dns.Server{Handler: dns.HandlerFunc(serveDNS), PacketConn: conn}
150+ go func() {
151+ _ = server.ActivateAndServe()
152+ }()
153+
154+ return server
155+}
156+
157+// Check that when a container is connected to an internal network, DNS
158+// requests sent to daemon's internal DNS resolver are not forwarded to
159+// an upstream resolver listening on a localhost address.
160+// (Assumes the host does not already have a DNS server on 127.0.0.1.)
161+func TestInternalNetworkDNS(t *testing.T) {
162+ skip.If(t, testEnv.DaemonInfo.OSType == "windows", "No resolv.conf on Windows")
163+ skip.If(t, testEnv.IsRootless, "Can't use resolver on host in rootless mode")
164+ ctx := setupTest(t)
165+
166+ // Start a DNS server on the loopback interface.
167+ server := startDaftDNS(t, "127.0.0.1")
168+ defer server.Shutdown()
169+
170+ // Set up a temp resolv.conf pointing at that DNS server, and a daemon using it.
171+ tmpFileName := writeTempResolvConf(t, "127.0.0.1")
172+ d := daemon.New(t, daemon.WithEnvVars("DOCKER_TEST_RESOLV_CONF_PATH="+tmpFileName))
173+ d.StartWithBusybox(ctx, t, "--experimental", "--ip6tables")
174+ defer d.Stop(t)
175+
176+ c := d.NewClientT(t)
177+ defer c.Close()
178+
179+ intNetName := "intnet"
180+ network.CreateNoError(ctx, t, c, intNetName,
181+ network.WithDriver("bridge"),
182+ network.WithInternal(),
183+ )
184+ defer network.RemoveNoError(ctx, t, c, intNetName)
185+
186+ extNetName := "extnet"
187+ network.CreateNoError(ctx, t, c, extNetName,
188+ network.WithDriver("bridge"),
189+ )
190+ defer network.RemoveNoError(ctx, t, c, extNetName)
191+
192+ // Create a container, initially with external connectivity.
193+ // Expect the external DNS server to respond to a request from the container.
194+ ctrId := container.Run(ctx, t, c, container.WithNetworkMode(extNetName))
195+ defer c.ContainerRemove(ctx, ctrId, containertypes.RemoveOptions{Force: true})
196+ res, err := container.Exec(ctx, c, ctrId, []string{"nslookup", "test.example"})
197+ assert.NilError(t, err)
198+ assert.Check(t, is.Equal(res.ExitCode, 0))
199+ assert.Check(t, is.Contains(res.Stdout(), dnsRespAddr))
200+
201+ // Connect the container to the internal network as well.
202+ // External DNS should still be used.
203+ err = c.NetworkConnect(ctx, intNetName, ctrId, nil)
204+ assert.NilError(t, err)
205+ res, err = container.Exec(ctx, c, ctrId, []string{"nslookup", "test.example"})
206+ assert.NilError(t, err)
207+ assert.Check(t, is.Equal(res.ExitCode, 0))
208+ assert.Check(t, is.Contains(res.Stdout(), dnsRespAddr))
209+
210+ // Disconnect from the external network.
211+ // Expect no access to the external DNS.
212+ err = c.NetworkDisconnect(ctx, extNetName, ctrId, true)
213+ assert.NilError(t, err)
214+ res, err = container.Exec(ctx, c, ctrId, []string{"nslookup", "test.example"})
215+ assert.NilError(t, err)
216+ assert.Check(t, is.Equal(res.ExitCode, 1))
217+ assert.Check(t, is.Contains(res.Stdout(), "SERVFAIL"))
218+
219+ // Reconnect the external network.
220+ // Check that the external DNS server is used again.
221+ err = c.NetworkConnect(ctx, extNetName, ctrId, nil)
222+ assert.NilError(t, err)
223+ res, err = container.Exec(ctx, c, ctrId, []string{"nslookup", "test.example"})
224+ assert.NilError(t, err)
225+ assert.Check(t, is.Equal(res.ExitCode, 0))
226+ assert.Check(t, is.Contains(res.Stdout(), dnsRespAddr))
227+}
228diff --git a/libnetwork/endpoint.go b/libnetwork/endpoint.go
229index d9c257dc68..3ca546a4ac 100644
230--- a/libnetwork/endpoint.go
231+++ b/libnetwork/endpoint.go
232@@ -538,8 +538,13 @@ func (ep *Endpoint) sbJoin(sb *Sandbox, options ...EndpointOption) (err error) {
233 return sb.setupDefaultGW()
234 }
235
236- moveExtConn := sb.getGatewayEndpoint() != extEp
237+ currentExtEp := sb.getGatewayEndpoint()
238+ // Enable upstream forwarding if the sandbox gained external connectivity.
239+ if sb.resolver != nil {
240+ sb.resolver.SetForwardingPolicy(currentExtEp != nil)
241+ }
242
243+ moveExtConn := currentExtEp != extEp
244 if moveExtConn {
245 if extEp != nil {
246 log.G(context.TODO()).Debugf("Revoking external connectivity on endpoint %s (%s)", extEp.Name(), extEp.ID())
247@@ -735,6 +740,11 @@ func (ep *Endpoint) sbLeave(sb *Sandbox, force bool, options ...EndpointOption)
248
249 // New endpoint providing external connectivity for the sandbox
250 extEp = sb.getGatewayEndpoint()
251+ // Disable upstream forwarding if the sandbox lost external connectivity.
252+ if sb.resolver != nil {
253+ sb.resolver.SetForwardingPolicy(extEp != nil)
254+ }
255+
256 if moveExtConn && extEp != nil {
257 log.G(context.TODO()).Debugf("Programming external connectivity on endpoint %s (%s)", extEp.Name(), extEp.ID())
258 extN, err := extEp.getNetworkFromStore()
259diff --git a/libnetwork/resolver.go b/libnetwork/resolver.go
260index 9df2154499..5d5686fc86 100644
261--- a/libnetwork/resolver.go
262+++ b/libnetwork/resolver.go
263@@ -9,6 +9,7 @@ import (
264 "strconv"
265 "strings"
266 "sync"
267+ "sync/atomic"
268 "time"
269
270 "github.com/containerd/log"
271@@ -75,7 +76,7 @@ type Resolver struct {
272 tcpListen *net.TCPListener
273 err error
274 listenAddress string
275- proxyDNS bool
276+ proxyDNS atomic.Bool
277 startCh chan struct{}
278 logger *log.Entry
279
280@@ -85,15 +86,17 @@ type Resolver struct {
281
282 // NewResolver creates a new instance of the Resolver
283 func NewResolver(address string, proxyDNS bool, backend DNSBackend) *Resolver {
284- return &Resolver{
285+ r := &Resolver{
286 backend: backend,
287- proxyDNS: proxyDNS,
288 listenAddress: address,
289 err: fmt.Errorf("setup not done yet"),
290 startCh: make(chan struct{}, 1),
291 fwdSem: semaphore.NewWeighted(maxConcurrent),
292 logInverval: rate.Sometimes{Interval: logInterval},
293 }
294+ r.proxyDNS.Store(proxyDNS)
295+
296+ return r
297 }
298
299 func (r *Resolver) log(ctx context.Context) *log.Entry {
300@@ -194,6 +197,12 @@ func (r *Resolver) SetExtServers(extDNS []extDNSEntry) {
301 }
302 }
303
304+// SetForwardingPolicy re-configures the embedded DNS resolver to either enable or disable forwarding DNS queries to
305+// external servers.
306+func (r *Resolver) SetForwardingPolicy(policy bool) {
307+ r.proxyDNS.Store(policy)
308+}
309+
310 // NameServer returns the IP of the DNS resolver for the containers.
311 func (r *Resolver) NameServer() string {
312 return r.listenAddress
313@@ -421,7 +430,7 @@ func (r *Resolver) serveDNS(w dns.ResponseWriter, query *dns.Msg) {
314 return
315 }
316
317- if r.proxyDNS {
318+ if r.proxyDNS.Load() {
319 // If the user sets ndots > 0 explicitly and the query is
320 // in the root domain don't forward it out. We will return
321 // failure and let the client retry with the search domain
322diff --git a/libnetwork/sandbox_dns_unix.go b/libnetwork/sandbox_dns_unix.go
323index e30f394057..9f7a1c4671 100644
324--- a/libnetwork/sandbox_dns_unix.go
325+++ b/libnetwork/sandbox_dns_unix.go
326@@ -30,10 +30,11 @@ const (
327 func (sb *Sandbox) startResolver(restore bool) {
328 sb.resolverOnce.Do(func() {
329 var err error
330- // The embedded resolver is always started with proxyDNS set as true, even when the sandbox is only attached to
331- // an internal network. This way, it's the driver responsibility to make sure `connect` syscall fails fast when
332- // no external connectivity is available (eg. by not setting a default gateway).
333- sb.resolver = NewResolver(resolverIPSandbox, true, sb)
334+ // The resolver is started with proxyDNS=false if the sandbox does not currently
335+ // have a gateway. So, if the Sandbox is only connected to an 'internal' network,
336+ // it will not forward DNS requests to external resolvers. The resolver's
337+ // proxyDNS setting is then updated as network Endpoints are added/removed.
338+ sb.resolver = NewResolver(resolverIPSandbox, sb.getGatewayEndpoint() != nil, sb)
339 defer func() {
340 if err != nil {
341 sb.resolver = nil
342--
3432.50.1
344