From b8dbe46687c2a96efa9252b69d3fc1ce33bdc416 Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Thu, 18 Nov 2021 16:12:59 +1100 Subject: [PATCH 1/3] 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 Signed-off-by: Kir Kolyshkin Signed-off-by: Aleksa Sarai --- 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 6ce1854f6..1484703b0 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 1d4f5033a..e4107ce39 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)) From f46b6ba2c9314cfc8caae24a32ec5fe9ef1059fe Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Fri, 3 Dec 2021 11:01:46 +1100 Subject: [PATCH 2/3] VERSION: release v1.0.3 Signed-off-by: Aleksa Sarai --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index f650172cd..21e8796a0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.2+dev +1.0.3 From 31f7b334076f7cc8203ef6ca6aefa644d7239c8c Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Fri, 3 Dec 2021 11:02:03 +1100 Subject: [PATCH 3/3] VERSION: back to development Signed-off-by: Aleksa Sarai --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 21e8796a0..724c5ddaa 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.3 +1.0.3+dev