Skip to content

Commit 121db29

Browse files
kevinGCshentubot
authored andcommitted
Ping support via IPv4 raw sockets.
Broadly, this change: * Enables sockets to be created via `socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)`. * Passes the network-layer (IP) header up the stack to the transport endpoint, which can pass it up to the socket layer. This allows a raw socket to return the entire IP packet to users. * Adds functions to stack.TransportProtocol, stack.Stack, stack.transportDemuxer that enable incoming packets to be delivered to raw endpoints. New raw sockets of other protocols (not ICMP) just need to register with the stack. * Enables ping.endpoint to return IP headers when created via SOCK_RAW. PiperOrigin-RevId: 235993280 Change-Id: I60ed994f5ff18b2cbd79f063a7fdf15d093d845a
1 parent 6df212b commit 121db29

22 files changed

+533
-59
lines changed

pkg/sentry/socket/epsocket/BUILD

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ go_library(
2727
"//pkg/sentry/fs/fsutil",
2828
"//pkg/sentry/inet",
2929
"//pkg/sentry/kernel",
30+
"//pkg/sentry/kernel/auth",
3031
"//pkg/sentry/kernel/kdefs",
3132
"//pkg/sentry/kernel/time",
3233
"//pkg/sentry/safemem",

pkg/sentry/socket/epsocket/provider.go

+24-4
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@ import (
1818
"syscall"
1919

2020
"gvisor.googlesource.com/gvisor/pkg/abi/linux"
21+
"gvisor.googlesource.com/gvisor/pkg/sentry/context"
2122
"gvisor.googlesource.com/gvisor/pkg/sentry/fs"
2223
"gvisor.googlesource.com/gvisor/pkg/sentry/kernel"
24+
"gvisor.googlesource.com/gvisor/pkg/sentry/kernel/auth"
2325
"gvisor.googlesource.com/gvisor/pkg/sentry/socket"
2426
"gvisor.googlesource.com/gvisor/pkg/sentry/socket/unix/transport"
2527
"gvisor.googlesource.com/gvisor/pkg/syserr"
@@ -38,9 +40,9 @@ type provider struct {
3840
netProto tcpip.NetworkProtocolNumber
3941
}
4042

41-
// GetTransportProtocol figures out transport protocol. Currently only TCP,
43+
// getTransportProtocol figures out transport protocol. Currently only TCP,
4244
// UDP, and ICMP are supported.
43-
func GetTransportProtocol(stype transport.SockType, protocol int) (tcpip.TransportProtocolNumber, *syserr.Error) {
45+
func getTransportProtocol(ctx context.Context, stype transport.SockType, protocol int) (tcpip.TransportProtocolNumber, *syserr.Error) {
4446
switch stype {
4547
case linux.SOCK_STREAM:
4648
if protocol != 0 && protocol != syscall.IPPROTO_TCP {
@@ -57,6 +59,18 @@ func GetTransportProtocol(stype transport.SockType, protocol int) (tcpip.Transpo
5759
case syscall.IPPROTO_ICMPV6:
5860
return header.ICMPv6ProtocolNumber, nil
5961
}
62+
63+
case linux.SOCK_RAW:
64+
// Raw sockets require CAP_NET_RAW.
65+
creds := auth.CredentialsFromContext(ctx)
66+
if !creds.HasCapability(linux.CAP_NET_RAW) {
67+
return 0, syserr.ErrPermissionDenied
68+
}
69+
70+
switch protocol {
71+
case syscall.IPPROTO_ICMP:
72+
return header.ICMPv4ProtocolNumber, nil
73+
}
6074
}
6175
return 0, syserr.ErrInvalidArgument
6276
}
@@ -76,14 +90,20 @@ func (p *provider) Socket(t *kernel.Task, stype transport.SockType, protocol int
7690
}
7791

7892
// Figure out the transport protocol.
79-
transProto, err := GetTransportProtocol(stype, protocol)
93+
transProto, err := getTransportProtocol(t, stype, protocol)
8094
if err != nil {
8195
return nil, err
8296
}
8397

8498
// Create the endpoint.
99+
var ep tcpip.Endpoint
100+
var e *tcpip.Error
85101
wq := &waiter.Queue{}
86-
ep, e := eps.Stack.NewEndpoint(transProto, p.netProto, wq)
102+
if stype == linux.SOCK_RAW {
103+
ep, e = eps.Stack.NewRawEndpoint(transProto, p.netProto, wq)
104+
} else {
105+
ep, e = eps.Stack.NewEndpoint(transProto, p.netProto, wq)
106+
}
87107
if e != nil {
88108
return nil, syserr.TranslateNetstackError(e)
89109
}

pkg/tcpip/network/ip_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ func (t *testObject) checkValues(protocol tcpip.TransportProtocolNumber, vv buff
9494
// DeliverTransportPacket is called by network endpoints after parsing incoming
9595
// packets. This is used by the test object to verify that the results of the
9696
// parsing are expected.
97-
func (t *testObject) DeliverTransportPacket(r *stack.Route, protocol tcpip.TransportProtocolNumber, vv buffer.VectorisedView) {
97+
func (t *testObject) DeliverTransportPacket(r *stack.Route, protocol tcpip.TransportProtocolNumber, netHeader buffer.View, vv buffer.VectorisedView) {
9898
t.checkValues(protocol, vv, r.RemoteAddress, r.LocalAddress)
9999
t.dataCalls++
100100
}

pkg/tcpip/network/ipv4/icmp.go

+7-4
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ func (e *endpoint) handleControl(typ stack.ControlType, extra uint32, vv buffer.
5555
e.dispatcher.DeliverTransportControlPacket(e.id.LocalAddress, h.DestinationAddress(), ProtocolNumber, p, typ, extra, vv)
5656
}
5757

58-
func (e *endpoint) handleICMP(r *stack.Route, vv buffer.VectorisedView) {
58+
func (e *endpoint) handleICMP(r *stack.Route, netHeader buffer.View, vv buffer.VectorisedView) {
5959
v := vv.First()
6060
if len(v) < header.ICMPv4MinimumSize {
6161
return
@@ -67,19 +67,22 @@ func (e *endpoint) handleICMP(r *stack.Route, vv buffer.VectorisedView) {
6767
if len(v) < header.ICMPv4EchoMinimumSize {
6868
return
6969
}
70-
vv.TrimFront(header.ICMPv4MinimumSize)
71-
req := echoRequest{r: r.Clone(), v: vv.ToView()}
70+
echoPayload := vv.ToView()
71+
echoPayload.TrimFront(header.ICMPv4MinimumSize)
72+
req := echoRequest{r: r.Clone(), v: echoPayload}
7273
select {
7374
case e.echoRequests <- req:
7475
default:
7576
req.r.Release()
7677
}
78+
// It's possible that a raw socket expects to receive this.
79+
e.dispatcher.DeliverTransportPacket(r, header.ICMPv4ProtocolNumber, netHeader, vv)
7780

7881
case header.ICMPv4EchoReply:
7982
if len(v) < header.ICMPv4EchoMinimumSize {
8083
return
8184
}
82-
e.dispatcher.DeliverTransportPacket(r, header.ICMPv4ProtocolNumber, vv)
85+
e.dispatcher.DeliverTransportPacket(r, header.ICMPv4ProtocolNumber, netHeader, vv)
8386

8487
case header.ICMPv4DstUnreachable:
8588
if len(v) < header.ICMPv4DstUnreachableMinimumSize {

pkg/tcpip/network/ipv4/ipv4.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,8 @@ func (e *endpoint) WritePacket(r *stack.Route, hdr buffer.Prependable, payload b
131131
// HandlePacket is called by the link layer when new ipv4 packets arrive for
132132
// this endpoint.
133133
func (e *endpoint) HandlePacket(r *stack.Route, vv buffer.VectorisedView) {
134-
h := header.IPv4(vv.First())
134+
headerView := vv.First()
135+
h := header.IPv4(headerView)
135136
if !h.IsValid(vv.Size()) {
136137
return
137138
}
@@ -153,11 +154,12 @@ func (e *endpoint) HandlePacket(r *stack.Route, vv buffer.VectorisedView) {
153154
}
154155
p := h.TransportProtocol()
155156
if p == header.ICMPv4ProtocolNumber {
156-
e.handleICMP(r, vv)
157+
headerView.CapLength(hlen)
158+
e.handleICMP(r, headerView, vv)
157159
return
158160
}
159161
r.Stats().IP.PacketsDelivered.Increment()
160-
e.dispatcher.DeliverTransportPacket(r, p, vv)
162+
e.dispatcher.DeliverTransportPacket(r, p, headerView, vv)
161163
}
162164

163165
// Close cleans up resources associated with the endpoint.

pkg/tcpip/network/ipv6/icmp.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ func (e *endpoint) handleControl(typ stack.ControlType, extra uint32, vv buffer.
6262
e.dispatcher.DeliverTransportControlPacket(e.id.LocalAddress, h.DestinationAddress(), ProtocolNumber, p, typ, extra, vv)
6363
}
6464

65-
func (e *endpoint) handleICMP(r *stack.Route, vv buffer.VectorisedView) {
65+
func (e *endpoint) handleICMP(r *stack.Route, netHeader buffer.View, vv buffer.VectorisedView) {
6666
v := vv.First()
6767
if len(v) < header.ICMPv6MinimumSize {
6868
return
@@ -148,7 +148,7 @@ func (e *endpoint) handleICMP(r *stack.Route, vv buffer.VectorisedView) {
148148
if len(v) < header.ICMPv6EchoMinimumSize {
149149
return
150150
}
151-
e.dispatcher.DeliverTransportPacket(r, header.ICMPv6ProtocolNumber, vv)
151+
e.dispatcher.DeliverTransportPacket(r, header.ICMPv6ProtocolNumber, netHeader, vv)
152152

153153
}
154154
}

pkg/tcpip/network/ipv6/ipv6.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@ func (e *endpoint) WritePacket(r *stack.Route, hdr buffer.Prependable, payload b
102102
// HandlePacket is called by the link layer when new ipv6 packets arrive for
103103
// this endpoint.
104104
func (e *endpoint) HandlePacket(r *stack.Route, vv buffer.VectorisedView) {
105-
h := header.IPv6(vv.First())
105+
headerView := vv.First()
106+
h := header.IPv6(headerView)
106107
if !h.IsValid(vv.Size()) {
107108
return
108109
}
@@ -112,12 +113,12 @@ func (e *endpoint) HandlePacket(r *stack.Route, vv buffer.VectorisedView) {
112113

113114
p := h.TransportProtocol()
114115
if p == header.ICMPv6ProtocolNumber {
115-
e.handleICMP(r, vv)
116+
e.handleICMP(r, headerView, vv)
116117
return
117118
}
118119

119120
r.Stats().IP.PacketsDelivered.Increment()
120-
e.dispatcher.DeliverTransportPacket(r, p, vv)
121+
e.dispatcher.DeliverTransportPacket(r, p, headerView, vv)
121122
}
122123

123124
// Close cleans up resources associated with the endpoint.

pkg/tcpip/stack/nic.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,7 @@ func (n *NIC) getRef(protocol tcpip.NetworkProtocolNumber, dst tcpip.Address) *r
505505

506506
// DeliverTransportPacket delivers the packets to the appropriate transport
507507
// protocol endpoint.
508-
func (n *NIC) DeliverTransportPacket(r *Route, protocol tcpip.TransportProtocolNumber, vv buffer.VectorisedView) {
508+
func (n *NIC) DeliverTransportPacket(r *Route, protocol tcpip.TransportProtocolNumber, netHeader buffer.View, vv buffer.VectorisedView) {
509509
state, ok := n.stack.transportProtocols[protocol]
510510
if !ok {
511511
n.stack.stats.UnknownProtocolRcvdPackets.Increment()
@@ -525,16 +525,16 @@ func (n *NIC) DeliverTransportPacket(r *Route, protocol tcpip.TransportProtocolN
525525
}
526526

527527
id := TransportEndpointID{dstPort, r.LocalAddress, srcPort, r.RemoteAddress}
528-
if n.demux.deliverPacket(r, protocol, vv, id) {
528+
if n.demux.deliverPacket(r, protocol, netHeader, vv, id) {
529529
return
530530
}
531-
if n.stack.demux.deliverPacket(r, protocol, vv, id) {
531+
if n.stack.demux.deliverPacket(r, protocol, netHeader, vv, id) {
532532
return
533533
}
534534

535535
// Try to deliver to per-stack default handler.
536536
if state.defaultHandler != nil {
537-
if state.defaultHandler(r, id, vv) {
537+
if state.defaultHandler(r, id, netHeader, vv) {
538538
return
539539
}
540540
}

pkg/tcpip/stack/registration.go

+7-3
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ const (
6464
type TransportEndpoint interface {
6565
// HandlePacket is called by the stack when new packets arrive to
6666
// this transport endpoint.
67-
HandlePacket(r *Route, id TransportEndpointID, vv buffer.VectorisedView)
67+
HandlePacket(r *Route, id TransportEndpointID, netHeader buffer.View, vv buffer.VectorisedView)
6868

6969
// HandleControlPacket is called by the stack when new control (e.g.,
7070
// ICMP) packets arrive to this transport endpoint.
@@ -80,6 +80,9 @@ type TransportProtocol interface {
8080
// NewEndpoint creates a new endpoint of the transport protocol.
8181
NewEndpoint(stack *Stack, netProto tcpip.NetworkProtocolNumber, waitQueue *waiter.Queue) (tcpip.Endpoint, *tcpip.Error)
8282

83+
// NewRawEndpoint creates a new raw endpoint of the transport protocol.
84+
NewRawEndpoint(stack *Stack, netProto tcpip.NetworkProtocolNumber, waitQueue *waiter.Queue) (tcpip.Endpoint, *tcpip.Error)
85+
8386
// MinimumPacketSize returns the minimum valid packet size of this
8487
// transport protocol. The stack automatically drops any packets smaller
8588
// than this targeted at this protocol.
@@ -113,8 +116,9 @@ type TransportProtocol interface {
113116
// the network layer.
114117
type TransportDispatcher interface {
115118
// DeliverTransportPacket delivers packets to the appropriate
116-
// transport protocol endpoint.
117-
DeliverTransportPacket(r *Route, protocol tcpip.TransportProtocolNumber, vv buffer.VectorisedView)
119+
// transport protocol endpoint. It also returns the network layer
120+
// header for the enpoint to inspect or pass up the stack.
121+
DeliverTransportPacket(r *Route, protocol tcpip.TransportProtocolNumber, netHeader buffer.View, vv buffer.VectorisedView)
118122

119123
// DeliverTransportControlPacket delivers control packets to the
120124
// appropriate transport protocol endpoint.

pkg/tcpip/stack/stack.go

+50-2
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ const (
4848

4949
type transportProtocolState struct {
5050
proto TransportProtocol
51-
defaultHandler func(*Route, TransportEndpointID, buffer.VectorisedView) bool
51+
defaultHandler func(r *Route, id TransportEndpointID, netHeader buffer.View, vv buffer.VectorisedView) bool
5252
}
5353

5454
// TCPProbeFunc is the expected function type for a TCP probe function to be
@@ -437,7 +437,7 @@ func (s *Stack) TransportProtocolOption(transport tcpip.TransportProtocolNumber,
437437
//
438438
// It must be called only during initialization of the stack. Changing it as the
439439
// stack is operating is not supported.
440-
func (s *Stack) SetTransportProtocolHandler(p tcpip.TransportProtocolNumber, h func(*Route, TransportEndpointID, buffer.VectorisedView) bool) {
440+
func (s *Stack) SetTransportProtocolHandler(p tcpip.TransportProtocolNumber, h func(*Route, TransportEndpointID, buffer.View, buffer.VectorisedView) bool) {
441441
state := s.transportProtocols[p]
442442
if state != nil {
443443
state.defaultHandler = h
@@ -499,6 +499,18 @@ func (s *Stack) NewEndpoint(transport tcpip.TransportProtocolNumber, network tcp
499499
return t.proto.NewEndpoint(s, network, waiterQueue)
500500
}
501501

502+
// NewRawEndpoint creates a new raw transport layer endpoint of the given
503+
// protocol. Raw endpoints receive all traffic for a given protocol regardless
504+
// of address.
505+
func (s *Stack) NewRawEndpoint(transport tcpip.TransportProtocolNumber, network tcpip.NetworkProtocolNumber, waiterQueue *waiter.Queue) (tcpip.Endpoint, *tcpip.Error) {
506+
t, ok := s.transportProtocols[transport]
507+
if !ok {
508+
return nil, tcpip.ErrUnknownProtocol
509+
}
510+
511+
return t.proto.NewRawEndpoint(s, network, waiterQueue)
512+
}
513+
502514
// createNIC creates a NIC with the provided id and link-layer endpoint, and
503515
// optionally enable it.
504516
func (s *Stack) createNIC(id tcpip.NICID, name string, linkEP tcpip.LinkEndpointID, enabled bool) *tcpip.Error {
@@ -934,6 +946,42 @@ func (s *Stack) UnregisterTransportEndpoint(nicID tcpip.NICID, netProtos []tcpip
934946
}
935947
}
936948

949+
// RegisterRawTransportEndpoint registers the given endpoint with the stack
950+
// transport dispatcher. Received packets that match the provided protocol will
951+
// be delivered to the given endpoint.
952+
func (s *Stack) RegisterRawTransportEndpoint(nicID tcpip.NICID, netProtos []tcpip.NetworkProtocolNumber, protocol tcpip.TransportProtocolNumber, ep TransportEndpoint, reusePort bool) *tcpip.Error {
953+
if nicID == 0 {
954+
return s.demux.registerRawEndpoint(netProtos, protocol, ep, reusePort)
955+
}
956+
957+
s.mu.RLock()
958+
defer s.mu.RUnlock()
959+
960+
nic := s.nics[nicID]
961+
if nic == nil {
962+
return tcpip.ErrUnknownNICID
963+
}
964+
965+
return nic.demux.registerRawEndpoint(netProtos, protocol, ep, reusePort)
966+
}
967+
968+
// UnregisterRawTransportEndpoint removes the endpoint for the protocol from
969+
// the stack transport dispatcher.
970+
func (s *Stack) UnregisterRawTransportEndpoint(nicID tcpip.NICID, netProtos []tcpip.NetworkProtocolNumber, protocol tcpip.TransportProtocolNumber, ep TransportEndpoint) {
971+
if nicID == 0 {
972+
s.demux.unregisterRawEndpoint(netProtos, protocol, ep)
973+
return
974+
}
975+
976+
s.mu.RLock()
977+
defer s.mu.RUnlock()
978+
979+
nic := s.nics[nicID]
980+
if nic != nil {
981+
nic.demux.unregisterRawEndpoint(netProtos, protocol, ep)
982+
}
983+
}
984+
937985
// NetworkProtocolInstance returns the protocol instance in the stack for the
938986
// specified network protocol. This method is public for protocol implementers
939987
// and tests to use.

pkg/tcpip/stack/stack_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ func (f *fakeNetworkEndpoint) HandlePacket(r *stack.Route, vv buffer.VectorisedV
9797
}
9898

9999
// Dispatch the packet to the transport protocol.
100-
f.dispatcher.DeliverTransportPacket(r, tcpip.TransportProtocolNumber(b[2]), vv)
100+
f.dispatcher.DeliverTransportPacket(r, tcpip.TransportProtocolNumber(b[2]), buffer.View([]byte{}), vv)
101101
}
102102

103103
func (f *fakeNetworkEndpoint) MaxHeaderLength() uint16 {

0 commit comments

Comments
 (0)