Vá Linter no estilo de go vet para encontrar usos incorretos do reflect.SliceHeader e reflect.StringHeader , e elencos inseguros entre estruturas com campos do tamanho de arquitetura.

go-safer relata os seguintes padrões de uso:
reflect.SliceHeader ou reflect.StringHeader ,reflect.SliceHeader ou reflect.StringHeader que não foi criado lançando uma fatia ou string real, eint , uint ou uintptrO padrão 1 identifica o código que se parece com o seguinte:
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 ))
} Ele também capturará casos em que reflect.SliceHeader foi renomeado, como no type MysteryType reflect.SliceHeader .
O padrão 2 identifica código como o seguinte:
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 captura as atribuições a um objeto de tipo reflect.SliceHeader . Usando o gráfico de fluxo de controle da função, pode ver que sH não foi derivado lançando uma fatia real (aqui está nil ).
Padrão 3 Identificou Casts como os seguintes:
type A struct {
x int
}
type B struct {
y int64
}
func unsafeFunction ( a A ) B {
return * ( * B )( unsafe . Pointer ( & a ))
} Existem mais exemplos em código incorreto (relatado) e seguro nos casos de teste nos diretórios de passes/*/testdata/src .
Se reflect.SliceHeader ou reflect.StringHeader não for criado lançando uma fatia ou string real, o tempo de execução Go não tratará o campo Data nesses tipos como uma referência à matriz de dados subjacente. Portanto, se o coletor de lixo for executado imediatamente antes do elenco final da instância do cabeçalho literal para uma fatia ou string real, poderá coletar a fatia ou a string original. Isso pode levar a uma vulnerabilidade de vazamento de informações.
Para obter mais detalhes, como uma exploração de prova de conceito e uma sugestão para uma versão fixa desses padrões inseguros, leia esta postagem do blog: Golang Slice Cabeçalho GC Confusão de dados no código do mundo real
Para instalar go-safer , use o seguinte comando:
go get github.com/jlauinger/go-safer
Isso instalará go-safer em $GOPATH/bin , portanto, verifique se ele está incluído na sua variável de ambiente $PATH .
Run Go-Safer em um pacote como este:
$ go-safer example/cmd
Ou forneça vários pacotes, separados por espaços:
$ go-safer example/cmd example/util strings
Para verificar um pacote e, recursivamente, todas as suas importações, use ./... :
$ go-safer example/cmd/...
Por fim, para verificar o pacote no diretório atual que você pode usar . :
$ go-safer .
go-safer aceita as mesmas bandeiras 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)
O fornecimento da bandeira -help imprime as informações de uso para go-safer :
$ go-safer -help
Se o seu projeto usar módulos Go e um arquivo go.mod , go-safer buscará todas as dependências automaticamente antes de analisá-las. Ele se comporta exatamente como go build .
Se você usar uma forma diferente de gerenciamento de dependência, por exemplo, manual, go get , go mod vendor ou qualquer outra coisa, precisará executar seu gerenciamento de dependência antes de executar go-safer para ter todas as dependências atualizadas antes da análise.
Para obter o código -fonte e compilar o binário, execute o seguinte:
$ git clone https://github.com/jlauinger/go-safer
$ cd go-safer
$ go build
Para executar os casos de teste, use o seguinte comando:
$ go test ./...
go-safer usa a infraestrutura de teste em golang.org/x/tools/go/analysis/analysistest . Para adicionar um caso de teste, crie um novo pacote dentro dos diretórios bad ou good em passes/sliceheader/testdata/src . Adicione tantos arquivos Go ao pacote conforme necessário.
Em seguida, registre o novo pacote no arquivo sliceheader_test.go especificando o caminho do pacote.
Nos arquivos de origem do caso de teste, adicione comentários de anotação às linhas que devem ser relatadas (ou não). Os comentários devem ser assim:
sH.Len = strH.Len // want "assigning to reflect header object" "assigning to reflect header object"
fmt.Println("hello world") // ok
As anotações que indicam uma linha que devem ser relatadas devem começar com want e, em seguida, ter a mensagem desejada duas vezes. Por algum motivo, a infraestrutura de teste fará com que go-safer emitirá a anotação duas vezes, portanto, é necessário ter duas vezes também para passar no teste.
Os casos de teste para o passe structcast podem ser adicionados da mesma forma.
Como go-safer é construída sobre a infraestrutura padrão do GO, você pode importar os passes para o seu próprio linhador baseado em veterinário.
Licenciado sob a licença do MIT (a "licença"). Você não pode usar este projeto, exceto em conformidade com a licença. Você pode obter uma cópia da licença aqui.
Copyright 2020 Johannes Lauinger
Essa ferramenta foi desenvolvida como parte da tese de meu mestrado no grupo de tecnologia de software da TU Darmstadt.