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 }