mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Implement the MSG_CTRUNC msghdr flag for Unix sockets.
Updates google/gvisor#206 PiperOrigin-RevId: 245880573 Change-Id: Ifa715e98d47f64b8a32b04ae9378d6cd6bd4025e
This commit is contained in:
@@ -32,17 +32,20 @@ func newSCMRights(fds []int) control.SCMRights {
|
||||
}
|
||||
|
||||
// Files implements control.SCMRights.Files.
|
||||
func (c *scmRights) Files(ctx context.Context, max int) control.RightsFiles {
|
||||
func (c *scmRights) Files(ctx context.Context, max int) (control.RightsFiles, bool) {
|
||||
n := max
|
||||
var trunc bool
|
||||
if l := len(c.fds); n > l {
|
||||
n = l
|
||||
} else if n < l {
|
||||
trunc = true
|
||||
}
|
||||
|
||||
rf := control.RightsFiles(fdsToFiles(ctx, c.fds[:n]))
|
||||
|
||||
// Only consume converted FDs (fdsToFiles may convert fewer than n FDs).
|
||||
c.fds = c.fds[len(rf):]
|
||||
return rf
|
||||
return rf, trunc
|
||||
}
|
||||
|
||||
// Clone implements transport.RightsControlMessage.Clone.
|
||||
|
||||
@@ -282,11 +282,11 @@ func (c *ConnectedEndpoint) EventUpdate() {
|
||||
}
|
||||
|
||||
// Recv implements transport.Receiver.Recv.
|
||||
func (c *ConnectedEndpoint) Recv(data [][]byte, creds bool, numRights uintptr, peek bool) (uintptr, uintptr, transport.ControlMessages, tcpip.FullAddress, bool, *syserr.Error) {
|
||||
func (c *ConnectedEndpoint) Recv(data [][]byte, creds bool, numRights uintptr, peek bool) (uintptr, uintptr, transport.ControlMessages, bool, tcpip.FullAddress, bool, *syserr.Error) {
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
if c.readClosed {
|
||||
return 0, 0, transport.ControlMessages{}, tcpip.FullAddress{}, false, syserr.ErrClosedForReceive
|
||||
return 0, 0, transport.ControlMessages{}, false, tcpip.FullAddress{}, false, syserr.ErrClosedForReceive
|
||||
}
|
||||
|
||||
var cm unet.ControlMessage
|
||||
@@ -296,7 +296,7 @@ func (c *ConnectedEndpoint) Recv(data [][]byte, creds bool, numRights uintptr, p
|
||||
|
||||
// N.B. Unix sockets don't have a receive buffer, the send buffer
|
||||
// serves both purposes.
|
||||
rl, ml, cl, err := fdReadVec(c.file.FD(), data, []byte(cm), peek, c.sndbuf)
|
||||
rl, ml, cl, cTrunc, err := fdReadVec(c.file.FD(), data, []byte(cm), peek, c.sndbuf)
|
||||
if rl > 0 && err != nil {
|
||||
// We got some data, so all we need to do on error is return
|
||||
// the data that we got. Short reads are fine, no need to
|
||||
@@ -304,7 +304,7 @@ func (c *ConnectedEndpoint) Recv(data [][]byte, creds bool, numRights uintptr, p
|
||||
err = nil
|
||||
}
|
||||
if err != nil {
|
||||
return 0, 0, transport.ControlMessages{}, tcpip.FullAddress{}, false, syserr.FromError(err)
|
||||
return 0, 0, transport.ControlMessages{}, false, tcpip.FullAddress{}, false, syserr.FromError(err)
|
||||
}
|
||||
|
||||
// There is no need for the callee to call RecvNotify because fdReadVec uses
|
||||
@@ -317,18 +317,18 @@ func (c *ConnectedEndpoint) Recv(data [][]byte, creds bool, numRights uintptr, p
|
||||
|
||||
// Avoid extra allocations in the case where there isn't any control data.
|
||||
if len(cm) == 0 {
|
||||
return rl, ml, transport.ControlMessages{}, tcpip.FullAddress{Addr: tcpip.Address(c.path)}, false, nil
|
||||
return rl, ml, transport.ControlMessages{}, cTrunc, tcpip.FullAddress{Addr: tcpip.Address(c.path)}, false, nil
|
||||
}
|
||||
|
||||
fds, err := cm.ExtractFDs()
|
||||
if err != nil {
|
||||
return 0, 0, transport.ControlMessages{}, tcpip.FullAddress{}, false, syserr.FromError(err)
|
||||
return 0, 0, transport.ControlMessages{}, false, tcpip.FullAddress{}, false, syserr.FromError(err)
|
||||
}
|
||||
|
||||
if len(fds) == 0 {
|
||||
return rl, ml, transport.ControlMessages{}, tcpip.FullAddress{Addr: tcpip.Address(c.path)}, false, nil
|
||||
return rl, ml, transport.ControlMessages{}, cTrunc, tcpip.FullAddress{Addr: tcpip.Address(c.path)}, false, nil
|
||||
}
|
||||
return rl, ml, control.New(nil, nil, newSCMRights(fds)), tcpip.FullAddress{Addr: tcpip.Address(c.path)}, false, nil
|
||||
return rl, ml, control.New(nil, nil, newSCMRights(fds)), cTrunc, tcpip.FullAddress{Addr: tcpip.Address(c.path)}, false, nil
|
||||
}
|
||||
|
||||
// close releases all resources related to the endpoint.
|
||||
|
||||
@@ -207,7 +207,7 @@ func TestSend(t *testing.T) {
|
||||
|
||||
func TestRecv(t *testing.T) {
|
||||
e := ConnectedEndpoint{readClosed: true}
|
||||
if _, _, _, _, _, err := e.Recv(nil, false, 0, false); err != syserr.ErrClosedForReceive {
|
||||
if _, _, _, _, _, _, err := e.Recv(nil, false, 0, false); err != syserr.ErrClosedForReceive {
|
||||
t.Errorf("Got %#v.Recv() = %v, want = %v", e, err, syserr.ErrClosedForReceive)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
//
|
||||
// If the total length of bufs is > maxlen, fdReadVec will do a partial read
|
||||
// and err will indicate why the message was truncated.
|
||||
func fdReadVec(fd int, bufs [][]byte, control []byte, peek bool, maxlen int) (readLen uintptr, msgLen uintptr, controlLen uint64, err error) {
|
||||
func fdReadVec(fd int, bufs [][]byte, control []byte, peek bool, maxlen int) (readLen uintptr, msgLen uintptr, controlLen uint64, controlTrunc bool, err error) {
|
||||
flags := uintptr(syscall.MSG_DONTWAIT | syscall.MSG_TRUNC)
|
||||
if peek {
|
||||
flags |= syscall.MSG_PEEK
|
||||
@@ -34,7 +34,7 @@ func fdReadVec(fd int, bufs [][]byte, control []byte, peek bool, maxlen int) (re
|
||||
length, iovecs, intermediate, err := buildIovec(bufs, maxlen, true)
|
||||
if err != nil && len(iovecs) == 0 {
|
||||
// No partial write to do, return error immediately.
|
||||
return 0, 0, 0, err
|
||||
return 0, 0, 0, false, err
|
||||
}
|
||||
|
||||
var msg syscall.Msghdr
|
||||
@@ -51,7 +51,7 @@ func fdReadVec(fd int, bufs [][]byte, control []byte, peek bool, maxlen int) (re
|
||||
n, _, e := syscall.RawSyscall(syscall.SYS_RECVMSG, uintptr(fd), uintptr(unsafe.Pointer(&msg)), flags)
|
||||
if e != 0 {
|
||||
// N.B. prioritize the syscall error over the buildIovec error.
|
||||
return 0, 0, 0, e
|
||||
return 0, 0, 0, false, e
|
||||
}
|
||||
|
||||
// Copy data back to bufs.
|
||||
@@ -59,11 +59,13 @@ func fdReadVec(fd int, bufs [][]byte, control []byte, peek bool, maxlen int) (re
|
||||
copyToMulti(bufs, intermediate)
|
||||
}
|
||||
|
||||
controlTrunc = msg.Flags&syscall.MSG_CTRUNC == syscall.MSG_CTRUNC
|
||||
|
||||
if n > length {
|
||||
return length, n, msg.Controllen, err
|
||||
return length, n, msg.Controllen, controlTrunc, err
|
||||
}
|
||||
|
||||
return n, n, msg.Controllen, err
|
||||
return n, n, msg.Controllen, controlTrunc, err
|
||||
}
|
||||
|
||||
// fdWriteVec sends from bufs to fd.
|
||||
|
||||
@@ -45,7 +45,10 @@ type SCMRights interface {
|
||||
transport.RightsControlMessage
|
||||
|
||||
// Files returns up to max RightsFiles.
|
||||
Files(ctx context.Context, max int) RightsFiles
|
||||
//
|
||||
// Returned files are consumed and ownership is transferred to the caller.
|
||||
// Subsequent calls to Files will return the next files.
|
||||
Files(ctx context.Context, max int) (rf RightsFiles, truncated bool)
|
||||
}
|
||||
|
||||
// RightsFiles represents a SCM_RIGHTS socket control message. A reference is
|
||||
@@ -71,14 +74,17 @@ func NewSCMRights(t *kernel.Task, fds []int32) (SCMRights, error) {
|
||||
}
|
||||
|
||||
// Files implements SCMRights.Files.
|
||||
func (fs *RightsFiles) Files(ctx context.Context, max int) RightsFiles {
|
||||
func (fs *RightsFiles) Files(ctx context.Context, max int) (RightsFiles, bool) {
|
||||
n := max
|
||||
var trunc bool
|
||||
if l := len(*fs); n > l {
|
||||
n = l
|
||||
} else if n < l {
|
||||
trunc = true
|
||||
}
|
||||
rf := (*fs)[:n]
|
||||
*fs = (*fs)[n:]
|
||||
return rf
|
||||
return rf, trunc
|
||||
}
|
||||
|
||||
// Clone implements transport.RightsControlMessage.Clone.
|
||||
@@ -99,8 +105,8 @@ func (fs *RightsFiles) Release() {
|
||||
}
|
||||
|
||||
// rightsFDs gets up to the specified maximum number of FDs.
|
||||
func rightsFDs(t *kernel.Task, rights SCMRights, cloexec bool, max int) []int32 {
|
||||
files := rights.Files(t, max)
|
||||
func rightsFDs(t *kernel.Task, rights SCMRights, cloexec bool, max int) ([]int32, bool) {
|
||||
files, trunc := rights.Files(t, max)
|
||||
fds := make([]int32, 0, len(files))
|
||||
for i := 0; i < max && len(files) > 0; i++ {
|
||||
fd, err := t.FDMap().NewFDFrom(0, files[0], kernel.FDFlags{cloexec}, t.ThreadGroup().Limits())
|
||||
@@ -114,19 +120,23 @@ func rightsFDs(t *kernel.Task, rights SCMRights, cloexec bool, max int) []int32
|
||||
|
||||
fds = append(fds, int32(fd))
|
||||
}
|
||||
return fds
|
||||
return fds, trunc
|
||||
}
|
||||
|
||||
// PackRights packs as many FDs as will fit into the unused capacity of buf.
|
||||
func PackRights(t *kernel.Task, rights SCMRights, cloexec bool, buf []byte) []byte {
|
||||
func PackRights(t *kernel.Task, rights SCMRights, cloexec bool, buf []byte, flags int) ([]byte, int) {
|
||||
maxFDs := (cap(buf) - len(buf) - linux.SizeOfControlMessageHeader) / 4
|
||||
// Linux does not return any FDs if none fit.
|
||||
if maxFDs <= 0 {
|
||||
return buf
|
||||
flags |= linux.MSG_CTRUNC
|
||||
return buf, flags
|
||||
}
|
||||
fds, trunc := rightsFDs(t, rights, cloexec, maxFDs)
|
||||
if trunc {
|
||||
flags |= linux.MSG_CTRUNC
|
||||
}
|
||||
fds := rightsFDs(t, rights, cloexec, maxFDs)
|
||||
align := t.Arch().Width()
|
||||
return putCmsg(buf, linux.SCM_RIGHTS, align, fds)
|
||||
return putCmsg(buf, flags, linux.SCM_RIGHTS, align, fds)
|
||||
}
|
||||
|
||||
// scmCredentials represents an SCM_CREDENTIALS socket control message.
|
||||
@@ -176,7 +186,7 @@ func putUint32(buf []byte, n uint32) []byte {
|
||||
|
||||
// putCmsg writes a control message header and as much data as will fit into
|
||||
// the unused capacity of a buffer.
|
||||
func putCmsg(buf []byte, msgType uint32, align uint, data []int32) []byte {
|
||||
func putCmsg(buf []byte, flags int, msgType uint32, align uint, data []int32) ([]byte, int) {
|
||||
space := AlignDown(cap(buf)-len(buf), 4)
|
||||
|
||||
// We can't write to space that doesn't exist, so if we are going to align
|
||||
@@ -193,7 +203,8 @@ func putCmsg(buf []byte, msgType uint32, align uint, data []int32) []byte {
|
||||
// a partial int32, so the length of the message will be
|
||||
// min(aligned length, header + datas).
|
||||
if space < linux.SizeOfControlMessageHeader {
|
||||
return buf
|
||||
flags |= linux.MSG_CTRUNC
|
||||
return buf, flags
|
||||
}
|
||||
|
||||
length := 4*len(data) + linux.SizeOfControlMessageHeader
|
||||
@@ -205,11 +216,12 @@ func putCmsg(buf []byte, msgType uint32, align uint, data []int32) []byte {
|
||||
buf = putUint32(buf, msgType)
|
||||
for _, d := range data {
|
||||
if len(buf)+4 > cap(buf) {
|
||||
flags |= linux.MSG_CTRUNC
|
||||
break
|
||||
}
|
||||
buf = putUint32(buf, uint32(d))
|
||||
}
|
||||
return alignSlice(buf, align)
|
||||
return alignSlice(buf, align), flags
|
||||
}
|
||||
|
||||
func putCmsgStruct(buf []byte, msgType uint32, align uint, data interface{}) []byte {
|
||||
@@ -253,7 +265,7 @@ func (c *scmCredentials) Credentials(t *kernel.Task) (kernel.ThreadID, auth.UID,
|
||||
|
||||
// PackCredentials packs the credentials in the control message (or default
|
||||
// credentials if none) into a buffer.
|
||||
func PackCredentials(t *kernel.Task, creds SCMCredentials, buf []byte) []byte {
|
||||
func PackCredentials(t *kernel.Task, creds SCMCredentials, buf []byte, flags int) ([]byte, int) {
|
||||
align := t.Arch().Width()
|
||||
|
||||
// Default credentials if none are available.
|
||||
@@ -265,7 +277,7 @@ func PackCredentials(t *kernel.Task, creds SCMCredentials, buf []byte) []byte {
|
||||
pid, uid, gid = creds.Credentials(t)
|
||||
}
|
||||
c := []int32{int32(pid), int32(uid), int32(gid)}
|
||||
return putCmsg(buf, linux.SCM_CREDENTIALS, align, c)
|
||||
return putCmsg(buf, flags, linux.SCM_CREDENTIALS, align, c)
|
||||
}
|
||||
|
||||
// AlignUp rounds a length up to an alignment. align must be a power of 2.
|
||||
|
||||
@@ -87,6 +87,11 @@ type Socket interface {
|
||||
// senderAddrLen is the address length to be returned to the application,
|
||||
// not necessarily the actual length of the address.
|
||||
//
|
||||
// flags control how RecvMsg should be completed. msgFlags indicate how
|
||||
// the RecvMsg call was completed. Note that control message truncation
|
||||
// may still be required even if the MSG_CTRUNC bit is not set in
|
||||
// msgFlags. In that case, the caller should set MSG_CTRUNC appropriately.
|
||||
//
|
||||
// If err != nil, the recv was not successful.
|
||||
RecvMsg(t *kernel.Task, dst usermem.IOSequence, flags int, haveDeadline bool, deadline ktime.Time, senderRequested bool, controlDataLen uint64) (n int, msgFlags int, senderAddr interface{}, senderAddrLen uint32, controlMessages ControlMessages, err *syserr.Error)
|
||||
|
||||
|
||||
@@ -72,13 +72,18 @@ type EndpointReader struct {
|
||||
|
||||
// Control contains the received control messages.
|
||||
Control transport.ControlMessages
|
||||
|
||||
// ControlTrunc indicates that SCM_RIGHTS FDs were discarded based on
|
||||
// the value of NumRights.
|
||||
ControlTrunc bool
|
||||
}
|
||||
|
||||
// ReadToBlocks implements safemem.Reader.ReadToBlocks.
|
||||
func (r *EndpointReader) ReadToBlocks(dsts safemem.BlockSeq) (uint64, error) {
|
||||
return safemem.FromVecReaderFunc{func(bufs [][]byte) (int64, error) {
|
||||
n, ms, c, err := r.Endpoint.RecvMsg(bufs, r.Creds, r.NumRights, r.Peek, r.From)
|
||||
n, ms, c, ct, err := r.Endpoint.RecvMsg(bufs, r.Creds, r.NumRights, r.Peek, r.From)
|
||||
r.Control = c
|
||||
r.ControlTrunc = ct
|
||||
r.MsgSize = ms
|
||||
if err != nil {
|
||||
return int64(n), err.ToError()
|
||||
|
||||
@@ -130,7 +130,11 @@ type Endpoint interface {
|
||||
//
|
||||
// msgLen is the length of the read message consumed for datagram Endpoints.
|
||||
// msgLen is always the same as recvLen for stream Endpoints.
|
||||
RecvMsg(data [][]byte, creds bool, numRights uintptr, peek bool, addr *tcpip.FullAddress) (recvLen, msgLen uintptr, cm ControlMessages, err *syserr.Error)
|
||||
//
|
||||
// CMTruncated indicates that the numRights hint was used to receive fewer
|
||||
// than the total available SCM_RIGHTS FDs. Additional truncation may be
|
||||
// required by the caller.
|
||||
RecvMsg(data [][]byte, creds bool, numRights uintptr, peek bool, addr *tcpip.FullAddress) (recvLen, msgLen uintptr, cm ControlMessages, CMTruncated bool, err *syserr.Error)
|
||||
|
||||
// SendMsg writes data and a control message to the endpoint's peer.
|
||||
// This method does not block if the data cannot be written.
|
||||
@@ -288,7 +292,7 @@ type Receiver interface {
|
||||
// See Endpoint.RecvMsg for documentation on shared arguments.
|
||||
//
|
||||
// notify indicates if RecvNotify should be called.
|
||||
Recv(data [][]byte, creds bool, numRights uintptr, peek bool) (recvLen, msgLen uintptr, cm ControlMessages, source tcpip.FullAddress, notify bool, err *syserr.Error)
|
||||
Recv(data [][]byte, creds bool, numRights uintptr, peek bool) (recvLen, msgLen uintptr, cm ControlMessages, CMTruncated bool, source tcpip.FullAddress, notify bool, err *syserr.Error)
|
||||
|
||||
// RecvNotify notifies the Receiver of a successful Recv. This must not be
|
||||
// called while holding any endpoint locks.
|
||||
@@ -328,7 +332,7 @@ type queueReceiver struct {
|
||||
}
|
||||
|
||||
// Recv implements Receiver.Recv.
|
||||
func (q *queueReceiver) Recv(data [][]byte, creds bool, numRights uintptr, peek bool) (uintptr, uintptr, ControlMessages, tcpip.FullAddress, bool, *syserr.Error) {
|
||||
func (q *queueReceiver) Recv(data [][]byte, creds bool, numRights uintptr, peek bool) (uintptr, uintptr, ControlMessages, bool, tcpip.FullAddress, bool, *syserr.Error) {
|
||||
var m *message
|
||||
var notify bool
|
||||
var err *syserr.Error
|
||||
@@ -338,7 +342,7 @@ func (q *queueReceiver) Recv(data [][]byte, creds bool, numRights uintptr, peek
|
||||
m, notify, err = q.readQueue.Dequeue()
|
||||
}
|
||||
if err != nil {
|
||||
return 0, 0, ControlMessages{}, tcpip.FullAddress{}, false, err
|
||||
return 0, 0, ControlMessages{}, false, tcpip.FullAddress{}, false, err
|
||||
}
|
||||
src := []byte(m.Data)
|
||||
var copied uintptr
|
||||
@@ -347,7 +351,7 @@ func (q *queueReceiver) Recv(data [][]byte, creds bool, numRights uintptr, peek
|
||||
copied += uintptr(n)
|
||||
src = src[n:]
|
||||
}
|
||||
return copied, uintptr(len(m.Data)), m.Control, m.Address, notify, nil
|
||||
return copied, uintptr(len(m.Data)), m.Control, false, m.Address, notify, nil
|
||||
}
|
||||
|
||||
// RecvNotify implements Receiver.RecvNotify.
|
||||
@@ -440,7 +444,7 @@ func (q *streamQueueReceiver) RecvMaxQueueSize() int64 {
|
||||
}
|
||||
|
||||
// Recv implements Receiver.Recv.
|
||||
func (q *streamQueueReceiver) Recv(data [][]byte, wantCreds bool, numRights uintptr, peek bool) (uintptr, uintptr, ControlMessages, tcpip.FullAddress, bool, *syserr.Error) {
|
||||
func (q *streamQueueReceiver) Recv(data [][]byte, wantCreds bool, numRights uintptr, peek bool) (uintptr, uintptr, ControlMessages, bool, tcpip.FullAddress, bool, *syserr.Error) {
|
||||
q.mu.Lock()
|
||||
defer q.mu.Unlock()
|
||||
|
||||
@@ -453,7 +457,7 @@ func (q *streamQueueReceiver) Recv(data [][]byte, wantCreds bool, numRights uint
|
||||
// the next time Recv() is called.
|
||||
m, n, err := q.readQueue.Dequeue()
|
||||
if err != nil {
|
||||
return 0, 0, ControlMessages{}, tcpip.FullAddress{}, false, err
|
||||
return 0, 0, ControlMessages{}, false, tcpip.FullAddress{}, false, err
|
||||
}
|
||||
notify = n
|
||||
q.buffer = []byte(m.Data)
|
||||
@@ -469,7 +473,7 @@ func (q *streamQueueReceiver) Recv(data [][]byte, wantCreds bool, numRights uint
|
||||
// Don't consume data since we are peeking.
|
||||
copied, data, _ = vecCopy(data, q.buffer)
|
||||
|
||||
return copied, copied, c, q.addr, notify, nil
|
||||
return copied, copied, c, false, q.addr, notify, nil
|
||||
}
|
||||
|
||||
// Consume data and control message since we are not peeking.
|
||||
@@ -484,9 +488,11 @@ func (q *streamQueueReceiver) Recv(data [][]byte, wantCreds bool, numRights uint
|
||||
c.Credentials = nil
|
||||
}
|
||||
|
||||
var cmTruncated bool
|
||||
if c.Rights != nil && numRights == 0 {
|
||||
c.Rights.Release()
|
||||
c.Rights = nil
|
||||
cmTruncated = true
|
||||
}
|
||||
|
||||
haveRights := c.Rights != nil
|
||||
@@ -538,6 +544,7 @@ func (q *streamQueueReceiver) Recv(data [][]byte, wantCreds bool, numRights uint
|
||||
if q.control.Rights != nil {
|
||||
// Consume rights.
|
||||
if numRights == 0 {
|
||||
cmTruncated = true
|
||||
q.control.Rights.Release()
|
||||
} else {
|
||||
c.Rights = q.control.Rights
|
||||
@@ -546,7 +553,7 @@ func (q *streamQueueReceiver) Recv(data [][]byte, wantCreds bool, numRights uint
|
||||
q.control.Rights = nil
|
||||
}
|
||||
}
|
||||
return copied, copied, c, q.addr, notify, nil
|
||||
return copied, copied, c, cmTruncated, q.addr, notify, nil
|
||||
}
|
||||
|
||||
// A ConnectedEndpoint is an Endpoint that can be used to send Messages.
|
||||
@@ -775,18 +782,18 @@ func (e *baseEndpoint) Connected() bool {
|
||||
}
|
||||
|
||||
// RecvMsg reads data and a control message from the endpoint.
|
||||
func (e *baseEndpoint) RecvMsg(data [][]byte, creds bool, numRights uintptr, peek bool, addr *tcpip.FullAddress) (uintptr, uintptr, ControlMessages, *syserr.Error) {
|
||||
func (e *baseEndpoint) RecvMsg(data [][]byte, creds bool, numRights uintptr, peek bool, addr *tcpip.FullAddress) (uintptr, uintptr, ControlMessages, bool, *syserr.Error) {
|
||||
e.Lock()
|
||||
|
||||
if e.receiver == nil {
|
||||
e.Unlock()
|
||||
return 0, 0, ControlMessages{}, syserr.ErrNotConnected
|
||||
return 0, 0, ControlMessages{}, false, syserr.ErrNotConnected
|
||||
}
|
||||
|
||||
recvLen, msgLen, cms, a, notify, err := e.receiver.Recv(data, creds, numRights, peek)
|
||||
recvLen, msgLen, cms, cmt, a, notify, err := e.receiver.Recv(data, creds, numRights, peek)
|
||||
e.Unlock()
|
||||
if err != nil {
|
||||
return 0, 0, ControlMessages{}, err
|
||||
return 0, 0, ControlMessages{}, false, err
|
||||
}
|
||||
|
||||
if notify {
|
||||
@@ -796,7 +803,7 @@ func (e *baseEndpoint) RecvMsg(data [][]byte, creds bool, numRights uintptr, pee
|
||||
if addr != nil {
|
||||
*addr = a
|
||||
}
|
||||
return recvLen, msgLen, cms, nil
|
||||
return recvLen, msgLen, cms, cmt, nil
|
||||
}
|
||||
|
||||
// SendMsg writes data and a control message to the endpoint's peer.
|
||||
|
||||
@@ -490,6 +490,9 @@ func (s *SocketOperations) RecvMsg(t *kernel.Task, dst usermem.IOSequence, flags
|
||||
if s.Passcred() {
|
||||
// Credentials take priority if they are enabled and there is space.
|
||||
wantCreds = rightsLen > 0
|
||||
if !wantCreds {
|
||||
msgFlags |= linux.MSG_CTRUNC
|
||||
}
|
||||
credLen := syscall.CmsgSpace(syscall.SizeofUcred)
|
||||
rightsLen -= credLen
|
||||
}
|
||||
@@ -516,6 +519,10 @@ func (s *SocketOperations) RecvMsg(t *kernel.Task, dst usermem.IOSequence, flags
|
||||
from, fromLen = epsocket.ConvertAddress(linux.AF_UNIX, *r.From)
|
||||
}
|
||||
|
||||
if r.ControlTrunc {
|
||||
msgFlags |= linux.MSG_CTRUNC
|
||||
}
|
||||
|
||||
if err != nil || dontWait || !waitAll || s.isPacket || n >= dst.NumBytes() {
|
||||
if s.isPacket && n < int64(r.MsgSize) {
|
||||
msgFlags |= linux.MSG_TRUNC
|
||||
@@ -546,12 +553,18 @@ func (s *SocketOperations) RecvMsg(t *kernel.Task, dst usermem.IOSequence, flags
|
||||
if r.From != nil {
|
||||
from, fromLen = epsocket.ConvertAddress(linux.AF_UNIX, *r.From)
|
||||
}
|
||||
|
||||
if r.ControlTrunc {
|
||||
msgFlags |= linux.MSG_CTRUNC
|
||||
}
|
||||
|
||||
if trunc {
|
||||
// n and r.MsgSize are the same for streams.
|
||||
total += int64(r.MsgSize)
|
||||
} else {
|
||||
total += n
|
||||
}
|
||||
|
||||
if err != nil || !waitAll || s.isPacket || n >= dst.NumBytes() {
|
||||
if total > 0 {
|
||||
err = nil
|
||||
|
||||
@@ -746,7 +746,10 @@ func recvSingleMsg(t *kernel.Task, s socket.Socket, msgPtr usermem.Addr, flags i
|
||||
if err != nil {
|
||||
return 0, syserror.ConvertIntr(err.ToError(), kernel.ERESTARTSYS)
|
||||
}
|
||||
cms.Unix.Release()
|
||||
if !cms.Unix.Empty() {
|
||||
mflags |= linux.MSG_CTRUNC
|
||||
cms.Unix.Release()
|
||||
}
|
||||
|
||||
if int(msg.Flags) != mflags {
|
||||
// Copy out the flags to the caller.
|
||||
@@ -771,7 +774,7 @@ func recvSingleMsg(t *kernel.Task, s socket.Socket, msgPtr usermem.Addr, flags i
|
||||
|
||||
if cr, ok := s.(transport.Credentialer); ok && cr.Passcred() {
|
||||
creds, _ := cms.Unix.Credentials.(control.SCMCredentials)
|
||||
controlData = control.PackCredentials(t, creds, controlData)
|
||||
controlData, mflags = control.PackCredentials(t, creds, controlData, mflags)
|
||||
}
|
||||
|
||||
if cms.IP.HasTimestamp {
|
||||
@@ -779,7 +782,7 @@ func recvSingleMsg(t *kernel.Task, s socket.Socket, msgPtr usermem.Addr, flags i
|
||||
}
|
||||
|
||||
if cms.Unix.Rights != nil {
|
||||
controlData = control.PackRights(t, cms.Unix.Rights.(control.SCMRights), flags&linux.MSG_CMSG_CLOEXEC != 0, controlData)
|
||||
controlData, mflags = control.PackRights(t, cms.Unix.Rights.(control.SCMRights), flags&linux.MSG_CMSG_CLOEXEC != 0, controlData, mflags)
|
||||
}
|
||||
|
||||
// Copy the address to the caller.
|
||||
|
||||
@@ -186,9 +186,6 @@ TEST_P(UnixSocketPairTest, BasicFDPassNoSpace) {
|
||||
// BasicFDPassNoSpaceMsgCtrunc sends an FD, but does not provide any space to
|
||||
// receive it. It then verifies that the MSG_CTRUNC flag is set in the msghdr.
|
||||
TEST_P(UnixSocketPairTest, BasicFDPassNoSpaceMsgCtrunc) {
|
||||
// FIXME(gvisor.dev/issue/206): Support MSG_CTRUNC.
|
||||
SKIP_IF(IsRunningOnGvisor());
|
||||
|
||||
auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
|
||||
|
||||
char sent_data[20];
|
||||
@@ -259,9 +256,6 @@ TEST_P(UnixSocketPairTest, BasicFDPassNullControlMsgCtrunc) {
|
||||
// space to receive it. It then verifies that the MSG_CTRUNC flag is set in the
|
||||
// msghdr.
|
||||
TEST_P(UnixSocketPairTest, BasicFDPassNotEnoughSpaceMsgCtrunc) {
|
||||
// FIXME(gvisor.dev/issue/206): Support MSG_CTRUNC.
|
||||
SKIP_IF(IsRunningOnGvisor());
|
||||
|
||||
auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
|
||||
|
||||
char sent_data[20];
|
||||
@@ -296,9 +290,6 @@ TEST_P(UnixSocketPairTest, BasicFDPassNotEnoughSpaceMsgCtrunc) {
|
||||
// space to receive two of them. It then verifies that the MSG_CTRUNC flag is
|
||||
// set in the msghdr.
|
||||
TEST_P(UnixSocketPairTest, BasicThreeFDPassTruncationMsgCtrunc) {
|
||||
// FIXME(gvisor.dev/issue/206): Support MSG_CTRUNC.
|
||||
SKIP_IF(IsRunningOnGvisor());
|
||||
|
||||
auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
|
||||
|
||||
char sent_data[20];
|
||||
@@ -408,9 +399,6 @@ TEST_P(UnixSocketPairTest, BasicFDPassUnalignedRecvNoMsgTrunc) {
|
||||
// provides enough space to receive one of them. It then verifies that the
|
||||
// MSG_CTRUNC flag is set in the msghdr.
|
||||
TEST_P(UnixSocketPairTest, BasicTwoFDPassUnalignedRecvTruncationMsgTrunc) {
|
||||
// FIXME(gvisor.dev/issue/206): Support MSG_CTRUNC.
|
||||
SKIP_IF(IsRunningOnGvisor());
|
||||
|
||||
auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
|
||||
|
||||
char sent_data[20];
|
||||
@@ -1010,9 +998,6 @@ TEST_P(UnixSocketPairTest, CredPassNoMsgCtrunc) {
|
||||
// the data without providing space for any credentials and verifies that
|
||||
// MSG_CTRUNC is set in the msghdr.
|
||||
TEST_P(UnixSocketPairTest, CredPassNoSpaceMsgCtrunc) {
|
||||
// FIXME(gvisor.dev/issue/206): Support MSG_CTRUNC.
|
||||
SKIP_IF(IsRunningOnGvisor());
|
||||
|
||||
auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
|
||||
|
||||
char sent_data[20];
|
||||
@@ -1061,9 +1046,6 @@ TEST_P(UnixSocketPairTest, CredPassNoSpaceMsgCtrunc) {
|
||||
// the data while providing enough space for only the first field of the
|
||||
// credentials and verifies that MSG_CTRUNC is set in the msghdr.
|
||||
TEST_P(UnixSocketPairTest, CredPassTruncatedMsgCtrunc) {
|
||||
// FIXME(gvisor.dev/issue/206): Support MSG_CTRUNC.
|
||||
SKIP_IF(IsRunningOnGvisor());
|
||||
|
||||
auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
|
||||
|
||||
char sent_data[20];
|
||||
|
||||
Reference in New Issue
Block a user