Refactor command line interface
This commit is contained in:
parent
935266c850
commit
2f52f6db6d
27
debug.go
27
debug.go
@ -19,6 +19,33 @@ import (
|
|||||||
"code.dumpstack.io/tools/out-of-tree/qemu"
|
"code.dumpstack.io/tools/out-of-tree/qemu"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type DebugCmd struct {
|
||||||
|
Kernel string `help:"regexp (first match)" required:""`
|
||||||
|
Gdb string `help:"gdb listen address" default:"tcp::1234"`
|
||||||
|
|
||||||
|
Kaslr bool `help:"Enable KASLR"`
|
||||||
|
Smep bool `help:"Enable SMEP"`
|
||||||
|
Smap bool `help:"Enable SMAP"`
|
||||||
|
Kpti bool `help:"Enable KPTI"`
|
||||||
|
|
||||||
|
NoKaslr bool `help:"Disable KASLR"`
|
||||||
|
NoSmep bool `help:"Disable SMEP"`
|
||||||
|
NoSmap bool `help:"Disable SMAP"`
|
||||||
|
NoKpti bool `help:"Disable KPTI"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cmd *DebugCmd) Run(g *Globals) (err error) {
|
||||||
|
kcfg, err := config.ReadKernelConfig(g.Config.Kernels)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return debugHandler(kcfg, g.WorkDir, cmd.Kernel, cmd.Gdb,
|
||||||
|
g.Config.Docker.Timeout.Duration,
|
||||||
|
cmd.Kaslr, cmd.Smep, cmd.Smap, cmd.Kpti,
|
||||||
|
cmd.NoKaslr, cmd.NoSmep, cmd.NoSmap, cmd.NoKpti)
|
||||||
|
}
|
||||||
|
|
||||||
func firstSupported(kcfg config.KernelConfig, ka config.Artifact,
|
func firstSupported(kcfg config.KernelConfig, ka config.Artifact,
|
||||||
kernel string) (ki config.KernelInfo, err error) {
|
kernel string) (ki config.KernelInfo, err error) {
|
||||||
|
|
||||||
|
14
gen.go
14
gen.go
@ -12,6 +12,20 @@ import (
|
|||||||
"code.dumpstack.io/tools/out-of-tree/config"
|
"code.dumpstack.io/tools/out-of-tree/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type GenCmd struct {
|
||||||
|
Type string `enum:"module,exploit" required:"" help:"module/exploit"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cmd *GenCmd) Run(g *Globals) (err error) {
|
||||||
|
switch cmd.Type {
|
||||||
|
case "module":
|
||||||
|
err = genConfig(config.KernelModule)
|
||||||
|
case "exploit":
|
||||||
|
err = genConfig(config.KernelExploit)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func genConfig(at config.ArtifactType) (err error) {
|
func genConfig(at config.ArtifactType) (err error) {
|
||||||
a := config.Artifact{
|
a := config.Artifact{
|
||||||
Name: "Put name here",
|
Name: "Put name here",
|
||||||
|
206
kernel.go
206
kernel.go
@ -24,18 +24,133 @@ import (
|
|||||||
"code.dumpstack.io/tools/out-of-tree/config"
|
"code.dumpstack.io/tools/out-of-tree/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
const kernelsAll int64 = math.MaxInt64
|
type KernelCmd struct {
|
||||||
|
NoDownload bool `help:"do not download qemu image while kernel generation"`
|
||||||
|
UseHost bool `help:"also use host kernels"`
|
||||||
|
|
||||||
|
List KernelListCmd `cmd:"" help:"list kernels"`
|
||||||
|
Autogen KernelAutogenCmd `cmd:"" help:"generate kernels based on the current config"`
|
||||||
|
DockerRegen KernelDockerRegenCmd `cmd:"" help:"regenerate kernels config from out_of_tree_* docker images"`
|
||||||
|
Genall KernelGenallCmd `cmd:"" help:"generate all kernels for distro"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type KernelListCmd struct{}
|
||||||
|
|
||||||
|
func (cmd *KernelListCmd) Run(g *Globals) (err error) {
|
||||||
|
kcfg, err := config.ReadKernelConfig(g.Config.Kernels)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func kernelListHandler(kcfg config.KernelConfig) (err error) {
|
|
||||||
if len(kcfg.Kernels) == 0 {
|
if len(kcfg.Kernels) == 0 {
|
||||||
return errors.New("No kernels found")
|
return errors.New("No kernels found")
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, k := range kcfg.Kernels {
|
for _, k := range kcfg.Kernels {
|
||||||
fmt.Println(k.DistroType, k.DistroRelease, k.KernelRelease)
|
fmt.Println(k.DistroType, k.DistroRelease, k.KernelRelease)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type KernelAutogenCmd struct {
|
||||||
|
Max int64 `help:"download random kernels from set defined by regex in release_mask, but no more than X for each of release_mask" default:"100500"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func kernelAutogenHandler(workPath, registry string,
|
||||||
|
commands []config.DockerCommand,
|
||||||
|
max int64, host, download bool) (err error) {
|
||||||
|
return errors.New("MEH")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cmd *KernelAutogenCmd) Run(kernelCmd *KernelCmd, g *Globals) (err error) {
|
||||||
|
ka, err := config.ReadArtifactConfig(g.WorkDir + "/.out-of-tree.toml")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, sk := range ka.SupportedKernels {
|
||||||
|
if sk.DistroRelease == "" {
|
||||||
|
err = errors.New("Please set distro_release")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = generateKernels(sk, g.Config.Docker.Registry, g.Config.Docker.Commands, cmd.Max, !kernelCmd.NoDownload)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return updateKernelsCfg(kernelCmd.UseHost, !kernelCmd.NoDownload)
|
||||||
|
}
|
||||||
|
|
||||||
|
type KernelDockerRegenCmd struct{}
|
||||||
|
|
||||||
|
func (cmd *KernelDockerRegenCmd) Run(kernelCmd *KernelCmd, g *Globals) (err error) {
|
||||||
|
dockerImages, err := listDockerImages()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, d := range dockerImages {
|
||||||
|
var imagePath string
|
||||||
|
imagePath, err = dockerImagePath(config.KernelMask{
|
||||||
|
DistroType: d.DistroType,
|
||||||
|
DistroRelease: d.DistroRelease,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := exec.Command("docker", "build", "-t",
|
||||||
|
d.ContainerName, imagePath)
|
||||||
|
var rawOutput []byte
|
||||||
|
rawOutput, err = cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
log.Println("docker build:", string(rawOutput))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = kickImage(d.ContainerName)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("kick image", d.ContainerName, ":", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
err = copyKernels(d.ContainerName)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("copy kernels", d.ContainerName, ":", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return updateKernelsCfg(kernelCmd.UseHost, !kernelCmd.NoDownload)
|
||||||
|
}
|
||||||
|
|
||||||
|
type KernelGenallCmd struct {
|
||||||
|
Distro string `required:"" help:"distribution"`
|
||||||
|
Ver string `required:"" help:"distro version"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cmd *KernelGenallCmd) Run(kernelCmd *KernelCmd, g *Globals) (err error) {
|
||||||
|
distroType, err := config.NewDistroType(cmd.Distro)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
km := config.KernelMask{
|
||||||
|
DistroType: distroType,
|
||||||
|
DistroRelease: cmd.Ver,
|
||||||
|
ReleaseMask: ".*",
|
||||||
|
}
|
||||||
|
err = generateKernels(km, g.Config.Docker.Registry, g.Config.Docker.Commands, math.MaxInt64, !kernelCmd.NoDownload)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return updateKernelsCfg(kernelCmd.UseHost, !kernelCmd.NoDownload)
|
||||||
|
}
|
||||||
|
|
||||||
func matchDebianHeadersPkg(container, mask string, generic bool) (
|
func matchDebianHeadersPkg(container, mask string, generic bool) (
|
||||||
pkgs []string, err error) {
|
pkgs []string, err error) {
|
||||||
|
|
||||||
@ -637,90 +752,3 @@ func generateKernels(km config.KernelMask, registry string,
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func kernelAutogenHandler(workPath, registry string,
|
|
||||||
commands []config.DockerCommand,
|
|
||||||
max int64, host, download bool) (err error) {
|
|
||||||
|
|
||||||
ka, err := config.ReadArtifactConfig(workPath + "/.out-of-tree.toml")
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, sk := range ka.SupportedKernels {
|
|
||||||
if sk.DistroRelease == "" {
|
|
||||||
err = errors.New("Please set distro_release")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = generateKernels(sk, registry, commands, max, download)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = updateKernelsCfg(host, download)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func kernelDockerRegenHandler(host, download bool) (err error) {
|
|
||||||
dockerImages, err := listDockerImages()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, d := range dockerImages {
|
|
||||||
var imagePath string
|
|
||||||
imagePath, err = dockerImagePath(config.KernelMask{
|
|
||||||
DistroType: d.DistroType,
|
|
||||||
DistroRelease: d.DistroRelease,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd := exec.Command("docker", "build", "-t",
|
|
||||||
d.ContainerName, imagePath)
|
|
||||||
var rawOutput []byte
|
|
||||||
rawOutput, err = cmd.CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
log.Println("docker build:", string(rawOutput))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = kickImage(d.ContainerName)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("kick image", d.ContainerName, ":", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
err = copyKernels(d.ContainerName)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("copy kernels", d.ContainerName, ":", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return updateKernelsCfg(host, download)
|
|
||||||
}
|
|
||||||
|
|
||||||
func kernelGenallHandler(distro, version, registry string,
|
|
||||||
commands []config.DockerCommand, host, download bool) (err error) {
|
|
||||||
|
|
||||||
distroType, err := config.NewDistroType(distro)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
km := config.KernelMask{
|
|
||||||
DistroType: distroType,
|
|
||||||
DistroRelease: version,
|
|
||||||
ReleaseMask: ".*",
|
|
||||||
}
|
|
||||||
err = generateKernels(km, registry, commands, kernelsAll, download)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return updateKernelsCfg(host, download)
|
|
||||||
}
|
|
||||||
|
209
log.go
209
log.go
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2019 Mikhail Klementev. All rights reserved.
|
// Copyright 2023 Mikhail Klementev. All rights reserved.
|
||||||
// Use of this source code is governed by a AGPLv3 license
|
// Use of this source code is governed by a AGPLv3 license
|
||||||
// (or later) that can be found in the LICENSE file.
|
// (or later) that can be found in the LICENSE file.
|
||||||
|
|
||||||
@ -18,56 +18,41 @@ import (
|
|||||||
"code.dumpstack.io/tools/out-of-tree/config"
|
"code.dumpstack.io/tools/out-of-tree/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
func logLogEntry(l logEntry) {
|
type LogCmd struct {
|
||||||
distroInfo := fmt.Sprintf("%s-%s {%s}", l.DistroType,
|
Query LogQueryCmd `cmd:"" help:"query logs"`
|
||||||
l.DistroRelease, l.KernelRelease)
|
Dump LogDumpCmd `cmd:"" help:"show all info for log entry with ID"`
|
||||||
|
Json LogJsonCmd `cmd:"" help:"generate json statistics"`
|
||||||
artifactInfo := fmt.Sprintf("{[%s] %s}", l.Type, l.Name)
|
Makrdown LogMarkdownCmd `cmd:"" help:"generate markdown statistics"`
|
||||||
|
|
||||||
colored := ""
|
|
||||||
if l.Type == config.KernelExploit {
|
|
||||||
colored = aurora.Sprintf("[%4d %4s] [%s] %40s %40s: %s %s",
|
|
||||||
l.ID, l.Tag, l.Timestamp, artifactInfo, distroInfo,
|
|
||||||
genOkFail("BUILD", l.Build.Ok),
|
|
||||||
genOkFail("LPE", l.Test.Ok))
|
|
||||||
} else {
|
|
||||||
colored = aurora.Sprintf("[%4d %4s] [%s] %40s %40s: %s %s %s",
|
|
||||||
l.ID, l.Tag, l.Timestamp, artifactInfo, distroInfo,
|
|
||||||
genOkFail("BUILD", l.Build.Ok),
|
|
||||||
genOkFail("INSMOD", l.Run.Ok),
|
|
||||||
genOkFail("TEST", l.Test.Ok))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
additional := ""
|
type LogQueryCmd struct {
|
||||||
if l.KernelPanic {
|
Num int `help:"how much lines" default:"50"`
|
||||||
additional = "(panic)"
|
Rate bool `help:"show artifact success rate"`
|
||||||
} else if l.KilledByTimeout {
|
Tag string `help:"filter tag"`
|
||||||
additional = "(timeout)"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if additional != "" {
|
func (cmd *LogQueryCmd) Run(g *Globals) (err error) {
|
||||||
fmt.Println(colored, additional)
|
db, err := openDatabase(g.Config.Database)
|
||||||
} else {
|
if err != nil {
|
||||||
fmt.Println(colored)
|
log.Fatalln(err)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
func logHandler(db *sql.DB, path, tag string, num int, rate bool) (err error) {
|
|
||||||
var les []logEntry
|
var les []logEntry
|
||||||
|
|
||||||
ka, kaErr := config.ReadArtifactConfig(path + "/.out-of-tree.toml")
|
ka, kaErr := config.ReadArtifactConfig(g.WorkDir + "/.out-of-tree.toml")
|
||||||
if kaErr == nil {
|
if kaErr == nil {
|
||||||
log.Println(".out-of-tree.toml found, filter by artifact name")
|
log.Println(".out-of-tree.toml found, filter by artifact name")
|
||||||
les, err = getAllArtifactLogs(db, tag, num, ka)
|
les, err = getAllArtifactLogs(db, cmd.Tag, cmd.Num, ka)
|
||||||
} else {
|
} else {
|
||||||
les, err = getAllLogs(db, tag, num)
|
les, err = getAllLogs(db, cmd.Tag, cmd.Num)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s := "\nS"
|
s := "\nS"
|
||||||
if rate {
|
if cmd.Rate {
|
||||||
if kaErr != nil {
|
if kaErr != nil {
|
||||||
err = kaErr
|
err = kaErr
|
||||||
return
|
return
|
||||||
@ -75,7 +60,7 @@ func logHandler(db *sql.DB, path, tag string, num int, rate bool) (err error) {
|
|||||||
|
|
||||||
s = fmt.Sprintf("{[%s] %s} Overall s", ka.Type, ka.Name)
|
s = fmt.Sprintf("{[%s] %s} Overall s", ka.Type, ka.Name)
|
||||||
|
|
||||||
les, err = getAllArtifactLogs(db, tag, math.MaxInt64, ka)
|
les, err = getAllArtifactLogs(db, cmd.Tag, math.MaxInt64, ka)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -99,10 +84,20 @@ func logHandler(db *sql.DB, path, tag string, num int, rate bool) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func logDumpHandler(db *sql.DB, id int) (err error) {
|
type LogDumpCmd struct {
|
||||||
|
ID int `help:"id" default:"-1"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cmd *LogDumpCmd) Run(g *Globals) (err error) {
|
||||||
|
db, err := openDatabase(g.Config.Database)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
var l logEntry
|
var l logEntry
|
||||||
if id > 0 {
|
if cmd.ID > 0 {
|
||||||
l, err = getLogByID(db, id)
|
l, err = getLogByID(db, cmd.ID)
|
||||||
} else {
|
} else {
|
||||||
l, err = getLastLog(db)
|
l, err = getLastLog(db)
|
||||||
}
|
}
|
||||||
@ -150,6 +145,102 @@ func logDumpHandler(db *sql.DB, id int) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LogJsonCmd struct {
|
||||||
|
Tag string `required:"" help:"filter tag"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cmd *LogJsonCmd) Run(g *Globals) (err error) {
|
||||||
|
db, err := openDatabase(g.Config.Database)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
distros, err := getStats(db, g.WorkDir, cmd.Tag)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes, err := json.Marshal(&distros)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(string(bytes))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type LogMarkdownCmd struct {
|
||||||
|
Tag string `required:"" help:"filter tag"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cmd *LogMarkdownCmd) Run(g *Globals) (err error) {
|
||||||
|
db, err := openDatabase(g.Config.Database)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
distros, err := getStats(db, g.WorkDir, cmd.Tag)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
table := tablewriter.NewWriter(os.Stdout)
|
||||||
|
table.SetHeader([]string{"Distro", "Release", "Kernel", "Reliability"})
|
||||||
|
table.SetBorders(tablewriter.Border{
|
||||||
|
Left: true, Top: false, Right: true, Bottom: false})
|
||||||
|
table.SetCenterSeparator("|")
|
||||||
|
|
||||||
|
for distro, releases := range distros {
|
||||||
|
for release, kernels := range releases {
|
||||||
|
for kernel, stats := range kernels {
|
||||||
|
all := float64(stats.All)
|
||||||
|
ok := float64(stats.TestOK)
|
||||||
|
r := fmt.Sprintf("%6.02f%%", (ok/all)*100)
|
||||||
|
table.Append([]string{distro, release, kernel, r})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
table.Render()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func logLogEntry(l logEntry) {
|
||||||
|
distroInfo := fmt.Sprintf("%s-%s {%s}", l.DistroType,
|
||||||
|
l.DistroRelease, l.KernelRelease)
|
||||||
|
|
||||||
|
artifactInfo := fmt.Sprintf("{[%s] %s}", l.Type, l.Name)
|
||||||
|
|
||||||
|
colored := ""
|
||||||
|
if l.Type == config.KernelExploit {
|
||||||
|
colored = aurora.Sprintf("[%4d %4s] [%s] %40s %40s: %s %s",
|
||||||
|
l.ID, l.Tag, l.Timestamp, artifactInfo, distroInfo,
|
||||||
|
genOkFail("BUILD", l.Build.Ok),
|
||||||
|
genOkFail("LPE", l.Test.Ok))
|
||||||
|
} else {
|
||||||
|
colored = aurora.Sprintf("[%4d %4s] [%s] %40s %40s: %s %s %s",
|
||||||
|
l.ID, l.Tag, l.Timestamp, artifactInfo, distroInfo,
|
||||||
|
genOkFail("BUILD", l.Build.Ok),
|
||||||
|
genOkFail("INSMOD", l.Run.Ok),
|
||||||
|
genOkFail("TEST", l.Test.Ok))
|
||||||
|
}
|
||||||
|
|
||||||
|
additional := ""
|
||||||
|
if l.KernelPanic {
|
||||||
|
additional = "(panic)"
|
||||||
|
} else if l.KilledByTimeout {
|
||||||
|
additional = "(timeout)"
|
||||||
|
}
|
||||||
|
|
||||||
|
if additional != "" {
|
||||||
|
fmt.Println(colored, additional)
|
||||||
|
} else {
|
||||||
|
fmt.Println(colored)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type runstat struct {
|
type runstat struct {
|
||||||
All, BuildOK, RunOK, TestOK, Timeout, Panic int
|
All, BuildOK, RunOK, TestOK, Timeout, Panic int
|
||||||
}
|
}
|
||||||
@ -206,45 +297,3 @@ func getStats(db *sql.DB, path, tag string) (
|
|||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func logJSONHandler(db *sql.DB, path, tag string) (err error) {
|
|
||||||
distros, err := getStats(db, path, tag)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes, err := json.Marshal(&distros)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println(string(bytes))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func logMarkdownHandler(db *sql.DB, path, tag string) (err error) {
|
|
||||||
distros, err := getStats(db, path, tag)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
table := tablewriter.NewWriter(os.Stdout)
|
|
||||||
table.SetHeader([]string{"Distro", "Release", "Kernel", "Reliability"})
|
|
||||||
table.SetBorders(tablewriter.Border{
|
|
||||||
Left: true, Top: false, Right: true, Bottom: false})
|
|
||||||
table.SetCenterSeparator("|")
|
|
||||||
|
|
||||||
for distro, releases := range distros {
|
|
||||||
for release, kernels := range releases {
|
|
||||||
for kernel, stats := range kernels {
|
|
||||||
all := float64(stats.All)
|
|
||||||
ok := float64(stats.TestOK)
|
|
||||||
r := fmt.Sprintf("%6.02f%%", (ok/all)*100)
|
|
||||||
table.Append([]string{distro, release, kernel, r})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
table.Render()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
363
main.go
363
main.go
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2018 Mikhail Klementev. All rights reserved.
|
// Copyright 2023 Mikhail Klementev. All rights reserved.
|
||||||
// Use of this source code is governed by a AGPLv3 license
|
// Use of this source code is governed by a AGPLv3 license
|
||||||
// (or later) that can be found in the LICENSE file.
|
// (or later) that can be found in the LICENSE file.
|
||||||
|
|
||||||
@ -8,69 +8,40 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"os/user"
|
|
||||||
"runtime"
|
|
||||||
"sort"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
kingpin "gopkg.in/alecthomas/kingpin.v2"
|
"github.com/alecthomas/kong"
|
||||||
|
|
||||||
"code.dumpstack.io/tools/out-of-tree/config"
|
"code.dumpstack.io/tools/out-of-tree/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
func findFallback(kcfg config.KernelConfig, ki config.KernelInfo) (rootfs string) {
|
type Globals struct {
|
||||||
for _, k := range kcfg.Kernels {
|
Config config.OutOfTree `help:"path to out-of-tree configuration" default:"~/.out-of-tree/out-of-tree.toml"`
|
||||||
if !exists(k.RootFS) || k.DistroType != ki.DistroType {
|
|
||||||
continue
|
WorkDir string `help:"path to work directory" default:"./" type:"path"`
|
||||||
}
|
|
||||||
if k.RootFS < ki.RootFS {
|
|
||||||
rootfs = k.RootFS
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleFallbacks(kcfg config.KernelConfig) {
|
type CLI struct {
|
||||||
sort.Sort(sort.Reverse(config.ByRootFS(kcfg.Kernels)))
|
Globals
|
||||||
|
|
||||||
for i, k := range kcfg.Kernels {
|
Pew PewCmd `cmd:"" help:"build, run, and test module/exploit"`
|
||||||
if !exists(k.RootFS) {
|
Kernel KernelCmd `cmd:"" help:"manipulate kernels"`
|
||||||
newRootFS := findFallback(kcfg, k)
|
Debug DebugCmd `cmd:"" help:"debug environment"`
|
||||||
|
Log LogCmd `cmd:"" help:"query logs"`
|
||||||
|
Pack PackCmd `cmd:"" help:"exploit pack test"`
|
||||||
|
Gen GenCmd `cmd:"" help:"generate .out-of-tree.toml skeleton"`
|
||||||
|
|
||||||
s := k.RootFS + " does not exists "
|
Version VersionFlag `name:"version" help:"print version information and quit"`
|
||||||
if newRootFS != "" {
|
|
||||||
s += "(fallback to " + newRootFS + ")"
|
|
||||||
} else {
|
|
||||||
s += "(no fallback found)"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
kcfg.Kernels[i].RootFS = newRootFS
|
type VersionFlag string
|
||||||
log.Println(s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkRequiredUtils() (err error) {
|
func (v VersionFlag) Decode(ctx *kong.DecodeContext) error { return nil }
|
||||||
// Check for required commands
|
func (v VersionFlag) IsBool() bool { return true }
|
||||||
for _, cmd := range []string{"docker", "qemu-system-x86_64"} {
|
func (v VersionFlag) BeforeApply(app *kong.Kong, vars kong.Vars) error {
|
||||||
_, err := exec.Command("which", cmd).CombinedOutput()
|
fmt.Println(vars["version"])
|
||||||
if err != nil {
|
app.Exit(0)
|
||||||
return fmt.Errorf("Command not found: %s", cmd)
|
return nil
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkDockerPermissions() (err error) {
|
|
||||||
output, err := exec.Command("docker", "ps").CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
err = fmt.Errorf("%s", output)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -78,283 +49,19 @@ func main() {
|
|||||||
|
|
||||||
rand.Seed(time.Now().UnixNano())
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
|
||||||
app := kingpin.New(
|
cli := CLI{}
|
||||||
"out-of-tree",
|
ctx := kong.Parse(&cli,
|
||||||
"kernel {module, exploit} development tool",
|
kong.Name("out-of-tree"),
|
||||||
|
kong.Description("kernel {module, exploit} development tool"),
|
||||||
|
kong.UsageOnError(),
|
||||||
|
kong.ConfigureHelp(kong.HelpOptions{
|
||||||
|
Compact: true,
|
||||||
|
}),
|
||||||
|
kong.Vars{
|
||||||
|
"version": "1.4.0",
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
app.Author("Mikhail Klementev <root@dumpstack.io>")
|
err := ctx.Run(&cli.Globals)
|
||||||
app.Version("1.4.0")
|
ctx.FatalIfErrorf(err)
|
||||||
|
|
||||||
pathFlag := app.Flag("path", "Path to work directory")
|
|
||||||
path := pathFlag.Default(".").ExistingDir()
|
|
||||||
|
|
||||||
usr, err := user.Current()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
os.MkdirAll(usr.HomeDir+"/.out-of-tree", os.ModePerm)
|
|
||||||
|
|
||||||
confPath := usr.HomeDir + "/.out-of-tree/out-of-tree.toml"
|
|
||||||
conf, err := config.ReadOutOfTreeConf(confPath)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
kcfgPathFlag := app.Flag("kernels", "Path to main kernels config")
|
|
||||||
kcfgPath := kcfgPathFlag.Default(conf.Kernels).String()
|
|
||||||
|
|
||||||
dbPathFlag := app.Flag("db", "Path to database")
|
|
||||||
dbPath := dbPathFlag.Default(conf.Database).String()
|
|
||||||
|
|
||||||
userKcfgPathFlag := app.Flag("user-kernels", "User kernels config")
|
|
||||||
userKcfgPathEnv := userKcfgPathFlag.Envar("OUT_OF_TREE_KCFG")
|
|
||||||
userKcfgPath := userKcfgPathEnv.Default(conf.UserKernels).String()
|
|
||||||
|
|
||||||
timeoutFlag := app.Flag("timeout", "Timeout after tool will not spawn new tests")
|
|
||||||
timeout := timeoutFlag.Duration()
|
|
||||||
|
|
||||||
qemuTimeoutFlag := app.Flag("qemu-timeout", "Timeout for qemu")
|
|
||||||
qemuTimeout := qemuTimeoutFlag.Default(conf.Qemu.Timeout).Duration()
|
|
||||||
|
|
||||||
dockerTimeoutFlag := app.Flag("docker-timeout", "Timeout for docker")
|
|
||||||
dockerTimeout := dockerTimeoutFlag.Default(conf.Docker.Timeout).Duration()
|
|
||||||
|
|
||||||
dockerRegistryFlag := app.Flag("docker-registry", "Registry for docker")
|
|
||||||
dockerRegistry := dockerRegistryFlag.Default(conf.Docker.Registry).String()
|
|
||||||
|
|
||||||
thresholdFlag := app.Flag("threshold", "Reliablity threshold for exit code")
|
|
||||||
threshold := thresholdFlag.Default("1.00").Float64()
|
|
||||||
|
|
||||||
disablePreloadFlag := app.Flag("disable-preload", "Disable module preload")
|
|
||||||
disablePreload = disablePreloadFlag.Bool()
|
|
||||||
|
|
||||||
pewCommand := app.Command("pew", "Build, run and test module/exploit")
|
|
||||||
|
|
||||||
pewMax := pewCommand.Flag("max", "Test no more than X kernels").
|
|
||||||
PlaceHolder("X").Default(fmt.Sprint(kernelsAll)).Int64()
|
|
||||||
|
|
||||||
pewRuns := pewCommand.Flag("runs", "Runs per each kernel").
|
|
||||||
Default("1").Int64()
|
|
||||||
|
|
||||||
pewKernelFlag := pewCommand.Flag("kernel", "Override kernel regex")
|
|
||||||
pewKernel := pewKernelFlag.String()
|
|
||||||
|
|
||||||
pewGuessFlag := pewCommand.Flag("guess", "Try all defined kernels")
|
|
||||||
pewGuess := pewGuessFlag.Bool()
|
|
||||||
|
|
||||||
pewBinaryFlag := pewCommand.Flag("binary", "Use binary, do not build")
|
|
||||||
pewBinary := pewBinaryFlag.String()
|
|
||||||
|
|
||||||
pewTestFlag := pewCommand.Flag("test", "Override path test")
|
|
||||||
pewTest := pewTestFlag.String()
|
|
||||||
|
|
||||||
pewDistFlag := pewCommand.Flag("dist", "Build result path")
|
|
||||||
pewDist := pewDistFlag.Default(pathDevNull).String()
|
|
||||||
|
|
||||||
pewThreadsFlag := pewCommand.Flag("threads", "Build result path")
|
|
||||||
pewThreads := pewThreadsFlag.Default(strconv.Itoa(runtime.NumCPU())).Int()
|
|
||||||
|
|
||||||
pewTagFlag := pewCommand.Flag("tag", "Log tagging")
|
|
||||||
pewTag := pewTagFlag.String()
|
|
||||||
|
|
||||||
pewVerboseFlag := pewCommand.Flag("verbose", "Show more information")
|
|
||||||
pewVerbose := pewVerboseFlag.Bool()
|
|
||||||
|
|
||||||
kernelCommand := app.Command("kernel", "Manipulate kernels")
|
|
||||||
kernelNoDownload := kernelCommand.Flag("no-download",
|
|
||||||
"Do not download qemu image while kernel generation").Bool()
|
|
||||||
kernelUseHost := kernelCommand.Flag("host", "Use also host kernels").Bool()
|
|
||||||
kernelListCommand := kernelCommand.Command("list", "List kernels")
|
|
||||||
kernelAutogenCommand := kernelCommand.Command("autogen",
|
|
||||||
"Generate kernels based on a current config")
|
|
||||||
kernelAutogenMax := kernelAutogenCommand.Flag("max",
|
|
||||||
"Download random kernels from set defined by regex in "+
|
|
||||||
"release_mask, but no more than X for each of "+
|
|
||||||
"release_mask").PlaceHolder("X").Default(
|
|
||||||
fmt.Sprint(kernelsAll)).Int64()
|
|
||||||
kernelDockerRegenCommand := kernelCommand.Command("docker-regen",
|
|
||||||
"Regenerate kernels config from out_of_tree_* docker images")
|
|
||||||
kernelGenallCommand := kernelCommand.Command("genall",
|
|
||||||
"Generate all kernels for distro")
|
|
||||||
|
|
||||||
genallDistroFlag := kernelGenallCommand.Flag("distro", "Distributive")
|
|
||||||
distro := genallDistroFlag.Required().String()
|
|
||||||
|
|
||||||
genallVerFlag := kernelGenallCommand.Flag("ver", "Distro version")
|
|
||||||
version := genallVerFlag.Required().String()
|
|
||||||
|
|
||||||
genCommand := app.Command("gen", "Generate .out-of-tree.toml skeleton")
|
|
||||||
genModuleCommand := genCommand.Command("module",
|
|
||||||
"Generate .out-of-tree.toml skeleton for kernel module")
|
|
||||||
genExploitCommand := genCommand.Command("exploit",
|
|
||||||
"Generate .out-of-tree.toml skeleton for kernel exploit")
|
|
||||||
|
|
||||||
debugCommand := app.Command("debug", "Kernel debug environment")
|
|
||||||
debugCommandFlag := debugCommand.Flag("kernel", "Regex (first match)")
|
|
||||||
debugKernel := debugCommandFlag.Required().String()
|
|
||||||
debugFlagGDB := debugCommand.Flag("gdb", "Set gdb listen address")
|
|
||||||
debugGDB := debugFlagGDB.Default("tcp::1234").String()
|
|
||||||
|
|
||||||
yekaslr := debugCommand.Flag("enable-kaslr", "Enable KASLR").Bool()
|
|
||||||
yesmep := debugCommand.Flag("enable-smep", "Enable SMEP").Bool()
|
|
||||||
yesmap := debugCommand.Flag("enable-smap", "Enable SMAP").Bool()
|
|
||||||
yekpti := debugCommand.Flag("enable-kpti", "Enable KPTI").Bool()
|
|
||||||
|
|
||||||
nokaslr := debugCommand.Flag("disable-kaslr", "Disable KASLR").Bool()
|
|
||||||
nosmep := debugCommand.Flag("disable-smep", "Disable SMEP").Bool()
|
|
||||||
nosmap := debugCommand.Flag("disable-smap", "Disable SMAP").Bool()
|
|
||||||
nokpti := debugCommand.Flag("disable-kpti", "Disable KPTI").Bool()
|
|
||||||
|
|
||||||
bootstrapCommand := app.Command("bootstrap", "Apparently nothing")
|
|
||||||
|
|
||||||
logCommand := app.Command("log", "Logs")
|
|
||||||
|
|
||||||
logQueryCommand := logCommand.Command("query", "Query logs")
|
|
||||||
logNum := logQueryCommand.Flag("num", "How much lines").Default("50").Int()
|
|
||||||
logRate := logQueryCommand.Flag("rate", "Show artifact success rate").Bool()
|
|
||||||
logTag := logQueryCommand.Flag("tag", "Filter tag").String()
|
|
||||||
|
|
||||||
logDumpCommand := logCommand.Command("dump",
|
|
||||||
"Show all info for log entry with ID")
|
|
||||||
logDumpID := logDumpCommand.Arg("ID", "").Default("-1").Int()
|
|
||||||
|
|
||||||
logJSONCommand := logCommand.Command("json", "Generate json statistics")
|
|
||||||
logJSONTag := logJSONCommand.Flag("tag", "Filter tag").Required().String()
|
|
||||||
|
|
||||||
logMarkdownCommand := logCommand.Command("markdown", "Generate markdown statistics")
|
|
||||||
logMarkdownTag := logMarkdownCommand.Flag("tag", "Filter tag").Required().String()
|
|
||||||
|
|
||||||
packCommand := app.Command("pack", "Exploit pack test")
|
|
||||||
packAutogen := packCommand.Flag("autogen", "Kernel autogeneration").Bool()
|
|
||||||
packNoDownload := packCommand.Flag("no-download",
|
|
||||||
"Do not download qemu image while kernel generation").Bool()
|
|
||||||
packExploitRuns := packCommand.Flag("exploit-runs",
|
|
||||||
"Amount of runs of each exploit").Default("4").Int64()
|
|
||||||
packKernelRuns := packCommand.Flag("kernel-runs",
|
|
||||||
"Amount of runs of each kernel").Default("1").Int64()
|
|
||||||
|
|
||||||
err = checkRequiredUtils()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = checkDockerPermissions()
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
log.Println("You have two options:")
|
|
||||||
log.Println("\t1. Add user to group docker;")
|
|
||||||
log.Println("\t2. Run out-of-tree with sudo.")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !exists(usr.HomeDir + "/.out-of-tree/kernels.toml") {
|
|
||||||
log.Println("No ~/.out-of-tree/kernels.toml: Probably you " +
|
|
||||||
"need to run `out-of-tree kernel autogen` in " +
|
|
||||||
"directory that contains .out-of-tree.toml " +
|
|
||||||
"with defined kernel masks " +
|
|
||||||
"(see docs at https://out-of-tree.io)")
|
|
||||||
}
|
|
||||||
|
|
||||||
kingpin.MustParse(app.Parse(os.Args[1:]))
|
|
||||||
|
|
||||||
if *yekaslr && *nokaslr {
|
|
||||||
log.Fatalln("Only one of disable/enable can be used at once")
|
|
||||||
}
|
|
||||||
|
|
||||||
if *yesmep && *nosmep {
|
|
||||||
log.Fatalln("Only one of disable/enable can be used at once")
|
|
||||||
}
|
|
||||||
|
|
||||||
if *yesmap && *nosmap {
|
|
||||||
log.Fatalln("Only one of disable/enable can be used at once")
|
|
||||||
}
|
|
||||||
|
|
||||||
if *yekpti && *nokpti {
|
|
||||||
log.Fatalln("Only one of disable/enable can be used at once")
|
|
||||||
}
|
|
||||||
|
|
||||||
kcfg, err := config.ReadKernelConfig(*kcfgPath)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if exists(*userKcfgPath) {
|
|
||||||
userKcfg, err := config.ReadKernelConfig(*userKcfgPath)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, nk := range userKcfg.Kernels {
|
|
||||||
if !hasKernel(nk, kcfg) {
|
|
||||||
kcfg.Kernels = append(kcfg.Kernels, nk)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleFallbacks(kcfg)
|
|
||||||
|
|
||||||
db, err := openDatabase(*dbPath)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
stop := time.Time{} // never stop
|
|
||||||
if *timeout != 0 {
|
|
||||||
stop = time.Now().Add(*timeout)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch kingpin.MustParse(app.Parse(os.Args[1:])) {
|
|
||||||
case pewCommand.FullCommand():
|
|
||||||
err = pewHandler(kcfg, *path, *pewKernel, *pewBinary,
|
|
||||||
*pewTest, *pewGuess, stop, *qemuTimeout, *dockerTimeout,
|
|
||||||
*pewMax, *pewRuns, *pewDist, *pewTag, *pewThreads,
|
|
||||||
db, *pewVerbose)
|
|
||||||
case kernelListCommand.FullCommand():
|
|
||||||
err = kernelListHandler(kcfg)
|
|
||||||
case kernelAutogenCommand.FullCommand():
|
|
||||||
err = kernelAutogenHandler(*path, *dockerRegistry,
|
|
||||||
conf.Docker.Commands, *kernelAutogenMax,
|
|
||||||
*kernelUseHost, !*kernelNoDownload)
|
|
||||||
case kernelDockerRegenCommand.FullCommand():
|
|
||||||
err = kernelDockerRegenHandler(*kernelUseHost, !*kernelNoDownload)
|
|
||||||
case kernelGenallCommand.FullCommand():
|
|
||||||
err = kernelGenallHandler(*distro, *version,
|
|
||||||
*dockerRegistry, conf.Docker.Commands,
|
|
||||||
*kernelUseHost, !*kernelNoDownload)
|
|
||||||
case genModuleCommand.FullCommand():
|
|
||||||
err = genConfig(config.KernelModule)
|
|
||||||
case genExploitCommand.FullCommand():
|
|
||||||
err = genConfig(config.KernelExploit)
|
|
||||||
case debugCommand.FullCommand():
|
|
||||||
err = debugHandler(kcfg, *path, *debugKernel, *debugGDB,
|
|
||||||
*dockerTimeout, *yekaslr, *yesmep, *yesmap, *yekpti,
|
|
||||||
*nokaslr, *nosmep, *nosmap, *nokpti)
|
|
||||||
case bootstrapCommand.FullCommand():
|
|
||||||
fmt.Println("bootstrap is no more required, " +
|
|
||||||
"now images downloading on-demand")
|
|
||||||
fmt.Println("please, remove it from any automation scripts, " +
|
|
||||||
"because it'll be removed in the next release")
|
|
||||||
case logQueryCommand.FullCommand():
|
|
||||||
err = logHandler(db, *path, *logTag, *logNum, *logRate)
|
|
||||||
case logDumpCommand.FullCommand():
|
|
||||||
err = logDumpHandler(db, *logDumpID)
|
|
||||||
case logJSONCommand.FullCommand():
|
|
||||||
err = logJSONHandler(db, *path, *logJSONTag)
|
|
||||||
case logMarkdownCommand.FullCommand():
|
|
||||||
err = logMarkdownHandler(db, *path, *logMarkdownTag)
|
|
||||||
case packCommand.FullCommand():
|
|
||||||
err = packHandler(db, *path, *dockerRegistry, stop,
|
|
||||||
conf.Docker.Commands, kcfg, *packAutogen,
|
|
||||||
!*packNoDownload, *packExploitRuns, *packKernelRuns)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if successRate(state) < *threshold {
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
52
pack.go
52
pack.go
@ -5,7 +5,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
@ -15,33 +14,57 @@ import (
|
|||||||
"code.dumpstack.io/tools/out-of-tree/config"
|
"code.dumpstack.io/tools/out-of-tree/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
func packHandler(db *sql.DB, path, registry string, stop time.Time,
|
type PackCmd struct {
|
||||||
commands []config.DockerCommand, kcfg config.KernelConfig,
|
Autogen bool `help:"kernel autogeneration"`
|
||||||
autogen, download bool, exploitRuns, kernelRuns int64) (err error) {
|
NoDownload bool `help:"do not download qemu image while kernel generation"`
|
||||||
|
ExploitRuns int64 `default:"4" help:"amount of runs of each exploit"`
|
||||||
|
KernelRuns int64 `default:"1" help:"amount of runs of each kernel"`
|
||||||
|
|
||||||
|
Tag string `help:"filter tag"`
|
||||||
|
|
||||||
|
Timeout time.Duration `help:"timeout after tool will not spawn new tests"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cmd *PackCmd) Run(g *Globals) (err error) {
|
||||||
|
kcfg, err := config.ReadKernelConfig(g.Config.Kernels)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err := openDatabase(g.Config.Database)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
stop := time.Time{} // never stop
|
||||||
|
if cmd.Timeout != 0 {
|
||||||
|
stop = time.Now().Add(cmd.Timeout)
|
||||||
|
}
|
||||||
|
|
||||||
dockerTimeout := time.Minute
|
|
||||||
qemuTimeout := time.Minute
|
|
||||||
threads := runtime.NumCPU()
|
threads := runtime.NumCPU()
|
||||||
|
|
||||||
tag := fmt.Sprintf("pack_run_%d", time.Now().Unix())
|
tag := fmt.Sprintf("pack_run_%d", time.Now().Unix())
|
||||||
log.Println("Tag:", tag)
|
log.Println("Tag:", tag)
|
||||||
|
|
||||||
files, err := ioutil.ReadDir(path)
|
files, err := ioutil.ReadDir(g.WorkDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, f := range files {
|
for _, f := range files {
|
||||||
workPath := path + "/" + f.Name()
|
workPath := g.WorkDir + "/" + f.Name()
|
||||||
|
|
||||||
if !exists(workPath + "/.out-of-tree.toml") {
|
if !exists(workPath + "/.out-of-tree.toml") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if autogen {
|
if cmd.Autogen {
|
||||||
var perRegex int64 = 1
|
var perRegex int64 = 1
|
||||||
err = kernelAutogenHandler(workPath, registry,
|
err = kernelAutogenHandler(workPath,
|
||||||
commands, perRegex, false, download)
|
g.Config.Docker.Registry,
|
||||||
|
g.Config.Docker.Commands,
|
||||||
|
perRegex, false, !cmd.NoDownload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -49,9 +72,10 @@ func packHandler(db *sql.DB, path, registry string, stop time.Time,
|
|||||||
|
|
||||||
log.Println(f.Name())
|
log.Println(f.Name())
|
||||||
|
|
||||||
pewHandler(kcfg, workPath, "", "", "", false,
|
pewHandler(kcfg, workPath, "", "", "", false, stop,
|
||||||
stop, dockerTimeout, qemuTimeout,
|
g.Config.Docker.Timeout.Duration,
|
||||||
kernelRuns, exploitRuns, pathDevNull,
|
g.Config.Qemu.Timeout.Duration,
|
||||||
|
cmd.KernelRuns, cmd.ExploitRuns, pathDevNull,
|
||||||
tag, threads, db, false)
|
tag, threads, db, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
40
pew.go
40
pew.go
@ -26,6 +26,46 @@ import (
|
|||||||
"code.dumpstack.io/tools/out-of-tree/qemu"
|
"code.dumpstack.io/tools/out-of-tree/qemu"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type PewCmd struct {
|
||||||
|
Max int64 `help:"test no more than X kernels" default:"100500"`
|
||||||
|
Runs int64 `help:"runs per each kernel" default:"1"`
|
||||||
|
Kernel string `help:"override kernel regex"`
|
||||||
|
Guess bool `help:"try all defined kernels"`
|
||||||
|
Binary string `help:"use binary, do not build"`
|
||||||
|
Test string `help:"override path for test"`
|
||||||
|
Dist string `help:"build result path" default:"/dev/null"`
|
||||||
|
Threads int `help:"threads"`
|
||||||
|
Tag string `help:"log tagging"`
|
||||||
|
Verbose bool `help:"show more information"`
|
||||||
|
Timeout time.Duration `help:"timeout after tool will not spawn new tests"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cmd *PewCmd) Run(g *Globals) (err error) {
|
||||||
|
kcfg, err := config.ReadKernelConfig(g.Config.Kernels)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
stop := time.Time{} // never stop
|
||||||
|
if cmd.Timeout != 0 {
|
||||||
|
stop = time.Now().Add(cmd.Timeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err := openDatabase(g.Config.Database)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
return pewHandler(
|
||||||
|
kcfg, g.WorkDir, cmd.Kernel, cmd.Binary, cmd.Test,
|
||||||
|
cmd.Guess, stop, g.Config.Qemu.Timeout.Duration,
|
||||||
|
g.Config.Docker.Timeout.Duration,
|
||||||
|
cmd.Max, cmd.Runs, cmd.Dist, cmd.Tag, cmd.Threads,
|
||||||
|
db, cmd.Verbose,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
type runstate struct {
|
type runstate struct {
|
||||||
Overall, Success float64
|
Overall, Success float64
|
||||||
}
|
}
|
||||||
|
@ -21,15 +21,9 @@ import (
|
|||||||
"code.dumpstack.io/tools/out-of-tree/qemu"
|
"code.dumpstack.io/tools/out-of-tree/qemu"
|
||||||
)
|
)
|
||||||
|
|
||||||
var disablePreload *bool
|
|
||||||
|
|
||||||
func preloadModules(q *qemu.System, ka config.Artifact, ki config.KernelInfo,
|
func preloadModules(q *qemu.System, ka config.Artifact, ki config.KernelInfo,
|
||||||
dockerTimeout time.Duration) (err error) {
|
dockerTimeout time.Duration) (err error) {
|
||||||
|
|
||||||
if *disablePreload {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, pm := range ka.Preload {
|
for _, pm := range ka.Preload {
|
||||||
err = preload(q, ki, pm, dockerTimeout)
|
err = preload(q, ki, pm, dockerTimeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user