You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
87 lines
3.2 KiB
87 lines
3.2 KiB
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))
|