summaryrefslogtreecommitdiff
path: root/app-containers/runc/files/CVE-2021-43784.patch
blob: ab3886ee9ba7cfcc6b3051b5252265a54e23e8c6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
From b8dbe46687c2a96efa9252b69d3fc1ce33bdc416 Mon Sep 17 00:00:00 2001
From: Aleksa Sarai <cyphar@cyphar.com>
Date: Thu, 18 Nov 2021 16:12:59 +1100
Subject: [PATCH] runc init: avoid netlink message length overflows

When writing netlink messages, it is possible to have a byte array
larger than UINT16_MAX which would result in the length field
overflowing and allowing user-controlled data to be parsed as control
characters (such as creating custom mount points, changing which set of
namespaces to allow, and so on).

Co-authored-by: Kir Kolyshkin <kolyshkin@gmail.com>
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
---
 libcontainer/container_linux.go | 20 +++++++++++++++++++-
 libcontainer/message_linux.go   |  9 +++++++++
 2 files changed, 28 insertions(+), 1 deletion(-)

diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go
index 6ce1854f68..1484703b0c 100644
--- a/libcontainer/container_linux.go
+++ b/libcontainer/container_linux.go
@@ -2028,16 +2028,34 @@ func encodeIDMapping(idMap []configs.IDMap) ([]byte, error) {
 	return data.Bytes(), nil
 }
 
+// netlinkError is an error wrapper type for use by custom netlink message
+// types. Panics with errors are wrapped in netlinkError so that the recover
+// in bootstrapData can distinguish intentional panics.
+type netlinkError struct{ error }
+
 // bootstrapData encodes the necessary data in netlink binary format
 // as a io.Reader.
 // Consumer can write the data to a bootstrap program
 // such as one that uses nsenter package to bootstrap the container's
 // init process correctly, i.e. with correct namespaces, uid/gid
 // mapping etc.
-func (c *linuxContainer) bootstrapData(cloneFlags uintptr, nsMaps map[configs.NamespaceType]string) (io.Reader, error) {
+func (c *linuxContainer) bootstrapData(cloneFlags uintptr, nsMaps map[configs.NamespaceType]string) (_ io.Reader, Err error) {
 	// create the netlink message
 	r := nl.NewNetlinkRequest(int(InitMsg), 0)
 
+	// Our custom messages cannot bubble up an error using returns, instead
+	// they will panic with the specific error type, netlinkError. In that
+	// case, recover from the panic and return that as an error.
+	defer func() {
+		if r := recover(); r != nil {
+			if e, ok := r.(netlinkError); ok {
+				Err = e.error
+			} else {
+				panic(r)
+			}
+		}
+	}()
+
 	// write cloneFlags
 	r.AddData(&Int32msg{
 		Type:  CloneFlagsAttr,
diff --git a/libcontainer/message_linux.go b/libcontainer/message_linux.go
index 1d4f5033aa..e4107ce39f 100644
--- a/libcontainer/message_linux.go
+++ b/libcontainer/message_linux.go
@@ -3,6 +3,9 @@
 package libcontainer
 
 import (
+	"fmt"
+	"math"
+
 	"github.com/vishvananda/netlink/nl"
 	"golang.org/x/sys/unix"
 )
@@ -54,6 +57,12 @@ type Bytemsg struct {
 
 func (msg *Bytemsg) Serialize() []byte {
 	l := msg.Len()
+	if l > math.MaxUint16 {
+		// We cannot return nil nor an error here, so we panic with
+		// a specific type instead, which is handled via recover in
+		// bootstrapData.
+		panic(netlinkError{fmt.Errorf("netlink: cannot serialize bytemsg of length %d (larger than UINT16_MAX)", l)})
+	}
 	buf := make([]byte, (l+unix.NLA_ALIGNTO-1) & ^(unix.NLA_ALIGNTO-1))
 	native := nl.NativeEndian()
 	native.PutUint16(buf[0:2], uint16(l))