Skip to content

Commit b8dbe46

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 4f0bb00 commit b8dbe46

2 files changed

Lines changed: 28 additions & 1 deletion

File tree

libcontainer/container_linux.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2028,16 +2028,34 @@ func encodeIDMapping(idMap []configs.IDMap) ([]byte, error) {
20282028
return data.Bytes(), nil
20292029
}
20302030

2031+
// netlinkError is an error wrapper type for use by custom netlink message
2032+
// types. Panics with errors are wrapped in netlinkError so that the recover
2033+
// in bootstrapData can distinguish intentional panics.
2034+
type netlinkError struct{ error }
2035+
20312036
// bootstrapData encodes the necessary data in netlink binary format
20322037
// as a io.Reader.
20332038
// Consumer can write the data to a bootstrap program
20342039
// such as one that uses nsenter package to bootstrap the container's
20352040
// init process correctly, i.e. with correct namespaces, uid/gid
20362041
// mapping etc.
2037-
func (c *linuxContainer) bootstrapData(cloneFlags uintptr, nsMaps map[configs.NamespaceType]string) (io.Reader, error) {
2042+
func (c *linuxContainer) bootstrapData(cloneFlags uintptr, nsMaps map[configs.NamespaceType]string) (_ io.Reader, Err error) {
20382043
// create the netlink message
20392044
r := nl.NewNetlinkRequest(int(InitMsg), 0)
20402045

2046+
// Our custom messages cannot bubble up an error using returns, instead
2047+
// they will panic with the specific error type, netlinkError. In that
2048+
// case, recover from the panic and return that as an error.
2049+
defer func() {
2050+
if r := recover(); r != nil {
2051+
if e, ok := r.(netlinkError); ok {
2052+
Err = e.error
2053+
} else {
2054+
panic(r)
2055+
}
2056+
}
2057+
}()
2058+
20412059
// write cloneFlags
20422060
r.AddData(&Int32msg{
20432061
Type: CloneFlagsAttr,

libcontainer/message_linux.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
package libcontainer
44

55
import (
6+
"fmt"
7+
"math"
8+
69
"github.com/vishvananda/netlink/nl"
710
"golang.org/x/sys/unix"
811
)
@@ -54,6 +57,12 @@ type Bytemsg struct {
5457

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

0 commit comments

Comments
 (0)