github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/sentry/socket/netstack/provider.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 netstack
    16  
    17  import (
    18  	"time"
    19  
    20  	"golang.org/x/sys/unix"
    21  	"github.com/nicocha30/gvisor-ligolo/pkg/abi/linux"
    22  	"github.com/nicocha30/gvisor-ligolo/pkg/context"
    23  	"github.com/nicocha30/gvisor-ligolo/pkg/log"
    24  	"github.com/nicocha30/gvisor-ligolo/pkg/sentry/kernel"
    25  	"github.com/nicocha30/gvisor-ligolo/pkg/sentry/kernel/auth"
    26  	"github.com/nicocha30/gvisor-ligolo/pkg/sentry/socket"
    27  	"github.com/nicocha30/gvisor-ligolo/pkg/sentry/vfs"
    28  	"github.com/nicocha30/gvisor-ligolo/pkg/syserr"
    29  	"github.com/nicocha30/gvisor-ligolo/pkg/tcpip"
    30  	"github.com/nicocha30/gvisor-ligolo/pkg/tcpip/header"
    31  	"github.com/nicocha30/gvisor-ligolo/pkg/tcpip/network/ipv4"
    32  	"github.com/nicocha30/gvisor-ligolo/pkg/tcpip/network/ipv6"
    33  	"github.com/nicocha30/gvisor-ligolo/pkg/tcpip/transport/tcp"
    34  	"github.com/nicocha30/gvisor-ligolo/pkg/tcpip/transport/udp"
    35  	"github.com/nicocha30/gvisor-ligolo/pkg/waiter"
    36  )
    37  
    38  // provider is an inet socket provider.
    39  type provider struct {
    40  	family   int
    41  	netProto tcpip.NetworkProtocolNumber
    42  }
    43  
    44  var rawMissingLogger = log.BasicRateLimitedLogger(time.Minute)
    45  
    46  // getTransportProtocol figures out transport protocol. Currently only TCP,
    47  // UDP, and ICMP are supported. The bool return value is true when this socket
    48  // is associated with a transport protocol. This is only false for SOCK_RAW,
    49  // IPPROTO_IP sockets.
    50  func getTransportProtocol(ctx context.Context, stype linux.SockType, protocol int) (tcpip.TransportProtocolNumber, bool, *syserr.Error) {
    51  	switch stype {
    52  	case linux.SOCK_STREAM:
    53  		if protocol != 0 && protocol != unix.IPPROTO_TCP {
    54  			return 0, true, syserr.ErrInvalidArgument
    55  		}
    56  		return tcp.ProtocolNumber, true, nil
    57  
    58  	case linux.SOCK_DGRAM:
    59  		switch protocol {
    60  		case 0, unix.IPPROTO_UDP:
    61  			return udp.ProtocolNumber, true, nil
    62  		case unix.IPPROTO_ICMP:
    63  			return header.ICMPv4ProtocolNumber, true, nil
    64  		case unix.IPPROTO_ICMPV6:
    65  			return header.ICMPv6ProtocolNumber, true, nil
    66  		}
    67  
    68  	case linux.SOCK_RAW:
    69  		// Raw sockets require CAP_NET_RAW.
    70  		creds := auth.CredentialsFromContext(ctx)
    71  		if !creds.HasCapability(linux.CAP_NET_RAW) {
    72  			rawMissingLogger.Infof("A process tried to create a raw socket without CAP_NET_RAW. Should the container config enable CAP_NET_RAW?")
    73  			return 0, true, syserr.ErrNotPermitted
    74  		}
    75  
    76  		switch protocol {
    77  		case unix.IPPROTO_ICMP:
    78  			return header.ICMPv4ProtocolNumber, true, nil
    79  		case unix.IPPROTO_ICMPV6:
    80  			return header.ICMPv6ProtocolNumber, true, nil
    81  		case unix.IPPROTO_UDP:
    82  			return header.UDPProtocolNumber, true, nil
    83  		case unix.IPPROTO_TCP:
    84  			return header.TCPProtocolNumber, true, nil
    85  		// IPPROTO_RAW signifies that the raw socket isn't assigned to
    86  		// a transport protocol. Users will be able to write packets'
    87  		// IP headers and won't receive anything.
    88  		case unix.IPPROTO_RAW:
    89  			return tcpip.TransportProtocolNumber(0), false, nil
    90  		}
    91  	}
    92  	return 0, true, syserr.ErrProtocolNotSupported
    93  }
    94  
    95  // Socket creates a new socket object for the AF_INET, AF_INET6, or AF_PACKET
    96  // family.
    97  func (p *provider) Socket(t *kernel.Task, stype linux.SockType, protocol int) (*vfs.FileDescription, *syserr.Error) {
    98  	// Fail right away if we don't have a stack.
    99  	stack := t.NetworkContext()
   100  	if stack == nil {
   101  		// Don't propagate an error here. Instead, allow the socket
   102  		// code to continue searching for another provider.
   103  		return nil, nil
   104  	}
   105  	eps, ok := stack.(*Stack)
   106  	if !ok {
   107  		return nil, nil
   108  	}
   109  
   110  	// Packet sockets are handled separately, since they are neither INET
   111  	// nor INET6 specific.
   112  	if p.family == linux.AF_PACKET {
   113  		return packetSocket(t, eps, stype, protocol)
   114  	}
   115  
   116  	// Figure out the transport protocol.
   117  	transProto, associated, err := getTransportProtocol(t, stype, protocol)
   118  	if err != nil {
   119  		return nil, err
   120  	}
   121  
   122  	// Create the endpoint.
   123  	var ep tcpip.Endpoint
   124  	var e tcpip.Error
   125  	wq := &waiter.Queue{}
   126  	if stype == linux.SOCK_RAW {
   127  		ep, e = eps.Stack.NewRawEndpoint(transProto, p.netProto, wq, associated)
   128  	} else {
   129  		ep, e = eps.Stack.NewEndpoint(transProto, p.netProto, wq)
   130  
   131  		// Assign task to PacketOwner interface to get the UID and GID for
   132  		// iptables owner matching.
   133  		if e == nil {
   134  			ep.SetOwner(t)
   135  		}
   136  	}
   137  	if e != nil {
   138  		return nil, syserr.TranslateNetstackError(e)
   139  	}
   140  
   141  	return New(t, p.family, stype, int(transProto), wq, ep)
   142  }
   143  
   144  func packetSocket(t *kernel.Task, epStack *Stack, stype linux.SockType, protocol int) (*vfs.FileDescription, *syserr.Error) {
   145  	// Packet sockets require CAP_NET_RAW.
   146  	creds := auth.CredentialsFromContext(t)
   147  	if !creds.HasCapability(linux.CAP_NET_RAW) {
   148  		rawMissingLogger.Infof("A process tried to create a raw socket without CAP_NET_RAW. Should the container config enable CAP_NET_RAW?")
   149  		return nil, syserr.ErrNotPermitted
   150  	}
   151  
   152  	// "cooked" packets don't contain link layer information.
   153  	var cooked bool
   154  	switch stype {
   155  	case linux.SOCK_DGRAM:
   156  		cooked = true
   157  	case linux.SOCK_RAW:
   158  		cooked = false
   159  	default:
   160  		return nil, syserr.ErrProtocolNotSupported
   161  	}
   162  
   163  	// protocol is passed in network byte order, but netstack wants it in
   164  	// host order.
   165  	netProto := tcpip.NetworkProtocolNumber(socket.Ntohs(uint16(protocol)))
   166  
   167  	wq := &waiter.Queue{}
   168  	ep, err := epStack.Stack.NewPacketEndpoint(cooked, netProto, wq)
   169  	if err != nil {
   170  		return nil, syserr.TranslateNetstackError(err)
   171  	}
   172  
   173  	return New(t, linux.AF_PACKET, stype, protocol, wq, ep)
   174  }
   175  
   176  // Pair just returns nil sockets (not supported).
   177  func (*provider) Pair(*kernel.Task, linux.SockType, int) (*vfs.FileDescription, *vfs.FileDescription, *syserr.Error) {
   178  	return nil, nil, nil
   179  }
   180  
   181  // init registers socket providers for AF_INET, AF_INET6, and AF_PACKET.
   182  func init() {
   183  	// Providers backed by netstack.
   184  	p := []provider{
   185  		{
   186  			family:   linux.AF_INET,
   187  			netProto: ipv4.ProtocolNumber,
   188  		},
   189  		{
   190  			family:   linux.AF_INET6,
   191  			netProto: ipv6.ProtocolNumber,
   192  		},
   193  		{
   194  			family: linux.AF_PACKET,
   195  		},
   196  	}
   197  
   198  	for i := range p {
   199  		socket.RegisterProvider(p[i].family, &p[i])
   200  	}
   201  }