github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/sentry/fsimpl/gofer/socket.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 gofer 16 17 import ( 18 "golang.org/x/sys/unix" 19 "github.com/nicocha30/gvisor-ligolo/pkg/abi/linux" 20 "github.com/nicocha30/gvisor-ligolo/pkg/context" 21 "github.com/nicocha30/gvisor-ligolo/pkg/log" 22 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/socket/unix/transport" 23 "github.com/nicocha30/gvisor-ligolo/pkg/syserr" 24 "github.com/nicocha30/gvisor-ligolo/pkg/waiter" 25 ) 26 27 func (d *dentry) isSocket() bool { 28 return d.fileType() == linux.S_IFSOCK 29 } 30 31 func isSocketTypeSupported(sockType linux.SockType) bool { 32 switch sockType { 33 case unix.SOCK_STREAM, unix.SOCK_DGRAM, unix.SOCK_SEQPACKET: 34 return true 35 default: 36 return false 37 } 38 } 39 40 // endpoint is a Gofer-backed transport.BoundEndpoint. 41 // 42 // An endpoint's lifetime is the time between when filesystem.BoundEndpointAt() 43 // is called and either BoundEndpoint.BidirectionalConnect or 44 // BoundEndpoint.UnidirectionalConnect is called. 45 // 46 // +stateify savable 47 type endpoint struct { 48 // dentry is the filesystem dentry which produced this endpoint. dentry is 49 // not synthetic. 50 dentry *dentry 51 52 // path is the sentry path where this endpoint is bound. 53 path string 54 } 55 56 // BidirectionalConnect implements BoundEndpoint.BidirectionalConnect. 57 func (e *endpoint) BidirectionalConnect(ctx context.Context, ce transport.ConnectingEndpoint, returnConnect func(transport.Receiver, transport.ConnectedEndpoint)) *syserr.Error { 58 // No lock ordering required as only the ConnectingEndpoint has a mutex. 59 ce.Lock() 60 61 // Check connecting state. 62 if ce.Connected() { 63 ce.Unlock() 64 return syserr.ErrAlreadyConnected 65 } 66 if ce.ListeningLocked() { 67 ce.Unlock() 68 return syserr.ErrInvalidEndpointState 69 } 70 71 c, err := e.newConnectedEndpoint(ctx, ce.Type(), ce.WaiterQueue()) 72 if err != nil { 73 ce.Unlock() 74 return err 75 } 76 77 returnConnect(c, c) 78 ce.Unlock() 79 if err := c.Init(); err != nil { 80 return syserr.FromError(err) 81 } 82 83 return nil 84 } 85 86 // UnidirectionalConnect implements 87 // transport.BoundEndpoint.UnidirectionalConnect. 88 func (e *endpoint) UnidirectionalConnect(ctx context.Context) (transport.ConnectedEndpoint, *syserr.Error) { 89 c, err := e.newConnectedEndpoint(ctx, linux.SOCK_DGRAM, &waiter.Queue{}) 90 if err != nil { 91 return nil, err 92 } 93 94 if err := c.Init(); err != nil { 95 return nil, syserr.FromError(err) 96 } 97 98 // We don't need the receiver. 99 c.CloseRecv() 100 c.Release(ctx) 101 102 return c, nil 103 } 104 105 func (e *endpoint) newConnectedEndpoint(ctx context.Context, sockType linux.SockType, queue *waiter.Queue) (*transport.SCMConnectedEndpoint, *syserr.Error) { 106 e.dentry.fs.renameMu.RLock() 107 hostSockFD, err := e.dentry.connect(ctx, sockType) 108 e.dentry.fs.renameMu.RUnlock() 109 if err != nil { 110 return nil, syserr.ErrConnectionRefused 111 } 112 113 c, serr := transport.NewSCMEndpoint(hostSockFD, queue, e.path) 114 if serr != nil { 115 unix.Close(hostSockFD) 116 log.Warningf("NewSCMEndpoint failed: path=%q, err=%v", e.path, serr) 117 return nil, serr 118 } 119 return c, nil 120 } 121 122 // Release implements transport.BoundEndpoint.Release. 123 func (e *endpoint) Release(ctx context.Context) { 124 e.dentry.DecRef(ctx) 125 } 126 127 // Passcred implements transport.BoundEndpoint.Passcred. 128 func (e *endpoint) Passcred() bool { 129 return false 130 }