Skip to content

Commit d72d057

Browse files
cypharkolyshkin
andcommitted
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 <[email protected]> Signed-off-by: Kir Kolyshkin <[email protected]> Signed-off-by: Aleksa Sarai <[email protected]>
1 parent 0c0ec3f commit d72d057

File tree

2 files changed

+28
-1
lines changed

2 files changed

+28
-1
lines changed

Diff for: libcontainer/container_linux.go

+19-1
Original file line numberDiff line numberDiff line change
@@ -2102,16 +2102,34 @@ func encodeIDMapping(idMap []configs.IDMap) ([]byte, error) {
21022102
return data.Bytes(), nil
21032103
}
21042104

2105+
// netlinkError is an error wrapper type for use by custom netlink message
2106+
// types. Panics with errors are wrapped in netlinkError so that the recover
2107+
// in bootstrapData can distinguish intentional panics.
2108+
type netlinkError struct{ error }
2109+
21052110
// bootstrapData encodes the necessary data in netlink binary format
21062111
// as a io.Reader.
21072112
// Consumer can write the data to a bootstrap program
21082113
// such as one that uses nsenter package to bootstrap the container's
21092114
// init process correctly, i.e. with correct namespaces, uid/gid
21102115
// mapping etc.
2111-
func (c *linuxContainer) bootstrapData(cloneFlags uintptr, nsMaps map[configs.NamespaceType]string, it initType) (io.Reader, error) {
2116+
func (c *linuxContainer) bootstrapData(cloneFlags uintptr, nsMaps map[configs.NamespaceType]string, it initType) (_ io.Reader, Err error) {
21122117
// create the netlink message
21132118
r := nl.NewNetlinkRequest(int(InitMsg), 0)
21142119

2120+
// Our custom messages cannot bubble up an error using returns, instead
2121+
// they will panic with the specific error type, netlinkError. In that
2122+
// case, recover from the panic and return that as an error.
2123+
defer func() {
2124+
if r := recover(); r != nil {
2125+
if e, ok := r.(netlinkError); ok {
2126+
Err = e.error
2127+
} else {
2128+
panic(r)
2129+
}
2130+
}
2131+
}()
2132+
21152133
// write cloneFlags
21162134
r.AddData(&Int32msg{
21172135
Type: CloneFlagsAttr,

Diff for: libcontainer/message_linux.go

+9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package libcontainer
22

33
import (
4+
"fmt"
5+
"math"
6+
47
"github.com/vishvananda/netlink/nl"
58
"golang.org/x/sys/unix"
69
)
@@ -53,6 +56,12 @@ type Bytemsg struct {
5356

5457
func (msg *Bytemsg) Serialize() []byte {
5558
l := msg.Len()
59+
if l > math.MaxUint16 {
60+
// We cannot return nil nor an error here, so we panic with
61+
// a specific type instead, which is handled via recover in
62+
// bootstrapData.
63+
panic(netlinkError{fmt.Errorf("netlink: cannot serialize bytemsg of length %d (larger than UINT16_MAX)", l)})
64+
}
5665
buf := make([]byte, (l+unix.NLA_ALIGNTO-1) & ^(unix.NLA_ALIGNTO-1))
5766
native := nl.NativeEndian()
5867
native.PutUint16(buf[0:2], uint16(l))

0 commit comments

Comments
 (0)