mirror of
				https://github.com/tailscale/tailscale.git
				synced 2025-11-04 09:25:11 +00:00 
			
		
		
		
	wgengine/netstack: add a missing refcount decrement after packet injection
Fixes #3762 Updates #3745 (probably fixes?) Change-Id: I1d3f0590fd5b8adfbc9110bc45ff717bb9e79aae Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
		
				
					committed by
					
						
						Brad Fitzpatrick
					
				
			
			
				
	
			
			
			
						parent
						
							790e41645b
						
					
				
				
					commit
					185825df11
				
			@@ -520,6 +520,7 @@ func (ns *Impl) injectInbound(p *packet.Parsed, t *tstun.Wrapper) filter.Respons
 | 
				
			|||||||
		Data: vv,
 | 
							Data: vv,
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	ns.linkEP.InjectInbound(pn, packetBuf)
 | 
						ns.linkEP.InjectInbound(pn, packetBuf)
 | 
				
			||||||
 | 
						packetBuf.DecRef()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// We've now delivered this to netstack, so we're done.
 | 
						// We've now delivered this to netstack, so we're done.
 | 
				
			||||||
	// Instead of returning a filter.Accept here (which would also
 | 
						// Instead of returning a filter.Accept here (which would also
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										76
									
								
								wgengine/netstack/netstack_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								wgengine/netstack/netstack_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,76 @@
 | 
				
			|||||||
 | 
					// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved.
 | 
				
			||||||
 | 
					// Use of this source code is governed by a BSD-style
 | 
				
			||||||
 | 
					// license that can be found in the LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package netstack
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"runtime"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"inet.af/netaddr"
 | 
				
			||||||
 | 
						"tailscale.com/net/packet"
 | 
				
			||||||
 | 
						"tailscale.com/net/tsdial"
 | 
				
			||||||
 | 
						"tailscale.com/net/tstun"
 | 
				
			||||||
 | 
						"tailscale.com/wgengine"
 | 
				
			||||||
 | 
						"tailscale.com/wgengine/filter"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TestInjectInboundLeak tests that injectInbound doesn't leak memory.
 | 
				
			||||||
 | 
					// See https://github.com/tailscale/tailscale/issues/3762
 | 
				
			||||||
 | 
					func TestInjectInboundLeak(t *testing.T) {
 | 
				
			||||||
 | 
						tunDev := tstun.NewFake()
 | 
				
			||||||
 | 
						dialer := new(tsdial.Dialer)
 | 
				
			||||||
 | 
						logf := func(format string, args ...interface{}) {
 | 
				
			||||||
 | 
							if !t.Failed() {
 | 
				
			||||||
 | 
								t.Logf(format, args...)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						eng, err := wgengine.NewUserspaceEngine(logf, wgengine.Config{
 | 
				
			||||||
 | 
							Tun:    tunDev,
 | 
				
			||||||
 | 
							Dialer: dialer,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer eng.Close()
 | 
				
			||||||
 | 
						ig, ok := eng.(wgengine.InternalsGetter)
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							t.Fatal("not an InternalsGetter")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						tunWrap, magicSock, ok := ig.GetInternals()
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							t.Fatal("failed to get internals")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ns, err := Create(logf, tunWrap, eng, magicSock, dialer)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer ns.Close()
 | 
				
			||||||
 | 
						ns.ProcessLocalIPs = true
 | 
				
			||||||
 | 
						if err := ns.Start(); err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("Start: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ns.atomicIsLocalIPFunc.Store(func(netaddr.IP) bool { return true })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pkt := &packet.Parsed{}
 | 
				
			||||||
 | 
						const N = 10_000
 | 
				
			||||||
 | 
						ms0 := getMemStats()
 | 
				
			||||||
 | 
						for i := 0; i < N; i++ {
 | 
				
			||||||
 | 
							outcome := ns.injectInbound(pkt, tunWrap)
 | 
				
			||||||
 | 
							if outcome != filter.DropSilently {
 | 
				
			||||||
 | 
								t.Fatalf("got outcome %v; want DropSilently", outcome)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ms1 := getMemStats()
 | 
				
			||||||
 | 
						if grew := int64(ms1.HeapObjects) - int64(ms0.HeapObjects); grew >= N {
 | 
				
			||||||
 | 
							t.Fatalf("grew by %v (which is too much and >= the %v packets we sent)", grew, N)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getMemStats() (ms runtime.MemStats) {
 | 
				
			||||||
 | 
						runtime.GC()
 | 
				
			||||||
 | 
						runtime.ReadMemStats(&ms)
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user