summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/socket/control/control.go
diff options
context:
space:
mode:
authorIan Gudger <igudger@google.com>2019-04-29 21:20:05 -0700
committerShentubot <shentubot@google.com>2019-04-29 21:21:08 -0700
commit81ecd8b6eab7457b331762626f8c210fec3504e6 (patch)
tree4c5e5aaf3ac8ff475657c66671dd6828938ae45e /pkg/sentry/socket/control/control.go
parent2843f2a956f5ef23e621f571f5c3e6a1e4a8223a (diff)
Implement the MSG_CTRUNC msghdr flag for Unix sockets.
Updates google/gvisor#206 PiperOrigin-RevId: 245880573 Change-Id: Ifa715e98d47f64b8a32b04ae9378d6cd6bd4025e
Diffstat (limited to 'pkg/sentry/socket/control/control.go')
-rw-r--r--pkg/sentry/socket/control/control.go42
1 files changed, 27 insertions, 15 deletions
diff --git a/pkg/sentry/socket/control/control.go b/pkg/sentry/socket/control/control.go
index abda364c9..c0238691d 100644
--- a/pkg/sentry/socket/control/control.go
+++ b/pkg/sentry/socket/control/control.go
@@ -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.