gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/sentry/syscalls/linux/linux64_test.go (about)

     1  // Copyright 2022 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 linux
    16  
    17  import (
    18  	"fmt"
    19  	"os"
    20  	"reflect"
    21  	"runtime"
    22  	"strings"
    23  	"testing"
    24  	"unicode"
    25  
    26  	"gvisor.dev/gvisor/pkg/sentry/seccheck"
    27  )
    28  
    29  func findPoint(name string) (seccheck.PointDesc, bool) {
    30  	for _, pt := range seccheck.Points {
    31  		if pt.Name == name {
    32  			return pt, true
    33  		}
    34  	}
    35  	return seccheck.PointDesc{}, false
    36  }
    37  
    38  // TestSeccheckMax catches cases that a new syscall was added but seccheck raw
    39  // syscall numbers (e.g. syscall/sysno/123) have not been updated.
    40  func TestSeccheckMax(t *testing.T) {
    41  	max := uintptr(0)
    42  	for sysno := range archToTest.Table {
    43  		if sysno > max {
    44  			max = sysno
    45  		}
    46  	}
    47  
    48  	want := fmt.Sprintf("syscall/sysno/%d/enter", max)
    49  	if _, ok := findPoint(want); !ok {
    50  		t.Errorf("seccheck.PointDesc for syscall %d not found. Update pkg/sentry/seccheck/metadata_amd64.go", max)
    51  	}
    52  }
    53  
    54  // TestSeccheckSyscalls verifies that all syscalls registered with a point
    55  // callback have the corresponding seccheck metadata created.
    56  func TestSeccheckSyscalls(t *testing.T) {
    57  	for sysno, syscall := range archToTest.Table {
    58  		if syscall.PointCallback == nil {
    59  			continue
    60  		}
    61  
    62  		// For every syscall with a PointCallback, there must be a corresponding
    63  		// seccheck.PointDesc created.
    64  		funcName := runtime.FuncForPC(reflect.ValueOf(syscall.PointCallback).Pointer()).Name()
    65  		if idx := strings.LastIndex(funcName, "."); idx > -1 {
    66  			funcName = funcName[idx+1:]
    67  		}
    68  		t.Run(funcName, func(t *testing.T) {
    69  			if !strings.HasPrefix(funcName, "Point") {
    70  				t.Errorf("PointCallback function name must start with Point: %q", funcName)
    71  			}
    72  			funcName = strings.TrimPrefix(funcName, "Point")
    73  			if len(funcName) == 0 {
    74  				t.Errorf("PointCallback function name invalid: %q", funcName)
    75  			}
    76  
    77  			pointName := strings.ToLower(string(funcName[0]))
    78  			for _, c := range funcName[1:] {
    79  				if unicode.IsUpper(c) {
    80  					pointName += "_"
    81  				}
    82  				pointName += string(unicode.ToLower(c))
    83  			}
    84  
    85  			for _, flavor := range []struct {
    86  				suffix string
    87  				typ    seccheck.SyscallType
    88  			}{
    89  				{suffix: "enter", typ: seccheck.SyscallEnter},
    90  				{suffix: "exit", typ: seccheck.SyscallExit},
    91  			} {
    92  				fullName := fmt.Sprintf("syscall/%s/%s", pointName, flavor.suffix)
    93  				pt, ok := findPoint(fullName)
    94  				if !ok {
    95  					t.Fatalf("seccheck.PointDesc %q not found.", fullName)
    96  				}
    97  				if want := seccheck.GetPointForSyscall(flavor.typ, sysno); want != pt.ID {
    98  					t.Errorf("seccheck.Point for syscall %q is wrong, want: %v, got: %v", pointName, want, pt.ID)
    99  				}
   100  			}
   101  		})
   102  	}
   103  }
   104  
   105  func TestMain(m *testing.M) {
   106  	seccheck.Initialize()
   107  	os.Exit(m.Run())
   108  }