Skip to content

Commit a715280

Browse files
committed
netstack/icmp: addn pkt header and payload size checks
1 parent e5bc08c commit a715280

3 files changed

Lines changed: 46 additions & 17 deletions

File tree

intra/core/async.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,21 @@ func Await(f func(), until time.Duration) (awaited bool) {
276276
}
277277
}
278278

279+
func Await1[T any](f func() T, until time.Duration) (v T, gotV bool) {
280+
done := make(chan struct{})
281+
Go("await", func() {
282+
defer close(done)
283+
v = f()
284+
})
285+
286+
select {
287+
case <-time.After(until):
288+
return v, false
289+
case <-done:
290+
return v, true
291+
}
292+
}
293+
279294
func EitherOr(either <-chan struct{}, or Callback, until time.Duration) (esc bool) {
280295
select {
281296
case <-time.Tick(until):

intra/netstack/icmp.go

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -62,23 +62,29 @@ func (f *icmpForwarder) reply4(id stack.TransportEndpointID, pkt *stack.PacketBu
6262
log.VV("icmp: v4: %s: packet? %v", f.o, pkt)
6363
}
6464

65-
if pkt == nil {
66-
log.E("icmp: v4: %s: nil packet", f.o)
65+
if pkt == nil || pkt.Size() <= 0 {
66+
log.E("icmp: v4: %s: nil packet (%t) or size 0", f.o, pkt == nil)
6767
return // not handled
6868
}
6969

7070
src := remoteAddrPort(id)
7171
dst := localAddrPort(id)
7272

73+
l4hdr := pkt.TransportHeader().Slice()
74+
l3hdr := pkt.NetworkHeader().Slice()
75+
if len(l4hdr) < header.ICMPv4MinimumSize || len(l3hdr) < header.IPv4MinimumSize {
76+
log.E("icmp: v4: %s: invalid packet size; l4hdr: %d / l3hdr: %d", f.o, len(l4hdr), len(l3hdr))
77+
return // not handled
78+
}
79+
7380
// ref: github.com/google/gvisor/blob/acf460d0d735/pkg/tcpip/stack/conntrack.go#L933
74-
hdr := header.ICMPv4(pkt.TransportHeader().Slice())
81+
hdr := header.ICMPv4(l4hdr)
7582
if hdr.Type() != header.ICMPv4Echo {
7683
// netstack handles other msgs except echo / ping
7784
log.D("icmp: v4: %s: type %v passthrough", f.o, hdr.Type())
7885
return // not handled
7986
}
80-
ipHdr := header.IPv4(pkt.NetworkHeader().Slice())
81-
87+
ipHdr := header.IPv4(l3hdr)
8288
replyData := stack.PayloadSince(pkt.TransportHeader())
8389
localAddressBroadcast := pkt.NetworkPacketInfo.LocalAddressBroadcast
8490

@@ -93,8 +99,9 @@ func (f *icmpForwarder) reply4(id stack.TransportEndpointID, pkt *stack.PacketBu
9399

94100
l3 := pkt.Network() // same as ipHdr; l3.Dst == id.LocalAddr and l3.Src == id.RemoteAddr
95101
route, err := f.s.FindRoute(pkt.NICID, localAddr, l3.SourceAddress(), pkt.NetworkProtocolNumber, false /* multicastLoop */)
96-
if err != nil {
97-
log.W("icmp: v4: %s: no route on %v to %s <= %s", f.o, pkt.NICID, l3.DestinationAddress(), l3.SourceAddress())
102+
if err != nil || replyData.Size() <= 0 {
103+
log.W("icmp: v4: %s: no route on %v to %s <= %s; sz: (l3hdr: %d / l4hdr: %d / payload: %d)",
104+
f.o, pkt.NICID, l3.DestinationAddress(), l3.SourceAddress(), len(l3hdr), len(l4hdr), replyData.Size())
98105
return // not handled
99106
}
100107

@@ -165,7 +172,13 @@ func (f *icmpForwarder) reply6(id stack.TransportEndpointID, pkt *stack.PacketBu
165172
return // not handled
166173
}
167174

168-
hdr := header.ICMPv6(pkt.TransportHeader().Slice())
175+
l4hdr := pkt.TransportHeader().Slice()
176+
if len(l4hdr) < header.ICMPv6MinimumSize {
177+
log.E("icmp: v6: %s: invalid packet size; l4hdr: %d", f.o, len(l4hdr))
178+
return // not handled
179+
}
180+
181+
hdr := header.ICMPv6(l4hdr)
169182
if hdr.Type() != header.ICMPv6EchoRequest {
170183
log.D("icmp: v6: %s: type %v/%v passthrough", f.o, hdr.Type(), hdr.Code())
171184
return // netstack to handle other msgs except echo / ping
@@ -182,14 +195,14 @@ func (f *icmpForwarder) reply6(id stack.TransportEndpointID, pkt *stack.PacketBu
182195
dst := localAddrPort(id)
183196
// github.com/google/gvisor/blob/9b4a7aa00/pkg/tcpip/network/ipv6/icmp.go#L1180
184197
data, derr := l4l7(pkt, route.MTU())
185-
if derr != nil {
186-
log.E("icmp: v6: %s: err getting payload: %v", f.o, derr)
198+
if derr != nil || len(data) <= 0 {
199+
log.E("icmp: v6: %s: payload (sz: %d) err: %v", f.o, len(data), derr)
187200
return // not handled
188201
}
189202

190203
if settings.Debug {
191-
log.D("icmp: v6: %s: type %v/%v sz[%d] from src(%v) => dst(%v)",
192-
f.o, hdr.Type(), hdr.Code(), len(data), src, dst)
204+
log.D("icmp: v6: %s: type %v/%v sz[l4: %d / payload: %d] from src(%v) => dst(%v)",
205+
f.o, hdr.Type(), hdr.Code(), len(l4hdr), len(data), src, dst)
193206
}
194207

195208
// always forward in a goroutine to avoid blocking netstack

intra/netstack/icmpecho.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"net/netip"
66
"sync/atomic"
7+
"time"
78

89
"github.com/celzero/firestack/intra/core"
910
"github.com/celzero/firestack/intra/core/wire"
@@ -164,7 +165,7 @@ func (r *icmpResponder) forward(h *icmpForwarder, pkt *stack.PacketBuffer, src,
164165
remote := src.Addr().AsSlice()
165166

166167
notok := len(local) == 0 || len(remote) == 0
167-
logwv(notok)("icmp: responder: forward: (sz: %d) empty addr; %s => %s", pkt.Size(), src, dst)
168+
logwv(notok)("icmp: responder: forward: (sz: %d) empty addr? %s => %s", pkt.Size(), src, dst)
168169
if notok {
169170
return false
170171
}
@@ -176,11 +177,11 @@ func (r *icmpResponder) forward(h *icmpForwarder, pkt *stack.PacketBuffer, src,
176177

177178
switch pkt.NetworkProtocolNumber {
178179
case header.IPv4ProtocolNumber:
179-
core.Gx("icmpecho.reply4", func() { h.reply4(id, pkt) })
180-
return true
180+
v, got := core.Await1(func() bool { defer pkt.DecRef(); return h.reply4(id, pkt.IncRef()) }, 3*time.Second)
181+
return got && v
181182
case header.IPv6ProtocolNumber:
182-
core.Gx("icmpecho.reply6", func() { h.reply6(id, pkt) })
183-
return true
183+
v, got := core.Await1(func() bool { defer pkt.DecRef(); return h.reply6(id, pkt.IncRef()) }, 3*time.Second)
184+
return got && v
184185
}
185186

186187
log.W("icmp: responder: unsupported proto: %d; %s => %s",

0 commit comments

Comments
 (0)