GO LINTER dans le style de go vet pour trouver des utilisations incorrectes de reflect.SliceHeader reflect.StringHeader

go-safer rapporte les modèles d'utilisation suivants:
reflect.SliceHeader reflect.StringHeaderreflect.StringHeader affectation à une instance string type reflect.SliceHeaderint , uint ou uintptrLe modèle 1 identifie le code qui ressemble à ceci:
func unsafeFunction ( s string ) [] byte {
sH := ( * reflect . StringHeader )( unsafe . Pointer ( & s ))
bH := & reflect. SliceHeader {
Data : sH . Data ,
Len : sH . Len ,
Cap : sH . Len ,
}
return * ( * [] byte )( unsafe . Pointer ( bH ))
} Il attrapera également des cas où reflect.SliceHeader a été renommé, comme dans type MysteryType reflect.SliceHeader .
Le modèle 2 identifie le code tel que les suivants:
func unsafeFunction ( s string ) [] byte {
strH := ( * reflect . StringHeader )( unsafe . Pointer ( & str ))
sH := ( * reflect . SliceHeader )( unsafe . Pointer ( nil ))
sH . Len = strH . Len
sH . Cap = strH . Len
sH . Data = strH . Data
return
} safer-go attrapera les affectations à un objet de type reflect.SliceHeader . En utilisant le graphique de flux de contrôle de la fonction, il peut voir que sH n'a pas été dérivé en jetant une véritable tranche (ici, il est nil à la place).
Le modèle 3 a identifié les moulages comme les suivants:
type A struct {
x int
}
type B struct {
y int64
}
func unsafeFunction ( a A ) B {
return * ( * B )( unsafe . Pointer ( & a ))
} Il y a plus d'exemples sur des répertoires incorrects (rapportés) et sûrs dans les cas de test dans les répertoires passes/*/testdata/src .
Si reflect.SliceHeader ou reflect.StringHeader n'est pas créé en jetant une tranche ou string réelle, alors le GO Runtime ne traitera pas le champ Data dans ces types comme une référence au tableau de données sous-jacent. Par conséquent, si le collecteur des ordures fonctionne juste avant le casting final de l'instance d'en-tête littérale à une véritable tranche ou string , il peut collecter la tranche ou string d'origine. Cela peut conduire à une vulnérabilité de fuite d'informations.
Pour plus de détails, comme un exploit de preuve de concept et une suggestion pour une version fixe de ces modèles dangereux, lisez cet article de blog: Golang Slice Header GC basé sur les données Confusion sur le code du monde réel
Pour installer go-safer , utilisez la commande suivante:
go get github.com/jlauinger/go-safer
Cela installera go-safer à $GOPATH/bin , alors assurez-vous qu'il est inclus dans votre variable d'environnement $PATH .
Exécutez Go-Safer sur un package comme celui-ci:
$ go-safer example/cmd
Ou fournit plusieurs packages, séparés par des espaces:
$ go-safer example/cmd example/util strings
Pour vérifier un package et, récursivement, toutes ses importations, utilisation ./... :
$ go-safer example/cmd/...
Enfin, pour vérifier le package dans le répertoire actuel que vous pouvez utiliser . :
$ go-safer .
go-safer accepte les mêmes drapeaux que go vet :
Flags:
-V print version and exit
-all
no effect (deprecated)
-c int
display offending line with this many lines of context (default -1)
-cpuprofile string
write CPU profile to this file
-debug string
debug flags, any subset of "fpstv"
-fix
apply all suggested fixes
-flags
print analyzer flags in JSON
-json
emit JSON output
-memprofile string
write memory profile to this file
-source
no effect (deprecated)
-tags string
no effect (deprecated)
-trace string
write trace log to this file
-v no effect (deprecated)
La fourniture du drapeau -help imprime les informations d'utilisation de go-safer :
$ go-safer -help
Si votre projet utilise des modules GO et un fichier go.mod , go-safer rapportera automatiquement toutes les dépendances avant de les analyser. Cela se comporte exactement comme go build .
Si vous utilisez une forme différente de gestion des dépendances, par exemple, manuel go get , go mod vendor ou autre chose, vous devez exécuter votre gestion de dépendance avant d'exécuter go-safer afin d'avoir toutes les dépendances à jour avant l'analyse.
Pour obtenir le code source et compiler le binaire, exécutez ceci:
$ git clone https://github.com/jlauinger/go-safer
$ cd go-safer
$ go build
Pour exécuter les cas de test, utilisez la commande suivante:
$ go test ./...
go-safer utilise l'infrastructure de test de golang.org/x/tools/go/analysis/analysistest . Pour ajouter un cas de test, créez un nouveau package dans les répertoires bad ou good dans passes/sliceheader/testdata/src . Ajoutez autant de fichiers GO au package au besoin.
Ensuite, enregistrez le nouveau package dans le fichier sliceheader_test.go en spécifiant le chemin du package.
Dans les fichiers de source de cas de test, ajoutez des commentaires d'annotation aux lignes qui doivent être signalées (ou non). Les commentaires doivent ressembler à ceci:
sH.Len = strH.Len // want "assigning to reflect header object" "assigning to reflect header object"
fmt.Println("hello world") // ok
Les annotations qui indiquent une ligne qui doit être signalée doit commencer par want et ensuite avoir le message souhaité deux fois. Pour une raison quelconque, l'infrastructure d'essai entraînera deux fois go-safer pour produire l'annotation, il faut donc s'attendre à passer deux fois aussi bien pour passer le test.
Les cas de test pour le pass structcast peuvent être ajoutés de manière similaire.
Étant donné que go-safer est construit sur l'infrastructure standard GO VET, vous pouvez importer les passes dans votre propre Linter basé sur GO VET.
Licencié en vertu de la licence du MIT (la "licence"). Vous ne pouvez pas utiliser ce projet sauf conforme à la licence. Vous pouvez obtenir une copie de la licence ici.
Copyright 2020 Johannes Lauinger
Cet outil a été développé dans le cadre de ma thèse de maîtrise au Software Technology Group de Tu Darmstadt.