github.com/ttpreport/gvisor-ligolo@v0.0.0-20240123134145-a858404967ba/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  	"github.com/ttpreport/gvisor-ligolo/pkg/abi/linux"
    19  	"github.com/ttpreport/gvisor-ligolo/pkg/context"
    20  	"github.com/ttpreport/gvisor-ligolo/pkg/log"
    21  	"github.com/ttpreport/gvisor-ligolo/pkg/sentry/socket/unix/transport"
    22  	"github.com/ttpreport/gvisor-ligolo/pkg/syserr"
    23  	"github.com/ttpreport/gvisor-ligolo/pkg/waiter"
    24  	"golang.org/x/sys/unix"
    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  }