github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/socket/control/control_vfs2.go (about) 1 // Copyright 2020 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package control 16 17 import ( 18 "github.com/SagerNet/gvisor/pkg/abi/linux" 19 "github.com/SagerNet/gvisor/pkg/context" 20 "github.com/SagerNet/gvisor/pkg/errors/linuxerr" 21 "github.com/SagerNet/gvisor/pkg/sentry/kernel" 22 "github.com/SagerNet/gvisor/pkg/sentry/socket/unix/transport" 23 "github.com/SagerNet/gvisor/pkg/sentry/vfs" 24 ) 25 26 // SCMRightsVFS2 represents a SCM_RIGHTS socket control message. 27 // 28 // +stateify savable 29 type SCMRightsVFS2 interface { 30 transport.RightsControlMessage 31 32 // Files returns up to max RightsFiles. 33 // 34 // Returned files are consumed and ownership is transferred to the caller. 35 // Subsequent calls to Files will return the next files. 36 Files(ctx context.Context, max int) (rf RightsFilesVFS2, truncated bool) 37 } 38 39 // RightsFilesVFS2 represents a SCM_RIGHTS socket control message. A reference 40 // is maintained for each vfs.FileDescription and is release either when an FD 41 // is created or when the Release method is called. 42 // 43 // +stateify savable 44 type RightsFilesVFS2 []*vfs.FileDescription 45 46 // NewSCMRightsVFS2 creates a new SCM_RIGHTS socket control message 47 // representation using local sentry FDs. 48 func NewSCMRightsVFS2(t *kernel.Task, fds []int32) (SCMRightsVFS2, error) { 49 files := make(RightsFilesVFS2, 0, len(fds)) 50 for _, fd := range fds { 51 file := t.GetFileVFS2(fd) 52 if file == nil { 53 files.Release(t) 54 return nil, linuxerr.EBADF 55 } 56 files = append(files, file) 57 } 58 return &files, nil 59 } 60 61 // Files implements SCMRights.Files. 62 func (fs *RightsFilesVFS2) Files(ctx context.Context, max int) (RightsFilesVFS2, bool) { 63 n := max 64 var trunc bool 65 if l := len(*fs); n > l { 66 n = l 67 } else if n < l { 68 trunc = true 69 } 70 rf := (*fs)[:n] 71 *fs = (*fs)[n:] 72 return rf, trunc 73 } 74 75 // Clone implements transport.RightsControlMessage.Clone. 76 func (fs *RightsFilesVFS2) Clone() transport.RightsControlMessage { 77 nfs := append(RightsFilesVFS2(nil), *fs...) 78 for _, nf := range nfs { 79 nf.IncRef() 80 } 81 return &nfs 82 } 83 84 // Release implements transport.RightsControlMessage.Release. 85 func (fs *RightsFilesVFS2) Release(ctx context.Context) { 86 for _, f := range *fs { 87 f.DecRef(ctx) 88 } 89 *fs = nil 90 } 91 92 // rightsFDsVFS2 gets up to the specified maximum number of FDs. 93 func rightsFDsVFS2(t *kernel.Task, rights SCMRightsVFS2, cloexec bool, max int) ([]int32, bool) { 94 files, trunc := rights.Files(t, max) 95 fds := make([]int32, 0, len(files)) 96 for i := 0; i < max && len(files) > 0; i++ { 97 fd, err := t.NewFDFromVFS2(0, files[0], kernel.FDFlags{ 98 CloseOnExec: cloexec, 99 }) 100 files[0].DecRef(t) 101 files = files[1:] 102 if err != nil { 103 t.Warningf("Error inserting FD: %v", err) 104 // This is what Linux does. 105 break 106 } 107 108 fds = append(fds, int32(fd)) 109 } 110 return fds, trunc 111 } 112 113 // PackRightsVFS2 packs as many FDs as will fit into the unused capacity of buf. 114 func PackRightsVFS2(t *kernel.Task, rights SCMRightsVFS2, cloexec bool, buf []byte, flags int) ([]byte, int) { 115 maxFDs := (cap(buf) - len(buf) - linux.SizeOfControlMessageHeader) / 4 116 // Linux does not return any FDs if none fit. 117 if maxFDs <= 0 { 118 flags |= linux.MSG_CTRUNC 119 return buf, flags 120 } 121 fds, trunc := rightsFDsVFS2(t, rights, cloexec, maxFDs) 122 if trunc { 123 flags |= linux.MSG_CTRUNC 124 } 125 align := t.Arch().Width() 126 return putCmsg(buf, flags, linux.SCM_RIGHTS, align, fds) 127 } 128 129 // NewVFS2 creates default control messages if needed. 130 func NewVFS2(t *kernel.Task, socketOrEndpoint interface{}, rights SCMRightsVFS2) transport.ControlMessages { 131 return transport.ControlMessages{ 132 Credentials: makeCreds(t, socketOrEndpoint), 133 Rights: rights, 134 } 135 }