mirror of
https://github.com/opencontainers/runc.git
synced 2026-07-10 21:53:57 +08:00
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>
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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))
|
||||
|
||||
Reference in New Issue
Block a user