mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Avoid uint32 to int cast in lisafs unmarshalling code.
On 32 bit systems, 0xffffffff will be cast to -1 which can trip the bound checks in the unmarshalling code. A compromised sentry (client) will be able to panic the gofer server. PiperOrigin-RevId: 423221118
This commit is contained in:
+2
-2
@@ -344,11 +344,11 @@ type ControlFDImpl interface {
|
||||
Symlink(c *Connection, name string, target string, uid UID, gid GID) (Inode, error)
|
||||
Link(c *Connection, dir ControlFDImpl, name string) (Inode, error)
|
||||
StatFS(c *Connection) (StatFS, error)
|
||||
Readlink(c *Connection, getLinkBuf func(uint32) []byte) (uint32, error)
|
||||
Readlink(c *Connection, getLinkBuf func(uint32) []byte) (uint16, error)
|
||||
Connect(c *Connection, sockType uint32) (int, error)
|
||||
Unlink(c *Connection, name string, flags uint32) error
|
||||
RenameLocked(c *Connection, newDir ControlFDImpl, newName string) (func(ControlFDImpl), func(), error)
|
||||
GetXattr(c *Connection, name string, dataBuf []byte) (uint32, error)
|
||||
GetXattr(c *Connection, name string, dataBuf []byte) (uint16, error)
|
||||
SetXattr(c *Connection, name string, value string, flags uint32) error
|
||||
ListXattr(c *Connection, size uint64) (StringArray, error)
|
||||
RemoveXattr(c *Connection, name string) error
|
||||
|
||||
@@ -251,7 +251,7 @@ func WalkHandler(c *Connection, comm Communicator, payloadLen uint32) (uint32, e
|
||||
// the slice allocation. The memory format should be WalkResp's.
|
||||
var (
|
||||
status WalkStatus
|
||||
numInodes primitive.Uint32
|
||||
numInodes primitive.Uint16
|
||||
)
|
||||
maxPayloadSize := status.SizeBytes() + numInodes.SizeBytes() + (len(req.Path) * (*Inode)(nil).SizeBytes())
|
||||
if maxPayloadSize > math.MaxUint32 {
|
||||
@@ -308,7 +308,7 @@ func WalkStatHandler(c *Connection, comm Communicator, payloadLen uint32) (uint3
|
||||
// We will manually marshal the statx results into the payload buffer as they
|
||||
// are generated to avoid the slice allocation. The memory format should be
|
||||
// the same as WalkStatResp's.
|
||||
var numStats primitive.Uint32
|
||||
var numStats primitive.Uint16
|
||||
maxPayloadSize := numStats.SizeBytes() + (len(req.Path) * linux.SizeOfStatx)
|
||||
if maxPayloadSize > math.MaxUint32 {
|
||||
// Too much to walk, can't do.
|
||||
@@ -730,7 +730,7 @@ func ReadLinkAtHandler(c *Connection, comm Communicator, payloadLen uint32) (uin
|
||||
// We will manually marshal ReadLinkAtResp, which just contains a
|
||||
// SizedString. Let Readlinkat directly write into the payload buffer and
|
||||
// manually write the string size before it.
|
||||
var linkLen primitive.Uint32
|
||||
var linkLen primitive.Uint16
|
||||
respMetaSize := uint32(linkLen.SizeBytes())
|
||||
n, err := fd.impl.Readlink(c, func(dataLen uint32) []byte {
|
||||
return comm.PayloadBuf(dataLen + respMetaSize)[respMetaSize:]
|
||||
@@ -738,9 +738,9 @@ func ReadLinkAtHandler(c *Connection, comm Communicator, payloadLen uint32) (uin
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
linkLen = primitive.Uint32(n)
|
||||
linkLen = primitive.Uint16(n)
|
||||
linkLen.MarshalUnsafe(comm.PayloadBuf(respMetaSize))
|
||||
return respMetaSize + n, nil
|
||||
return respMetaSize + uint32(n), nil
|
||||
}
|
||||
|
||||
// FlushHandler handles the Flush RPC.
|
||||
@@ -923,7 +923,7 @@ func Getdents64Handler(c *Connection, comm Communicator, payloadLen uint32) (uin
|
||||
// We will manually marshal the response Getdents64Resp.
|
||||
|
||||
// numDirents is the number of dirents marshalled into the payload.
|
||||
var numDirents primitive.Uint32
|
||||
var numDirents primitive.Uint16
|
||||
// The payload starts with numDirents, dirents go right after that.
|
||||
// payloadBufPos represents the position at which to write the next dirent.
|
||||
payloadBufPos := uint32(numDirents.SizeBytes())
|
||||
@@ -964,16 +964,16 @@ func FGetXattrHandler(c *Connection, comm Communicator, payloadLen uint32) (uint
|
||||
|
||||
// Manually marshal FGetXattrResp to avoid allocations and copying.
|
||||
// FGetXattrResp simply is a wrapper around SizedString.
|
||||
var valueLen primitive.Uint32
|
||||
var valueLen primitive.Uint16
|
||||
respMetaSize := uint32(valueLen.SizeBytes())
|
||||
payloadBuf := comm.PayloadBuf(respMetaSize + uint32(req.BufSize))
|
||||
n, err := fd.impl.GetXattr(c, string(req.Name), payloadBuf[respMetaSize:])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
valueLen = primitive.Uint32(n)
|
||||
valueLen = primitive.Uint16(n)
|
||||
valueLen.MarshalBytes(payloadBuf)
|
||||
return respMetaSize + n, nil
|
||||
return respMetaSize + uint32(n), nil
|
||||
}
|
||||
|
||||
// FSetXattrHandler handles the FSetXattr RPC.
|
||||
|
||||
+30
-27
@@ -181,17 +181,17 @@ func NoopMarshal(b []byte) []byte { return b }
|
||||
func NoopUnmarshal(b []byte) ([]byte, bool) { return b, true }
|
||||
|
||||
// SizedString represents a string in memory. The marshalled string bytes are
|
||||
// preceded by a uint32 signifying the string length.
|
||||
// preceded by a uint16 signifying the string length.
|
||||
type SizedString string
|
||||
|
||||
// SizeBytes implements marshal.Marshallable.SizeBytes.
|
||||
func (s *SizedString) SizeBytes() int {
|
||||
return (*primitive.Uint32)(nil).SizeBytes() + len(*s)
|
||||
return (*primitive.Uint16)(nil).SizeBytes() + len(*s)
|
||||
}
|
||||
|
||||
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
|
||||
func (s *SizedString) MarshalBytes(dst []byte) []byte {
|
||||
strLen := primitive.Uint32(len(*s))
|
||||
strLen := primitive.Uint16(len(*s))
|
||||
dst = strLen.MarshalUnsafe(dst)
|
||||
// Copy without any allocation.
|
||||
return dst[copy(dst[:strLen], *s):]
|
||||
@@ -199,7 +199,7 @@ func (s *SizedString) MarshalBytes(dst []byte) []byte {
|
||||
|
||||
// CheckedUnmarshal implements marshal.CheckedMarshallable.CheckedUnmarshal.
|
||||
func (s *SizedString) CheckedUnmarshal(src []byte) ([]byte, bool) {
|
||||
var strLen primitive.Uint32
|
||||
var strLen primitive.Uint16
|
||||
srcRemain, ok := strLen.CheckedUnmarshal(src)
|
||||
if !ok || len(srcRemain) < int(strLen) {
|
||||
return src, false
|
||||
@@ -210,12 +210,12 @@ func (s *SizedString) CheckedUnmarshal(src []byte) ([]byte, bool) {
|
||||
}
|
||||
|
||||
// StringArray represents an array of SizedStrings in memory. The marshalled
|
||||
// array data is preceded by a uint32 signifying the array length.
|
||||
// array data is preceded by a uint16 signifying the array length.
|
||||
type StringArray []string
|
||||
|
||||
// SizeBytes implements marshal.Marshallable.SizeBytes.
|
||||
func (s *StringArray) SizeBytes() int {
|
||||
size := (*primitive.Uint32)(nil).SizeBytes()
|
||||
size := (*primitive.Uint16)(nil).SizeBytes()
|
||||
for _, str := range *s {
|
||||
sstr := SizedString(str)
|
||||
size += sstr.SizeBytes()
|
||||
@@ -225,7 +225,7 @@ func (s *StringArray) SizeBytes() int {
|
||||
|
||||
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
|
||||
func (s *StringArray) MarshalBytes(dst []byte) []byte {
|
||||
arrLen := primitive.Uint32(len(*s))
|
||||
arrLen := primitive.Uint16(len(*s))
|
||||
dst = arrLen.MarshalUnsafe(dst)
|
||||
for _, str := range *s {
|
||||
sstr := SizedString(str)
|
||||
@@ -236,7 +236,7 @@ func (s *StringArray) MarshalBytes(dst []byte) []byte {
|
||||
|
||||
// CheckedUnmarshal implements marshal.CheckedMarshallable.CheckedUnmarshal.
|
||||
func (s *StringArray) CheckedUnmarshal(src []byte) ([]byte, bool) {
|
||||
var arrLen primitive.Uint32
|
||||
var arrLen primitive.Uint16
|
||||
srcRemain, ok := arrLen.CheckedUnmarshal(src)
|
||||
if !ok {
|
||||
return src, false
|
||||
@@ -248,7 +248,7 @@ func (s *StringArray) CheckedUnmarshal(src []byte) ([]byte, bool) {
|
||||
*s = (*s)[:arrLen]
|
||||
}
|
||||
|
||||
for i := primitive.Uint32(0); i < arrLen; i++ {
|
||||
for i := primitive.Uint16(0); i < arrLen; i++ {
|
||||
var sstr SizedString
|
||||
srcRemain, ok = sstr.CheckedUnmarshal(srcRemain)
|
||||
if !ok {
|
||||
@@ -436,7 +436,8 @@ const (
|
||||
WalkComponentSymlink
|
||||
)
|
||||
|
||||
// WalkResp is used to communicate the inodes walked by the server.
|
||||
// WalkResp is used to communicate the inodes walked by the server. In memory,
|
||||
// the inode array is preceded by a uint16 integer denoting array length.
|
||||
type WalkResp struct {
|
||||
Status WalkStatus
|
||||
Inodes []Inode
|
||||
@@ -445,14 +446,14 @@ type WalkResp struct {
|
||||
// SizeBytes implements marshal.Marshallable.SizeBytes.
|
||||
func (w *WalkResp) SizeBytes() int {
|
||||
return w.Status.SizeBytes() +
|
||||
(*primitive.Uint32)(nil).SizeBytes() + (len(w.Inodes) * (*Inode)(nil).SizeBytes())
|
||||
(*primitive.Uint16)(nil).SizeBytes() + (len(w.Inodes) * (*Inode)(nil).SizeBytes())
|
||||
}
|
||||
|
||||
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
|
||||
func (w *WalkResp) MarshalBytes(dst []byte) []byte {
|
||||
dst = w.Status.MarshalUnsafe(dst)
|
||||
|
||||
numInodes := primitive.Uint32(len(w.Inodes))
|
||||
numInodes := primitive.Uint16(len(w.Inodes))
|
||||
dst = numInodes.MarshalUnsafe(dst)
|
||||
|
||||
return MarshalUnsafeInodeSlice(w.Inodes, dst)
|
||||
@@ -466,7 +467,7 @@ func (w *WalkResp) CheckedUnmarshal(src []byte) ([]byte, bool) {
|
||||
}
|
||||
srcRemain := w.Status.UnmarshalUnsafe(src)
|
||||
|
||||
var numInodes primitive.Uint32
|
||||
var numInodes primitive.Uint16
|
||||
srcRemain = numInodes.UnmarshalUnsafe(srcRemain)
|
||||
if int(numInodes)*(*Inode)(nil).SizeBytes() > len(srcRemain) {
|
||||
return src, false
|
||||
@@ -479,19 +480,20 @@ func (w *WalkResp) CheckedUnmarshal(src []byte) ([]byte, bool) {
|
||||
return UnmarshalUnsafeInodeSlice(w.Inodes, srcRemain), true
|
||||
}
|
||||
|
||||
// WalkStatResp is used to communicate stat results for WalkStat.
|
||||
// WalkStatResp is used to communicate stat results for WalkStat. In memory,
|
||||
// the array data is preceded by a uint16 denoting the array length.
|
||||
type WalkStatResp struct {
|
||||
Stats []linux.Statx
|
||||
}
|
||||
|
||||
// SizeBytes implements marshal.Marshallable.SizeBytes.
|
||||
func (w *WalkStatResp) SizeBytes() int {
|
||||
return (*primitive.Uint32)(nil).SizeBytes() + (len(w.Stats) * linux.SizeOfStatx)
|
||||
return (*primitive.Uint16)(nil).SizeBytes() + (len(w.Stats) * linux.SizeOfStatx)
|
||||
}
|
||||
|
||||
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
|
||||
func (w *WalkStatResp) MarshalBytes(dst []byte) []byte {
|
||||
numStats := primitive.Uint32(len(w.Stats))
|
||||
numStats := primitive.Uint16(len(w.Stats))
|
||||
dst = numStats.MarshalUnsafe(dst)
|
||||
|
||||
return linux.MarshalUnsafeStatxSlice(w.Stats, dst)
|
||||
@@ -503,7 +505,7 @@ func (w *WalkStatResp) CheckedUnmarshal(src []byte) ([]byte, bool) {
|
||||
if w.SizeBytes() > len(src) {
|
||||
return src, false
|
||||
}
|
||||
var numStats primitive.Uint32
|
||||
var numStats primitive.Uint16
|
||||
srcRemain := numStats.UnmarshalUnsafe(src)
|
||||
|
||||
if int(numStats)*linux.SizeOfStatx > len(srcRemain) {
|
||||
@@ -585,17 +587,17 @@ type OpenCreateAtResp struct {
|
||||
|
||||
// FdArray is a utility struct which implements a marshallable type for
|
||||
// communicating an array of FDIDs. In memory, the array data is preceded by a
|
||||
// uint32 denoting the array length.
|
||||
// uint16 denoting the array length.
|
||||
type FdArray []FDID
|
||||
|
||||
// SizeBytes implements marshal.Marshallable.SizeBytes.
|
||||
func (f *FdArray) SizeBytes() int {
|
||||
return (*primitive.Uint32)(nil).SizeBytes() + (len(*f) * (*FDID)(nil).SizeBytes())
|
||||
return (*primitive.Uint16)(nil).SizeBytes() + (len(*f) * (*FDID)(nil).SizeBytes())
|
||||
}
|
||||
|
||||
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
|
||||
func (f *FdArray) MarshalBytes(dst []byte) []byte {
|
||||
arrLen := primitive.Uint32(len(*f))
|
||||
arrLen := primitive.Uint16(len(*f))
|
||||
dst = arrLen.MarshalUnsafe(dst)
|
||||
return MarshalUnsafeFDIDSlice(*f, dst)
|
||||
}
|
||||
@@ -606,7 +608,7 @@ func (f *FdArray) CheckedUnmarshal(src []byte) ([]byte, bool) {
|
||||
if f.SizeBytes() > len(src) {
|
||||
return src, false
|
||||
}
|
||||
var arrLen primitive.Uint32
|
||||
var arrLen primitive.Uint16
|
||||
srcRemain := arrLen.UnmarshalUnsafe(src)
|
||||
if int(arrLen)*(*FDID)(nil).SizeBytes() > len(srcRemain) {
|
||||
return src, false
|
||||
@@ -688,7 +690,7 @@ func (r *PReadResp) MarshalBytes(dst []byte) []byte {
|
||||
// CheckedUnmarshal implements marshal.CheckedMarshallable.CheckedUnmarshal.
|
||||
func (r *PReadResp) CheckedUnmarshal(src []byte) ([]byte, bool) {
|
||||
srcRemain, ok := r.NumBytes.CheckedUnmarshal(src)
|
||||
if !ok || int(r.NumBytes) > len(srcRemain) || int(r.NumBytes) > len(r.Buf) {
|
||||
if !ok || uint32(r.NumBytes) > uint32(len(srcRemain)) || uint32(r.NumBytes) > uint32(len(r.Buf)) {
|
||||
return src, false
|
||||
}
|
||||
|
||||
@@ -730,7 +732,7 @@ func (w *PWriteReq) CheckedUnmarshal(src []byte) ([]byte, bool) {
|
||||
|
||||
// This is an optimization. Assuming that the server is making this call, it
|
||||
// is safe to just point to src rather than allocating and copying.
|
||||
if int(w.NumBytes) > len(srcRemain) {
|
||||
if uint32(w.NumBytes) > uint32(len(srcRemain)) {
|
||||
return src, false
|
||||
}
|
||||
w.Buf = srcRemain[:w.NumBytes]
|
||||
@@ -1112,14 +1114,15 @@ func (d *Dirent64) CheckedUnmarshal(src []byte) ([]byte, bool) {
|
||||
return src, false
|
||||
}
|
||||
|
||||
// Getdents64Resp is used to communicate getdents64 results.
|
||||
// Getdents64Resp is used to communicate getdents64 results. In memory, the
|
||||
// dirents array is preceded by a uint16 integer denoting array length.
|
||||
type Getdents64Resp struct {
|
||||
Dirents []Dirent64
|
||||
}
|
||||
|
||||
// SizeBytes implements marshal.Marshallable.SizeBytes.
|
||||
func (g *Getdents64Resp) SizeBytes() int {
|
||||
ret := (*primitive.Uint32)(nil).SizeBytes()
|
||||
ret := (*primitive.Uint16)(nil).SizeBytes()
|
||||
for i := range g.Dirents {
|
||||
ret += g.Dirents[i].SizeBytes()
|
||||
}
|
||||
@@ -1128,7 +1131,7 @@ func (g *Getdents64Resp) SizeBytes() int {
|
||||
|
||||
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
|
||||
func (g *Getdents64Resp) MarshalBytes(dst []byte) []byte {
|
||||
numDirents := primitive.Uint32(len(g.Dirents))
|
||||
numDirents := primitive.Uint16(len(g.Dirents))
|
||||
dst = numDirents.MarshalUnsafe(dst)
|
||||
for i := range g.Dirents {
|
||||
dst = g.Dirents[i].MarshalBytes(dst)
|
||||
@@ -1142,7 +1145,7 @@ func (g *Getdents64Resp) CheckedUnmarshal(src []byte) ([]byte, bool) {
|
||||
if g.SizeBytes() > len(src) {
|
||||
return src, false
|
||||
}
|
||||
var numDirents primitive.Uint32
|
||||
var numDirents primitive.Uint16
|
||||
srcRemain := numDirents.UnmarshalUnsafe(src)
|
||||
if cap(g.Dirents) < int(numDirents) {
|
||||
g.Dirents = make([]Dirent64, numDirents)
|
||||
|
||||
@@ -16,6 +16,7 @@ package fsgofer
|
||||
|
||||
import (
|
||||
"io"
|
||||
"math"
|
||||
"path"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
@@ -622,17 +623,16 @@ func (fd *controlFDLisa) StatFS(c *lisafs.Connection) (lisafs.StatFS, error) {
|
||||
}
|
||||
|
||||
// Readlink implements lisafs.ControlFDImpl.Readlink.
|
||||
func (fd *controlFDLisa) Readlink(c *lisafs.Connection, getLinkBuf func(uint32) []byte) (uint32, error) {
|
||||
func (fd *controlFDLisa) Readlink(c *lisafs.Connection, getLinkBuf func(uint32) []byte) (uint16, error) {
|
||||
// This is similar to what os.Readlink does.
|
||||
const limit = uint32(1024 * 1024)
|
||||
for linkLen := uint32(128); linkLen < limit; linkLen *= 2 {
|
||||
b := getLinkBuf(linkLen)
|
||||
for linkLen := 128; linkLen < math.MaxUint16; linkLen *= 2 {
|
||||
b := getLinkBuf(uint32(linkLen))
|
||||
n, err := unix.Readlinkat(fd.hostFD, "", b)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if n < int(linkLen) {
|
||||
return uint32(n), nil
|
||||
return uint16(n), nil
|
||||
}
|
||||
}
|
||||
return 0, unix.ENOMEM
|
||||
@@ -693,7 +693,7 @@ func (fd *controlFDLisa) RenameLocked(c *lisafs.Connection, newDir lisafs.Contro
|
||||
}
|
||||
|
||||
// GetXattr implements lisafs.ControlFDImpl.GetXattr.
|
||||
func (fd *controlFDLisa) GetXattr(c *lisafs.Connection, name string, dataBuf []byte) (uint32, error) {
|
||||
func (fd *controlFDLisa) GetXattr(c *lisafs.Connection, name string, dataBuf []byte) (uint16, error) {
|
||||
if !c.ServerImpl().(*LisafsServer).config.EnableVerityXattr {
|
||||
return 0, unix.EOPNOTSUPP
|
||||
}
|
||||
@@ -701,7 +701,7 @@ func (fd *controlFDLisa) GetXattr(c *lisafs.Connection, name string, dataBuf []b
|
||||
return 0, unix.EOPNOTSUPP
|
||||
}
|
||||
n, err := unix.Fgetxattr(fd.hostFD, name, dataBuf)
|
||||
return uint32(n), err
|
||||
return uint16(n), err
|
||||
}
|
||||
|
||||
// SetXattr implements lisafs.ControlFDImpl.SetXattr.
|
||||
|
||||
Reference in New Issue
Block a user