github.com/Andyfoo/golang/x/net@v0.0.0-20190901054642-57c1bf301704/bpf/vm_load_test.go (about)

     1  // Copyright 2016 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package bpf_test
     6  
     7  import (
     8  	"net"
     9  	"testing"
    10  
    11  	"github.com/Andyfoo/golang/x/net/bpf"
    12  	"github.com/Andyfoo/golang/x/net/ipv4"
    13  )
    14  
    15  func TestVMLoadAbsoluteOffsetOutOfBounds(t *testing.T) {
    16  	pkt := []byte{
    17  		0xff, 0xff, 0xff, 0xff,
    18  		0xff, 0xff, 0xff, 0xff,
    19  		0, 1, 2, 3,
    20  	}
    21  
    22  	vm, done, err := testVM(t, []bpf.Instruction{
    23  		bpf.LoadAbsolute{
    24  			Off:  uint32(len(pkt)),
    25  			Size: 1,
    26  		},
    27  		// Out of bounds should return 0, return 1 to tell if execution continued
    28  		bpf.RetConstant{Val: 1},
    29  	})
    30  	if err != nil {
    31  		t.Fatalf("failed to load BPF program: %v", err)
    32  	}
    33  	defer done()
    34  
    35  	out, err := vm.Run(pkt)
    36  	if err != nil {
    37  		t.Fatalf("unexpected error while running program: %v", err)
    38  	}
    39  	if want, got := 0, out; want != got {
    40  		t.Fatalf("unexpected result:\n- want: %d\n-  got: %d",
    41  			want, got)
    42  	}
    43  }
    44  
    45  func TestVMLoadAbsoluteOffsetPlusSizeOutOfBounds(t *testing.T) {
    46  	pkt := []byte{
    47  		0xff, 0xff, 0xff, 0xff,
    48  		0xff, 0xff, 0xff, 0xff,
    49  		0,
    50  	}
    51  
    52  	vm, done, err := testVM(t, []bpf.Instruction{
    53  		bpf.LoadAbsolute{
    54  			Off:  uint32(len(pkt) - 1),
    55  			Size: 2,
    56  		},
    57  		// Out of bounds should return 0, return 1 to tell if execution continued
    58  		bpf.RetConstant{Val: 1},
    59  	})
    60  	if err != nil {
    61  		t.Fatalf("failed to load BPF program: %v", err)
    62  	}
    63  	defer done()
    64  
    65  	out, err := vm.Run(pkt)
    66  	if err != nil {
    67  		t.Fatalf("unexpected error while running program: %v", err)
    68  	}
    69  	if want, got := 0, out; want != got {
    70  		t.Fatalf("unexpected result:\n- want: %d\n-  got: %d",
    71  			want, got)
    72  	}
    73  }
    74  
    75  func TestVMLoadAbsoluteBadInstructionSize(t *testing.T) {
    76  	_, _, err := testVM(t, []bpf.Instruction{
    77  		bpf.LoadAbsolute{
    78  			Size: 5,
    79  		},
    80  		bpf.RetA{},
    81  	})
    82  	if errStr(err) != "assembling instruction 1: invalid load byte length 0" {
    83  		t.Fatalf("unexpected error: %v", err)
    84  	}
    85  }
    86  
    87  func TestVMLoadConstantOK(t *testing.T) {
    88  	vm, done, err := testVM(t, []bpf.Instruction{
    89  		bpf.LoadConstant{
    90  			Dst: bpf.RegX,
    91  			Val: 9,
    92  		},
    93  		bpf.TXA{},
    94  		bpf.RetA{},
    95  	})
    96  	if err != nil {
    97  		t.Fatalf("failed to load BPF program: %v", err)
    98  	}
    99  	defer done()
   100  
   101  	out, err := vm.Run([]byte{
   102  		0xff, 0xff, 0xff, 0xff,
   103  		0xff, 0xff, 0xff, 0xff,
   104  		0,
   105  	})
   106  	if err != nil {
   107  		t.Fatalf("unexpected error while running program: %v", err)
   108  	}
   109  	if want, got := 1, out; want != got {
   110  		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
   111  			want, got)
   112  	}
   113  }
   114  
   115  func TestVMLoadIndirectOutOfBounds(t *testing.T) {
   116  	pkt := []byte{
   117  		0xff, 0xff, 0xff, 0xff,
   118  		0xff, 0xff, 0xff, 0xff,
   119  		0,
   120  	}
   121  
   122  	vm, done, err := testVM(t, []bpf.Instruction{
   123  		bpf.LoadIndirect{
   124  			Off:  uint32(len(pkt)),
   125  			Size: 1,
   126  		},
   127  		// Out of bounds should return 0, return 1 to tell if execution continued
   128  		bpf.RetConstant{Val: 1},
   129  	})
   130  	if err != nil {
   131  		t.Fatalf("failed to load BPF program: %v", err)
   132  	}
   133  	defer done()
   134  
   135  	out, err := vm.Run(pkt)
   136  	if err != nil {
   137  		t.Fatalf("unexpected error while running program: %v", err)
   138  	}
   139  	if want, got := 0, out; want != got {
   140  		t.Fatalf("unexpected result:\n- want: %d\n-  got: %d",
   141  			want, got)
   142  	}
   143  }
   144  
   145  func TestVMLoadMemShiftOutOfBounds(t *testing.T) {
   146  	pkt := []byte{
   147  		0xff, 0xff, 0xff, 0xff,
   148  		0xff, 0xff, 0xff, 0xff,
   149  		0,
   150  	}
   151  
   152  	vm, done, err := testVM(t, []bpf.Instruction{
   153  		bpf.LoadMemShift{
   154  			Off: uint32(len(pkt)),
   155  		},
   156  		// Out of bounds should return 0, return 1 to tell if execution continued
   157  		bpf.RetConstant{Val: 1},
   158  	})
   159  	if err != nil {
   160  		t.Fatalf("failed to load BPF program: %v", err)
   161  	}
   162  	defer done()
   163  
   164  	out, err := vm.Run(pkt)
   165  	if err != nil {
   166  		t.Fatalf("unexpected error while running program: %v", err)
   167  	}
   168  	if want, got := 0, out; want != got {
   169  		t.Fatalf("unexpected result:\n- want: %d\n-  got: %d",
   170  			want, got)
   171  	}
   172  }
   173  
   174  const (
   175  	dhcp4Port = 53
   176  )
   177  
   178  func TestVMLoadMemShiftLoadIndirectNoResult(t *testing.T) {
   179  	vm, in, done := testDHCPv4(t)
   180  	defer done()
   181  
   182  	// Append mostly empty UDP header with incorrect DHCPv4 port
   183  	in = append(in, []byte{
   184  		0, 0,
   185  		0, dhcp4Port + 1,
   186  		0, 0,
   187  		0, 0,
   188  	}...)
   189  
   190  	out, err := vm.Run(in)
   191  	if err != nil {
   192  		t.Fatalf("unexpected error while running program: %v", err)
   193  	}
   194  	if want, got := 0, out; want != got {
   195  		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
   196  			want, got)
   197  	}
   198  }
   199  
   200  func TestVMLoadMemShiftLoadIndirectOK(t *testing.T) {
   201  	vm, in, done := testDHCPv4(t)
   202  	defer done()
   203  
   204  	// Append mostly empty UDP header with correct DHCPv4 port
   205  	in = append(in, []byte{
   206  		0, 0,
   207  		0, dhcp4Port,
   208  		0, 0,
   209  		0, 0,
   210  	}...)
   211  
   212  	out, err := vm.Run(in)
   213  	if err != nil {
   214  		t.Fatalf("unexpected error while running program: %v", err)
   215  	}
   216  	if want, got := len(in)-8, out; want != got {
   217  		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
   218  			want, got)
   219  	}
   220  }
   221  
   222  func testDHCPv4(t *testing.T) (virtualMachine, []byte, func()) {
   223  	// DHCPv4 test data courtesy of David Anderson:
   224  	// https://github.com/google/netboot/blob/master/dhcp4/conn_linux.go#L59-L70
   225  	vm, done, err := testVM(t, []bpf.Instruction{
   226  		// Load IPv4 packet length
   227  		bpf.LoadMemShift{Off: 8},
   228  		// Get UDP dport
   229  		bpf.LoadIndirect{Off: 8 + 2, Size: 2},
   230  		// Correct dport?
   231  		bpf.JumpIf{Cond: bpf.JumpEqual, Val: dhcp4Port, SkipFalse: 1},
   232  		// Accept
   233  		bpf.RetConstant{Val: 1500},
   234  		// Ignore
   235  		bpf.RetConstant{Val: 0},
   236  	})
   237  	if err != nil {
   238  		t.Fatalf("failed to load BPF program: %v", err)
   239  	}
   240  
   241  	// Minimal requirements to make a valid IPv4 header
   242  	h := &ipv4.Header{
   243  		Len: ipv4.HeaderLen,
   244  		Src: net.IPv4(192, 168, 1, 1),
   245  		Dst: net.IPv4(192, 168, 1, 2),
   246  	}
   247  	hb, err := h.Marshal()
   248  	if err != nil {
   249  		t.Fatalf("failed to marshal IPv4 header: %v", err)
   250  	}
   251  
   252  	hb = append([]byte{
   253  		0xff, 0xff, 0xff, 0xff,
   254  		0xff, 0xff, 0xff, 0xff,
   255  	}, hb...)
   256  
   257  	return vm, hb, done
   258  }