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 }