github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/pkg/validator/validator.go (about)

     1  // Copyright 2024 syzkaller project authors. All rights reserved.
     2  // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
     3  
     4  package validator
     5  
     6  import (
     7  	"errors"
     8  	"fmt"
     9  	"regexp"
    10  	"strings"
    11  
    12  	"github.com/google/syzkaller/pkg/auth"
    13  	"github.com/google/syzkaller/pkg/coveragedb"
    14  )
    15  
    16  type Result struct {
    17  	Ok  bool
    18  	Err error
    19  }
    20  
    21  var ResultOk = Result{true, nil}
    22  
    23  func AnyError(errPrefix string, results ...Result) error {
    24  	for _, res := range results {
    25  		if !res.Ok {
    26  			return wrapError(res.Err.Error(), errPrefix)
    27  		}
    28  	}
    29  	return nil
    30  }
    31  
    32  func AnyOk(results ...Result) Result {
    33  	if len(results) == 0 {
    34  		return ResultOk
    35  	}
    36  	for _, res := range results {
    37  		if res.Ok {
    38  			return ResultOk
    39  		}
    40  	}
    41  	return results[0]
    42  }
    43  
    44  func PanicIfNot(results ...Result) error {
    45  	if err := AnyError("", results...); err != nil {
    46  		panic(err.Error())
    47  	}
    48  	return nil
    49  }
    50  
    51  var ErrValueNotAllowed = errors.New("value is not allowed")
    52  
    53  func Allowlisted(str string, allowlist []string, valueName ...string) Result {
    54  	for _, allowed := range allowlist {
    55  		if allowed == str {
    56  			return Result{
    57  				Ok: true,
    58  			}
    59  		}
    60  	}
    61  	if len(valueName) == 0 {
    62  		return Result{
    63  			Err: fmt.Errorf("value %s is not allowed", str),
    64  		}
    65  	}
    66  	return Result{
    67  		Err: fmt.Errorf("%s(%s) is not allowed", valueName[0], str),
    68  	}
    69  }
    70  
    71  var (
    72  	EmptyStr       = makeStrLenFunc("not empty", 0)
    73  	AlphaNumeric   = makeStrReFunc("not an alphanum", "^[a-zA-Z0-9]*$")
    74  	CommitHash     = makeCombinedStrFunc("not a hash", AlphaNumeric, makeStrLenFunc("len is not 40", 40))
    75  	KernelFilePath = makeStrReFunc("not a kernel file path", "^[./_a-zA-Z0-9-]*$")
    76  	NamespaceName  = makeStrReFunc("not a namespace name", "^[a-zA-Z0-9_.-]{4,32}$")
    77  	ManagerName    = makeStrReFunc("not a manager name", "^[a-z0-9-]*$")
    78  	DashClientName = makeStrReFunc("not a dashboard client name", "^[a-zA-Z0-9_.-]{4,100}$")
    79  	DashClientKey  = makeStrReFunc("not a dashboard client key",
    80  		"^([a-zA-Z0-9]{16,128})|("+regexp.QuoteMeta(auth.OauthMagic)+".*)$")
    81  	TimePeriodType = makeStrReFunc(fmt.Sprintf("bad time period, use (%s|%s|%s)",
    82  		coveragedb.DayPeriod, coveragedb.MonthPeriod, coveragedb.QuarterPeriod),
    83  		fmt.Sprintf("^(%s|%s|%s)$", coveragedb.DayPeriod, coveragedb.MonthPeriod, coveragedb.QuarterPeriod))
    84  )
    85  
    86  type strValidationFunc func(string, ...string) Result
    87  
    88  func looksDangerous(s string) bool {
    89  	return strings.Contains(s, "--")
    90  }
    91  
    92  func makeStrReFunc(errStr, reStr string) strValidationFunc {
    93  	matchRe := regexp.MustCompile(reStr)
    94  	return func(s string, objName ...string) Result {
    95  		if s == "" {
    96  			return Result{false, wrapError(errStr + ": can't be empty")}
    97  		}
    98  		if looksDangerous(s) || !matchRe.MatchString(s) {
    99  			return Result{false, wrapError(errStr, objName...)}
   100  		}
   101  		return ResultOk
   102  	}
   103  }
   104  
   105  func makeStrLenFunc(errStr string, l int) strValidationFunc {
   106  	return func(s string, objName ...string) Result {
   107  		if len(s) != l {
   108  			return Result{false, wrapError(errStr, objName...)}
   109  		}
   110  		return ResultOk
   111  	}
   112  }
   113  
   114  func makeCombinedStrFunc(errStr string, funcs ...strValidationFunc) strValidationFunc {
   115  	return func(s string, objName ...string) Result {
   116  		for _, f := range funcs {
   117  			if res := f(s); !res.Ok {
   118  				return Result{false, wrapError(fmt.Sprintf(errStr+": %s", res.Err.Error()), objName...)}
   119  			}
   120  		}
   121  		return ResultOk
   122  	}
   123  }
   124  
   125  func wrapError(errStr string, prefix ...string) error {
   126  	if len(prefix) > 0 && prefix[0] != "" {
   127  		return fmt.Errorf("%s: %s", prefix[0], errStr)
   128  	}
   129  	return errors.New(errStr)
   130  }