Go Linter в стиле go vet чтобы найти неправильное использование reflect.SliceHeader и reflect.StringHeader , и небезопасные броски между структурами с полями размером с архитектуру.

go-safer сообщает о следующих шаблонах использования:
reflect.SliceHeader или reflect.StringHeader ,reflect.SliceHeader или reflect.StringHeader , который не был создан путем приготовления фактического среза или string , иint , uint или uintptrШаблон 1 идентифицирует код, который выглядит так:
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 ))
} Он также поймает случаи, когда reflect.SliceHeader был переименован, как в type MysteryType reflect.SliceHeader .
Шаблон 2 идентифицирует код, такой как следующее:
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 поймает назначения в объект типа reflect.SliceHeader . Используя график потока управления функции, он может видеть, что sH не был получен путем лишения реального среза (здесь вместо этого это nil ).
Шаблон 3 идентифицированные черты как следующие:
type A struct {
x int
}
type B struct {
y int64
}
func unsafeFunction ( a A ) B {
return * ( * B )( unsafe . Pointer ( & a ))
} Существует больше примеров по неправильному (сообщенному) и безопасному коду в тестовых случаях в каталогах passes/*/testdata/src .
Если reflect.SliceHeader или reflect.StringHeader не создается путем приготовления реального среза или string , то время выполнения GO не будет рассматривать поле Data в этих типах как ссылку на базовый массив данных. Поэтому, если коллекционер мусора работает непосредственно перед финальным актером из экземпляра буквального заголовка до реального ломтика или string , он может собрать исходный ломтик или string . Это может привести к уязвимости утечки информации.
Для получения более подробной информации, например, как эксплуатация подтверждения концепции и предложение для фиксированной версии этих небезопасных шаблонов, прочитайте этот блог: «Пост»: Golang Slice Header Header Data Prassication по реальному коду
Чтобы установить go-safer , используйте следующую команду:
go get github.com/jlauinger/go-safer
Это установит go-safer для $GOPATH/bin , поэтому убедитесь, что он включен в вашу переменную среды $PATH .
Заберитесь на сафе на таком пакете, как это:
$ go-safer example/cmd
Или подавать несколько пакетов, разделенных пространствами:
$ go-safer example/cmd example/util strings
Чтобы проверить пакет и, рекурсивно, все его импорт, использование ./... :
$ go-safer example/cmd/...
Наконец, чтобы проверить пакет в текущем каталоге, который вы можете использовать . :
$ go-safer .
go-safer принимает те же флаги, что и 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)
Поставляя флаг -help напечатает информацию об использовании для go-safer :
$ go-safer -help
Если ваш проект использует модули GO и файл go.mod , go-safer будет автоматически доставлять все зависимости, прежде чем он их анализирует. Это ведет себя точно так же, как go build .
Если вы используете другую форму управления зависимостями, например, go get , go mod vendor или что-то еще, вам необходимо запустить управление зависимостями, прежде чем запустить go-safer , чтобы все зависимости были актуальны перед анализом.
Чтобы получить исходный код и собрать двоичный, запустите это:
$ git clone https://github.com/jlauinger/go-safer
$ cd go-safer
$ go build
Для запуска тестовых сценарий Используйте следующую команду:
$ go test ./...
go-safer использует тестирующую инфраструктуру от golang.org/x/tools/go/analysis/analysistest . Чтобы добавить тестовый пример, создайте новый пакет в bad или good каталогах в passes/sliceheader/testdata/src . Добавьте столько файлов GO в пакет по мере необходимости.
Затем зарегистрируйте новый пакет в файле sliceheader_test.go , указав путь пакета.
В исходных файлах тестирования добавьте комментарии аннотации в строки, о которых следует сообщать (или нет). Комментарии должны выглядеть так:
sH.Len = strH.Len // want "assigning to reflect header object" "assigning to reflect header object"
fmt.Println("hello world") // ok
Аннотации, которые указывают на строку, о которой следует сообщать, должны начинаться с want , а затем иметь желаемое сообщение дважды. По какой-то причине инфраструктура тестирования заставит go-safer для вывода аннотации дважды, поэтому ее необходимо ожидать вдвое, чтобы пройти тест.
Тестовые примеры для прохода structcast могут быть добавлены аналогичным образом.
Поскольку go-safer построен на стандартной инфраструктуре Go Vet, вы можете импортировать проходы в свой собственный Linter на основе ветеринара.
Лицензирован по лицензии MIT («Лицензия»). Вы не можете использовать этот проект, кроме как в соответствии с лицензией. Вы можете получить копию лицензии здесь.
Copyright 2020 Johannes Lauinger
Этот инструмент был разработан в рамках диссертации моего мастера в группе программного обеспечения в Tu Darmstadt.