From fc0c76f114e775ffd235c118f7413da3958dd2fc Mon Sep 17 00:00:00 2001 From: Mikhail Klementev Date: Wed, 5 Apr 2023 11:29:31 +0000 Subject: [PATCH] Do not randomize kernels installation/test order by default --- kernel.go | 13 ++++++-- pack.go | 6 ++-- pew.go | 90 +++++++++++++++++++++++++++---------------------------- 3 files changed, 58 insertions(+), 51 deletions(-) diff --git a/kernel.go b/kernel.go index df27c54..78b01e4 100644 --- a/kernel.go +++ b/kernel.go @@ -29,6 +29,7 @@ type KernelCmd struct { UseHost bool `help:"also use host kernels"` Force bool `help:"force reinstall kernel"` NoHeaders bool `help:"do not install kernel headers"` + Shuffle bool `help:"randomize kernels installation order"` List KernelListCmd `cmd:"" help:"list kernels"` Autogen KernelAutogenCmd `cmd:"" help:"generate kernels based on the current config"` @@ -79,6 +80,7 @@ func (cmd KernelAutogenCmd) Run(kernelCmd *KernelCmd, g *Globals) (err error) { !kernelCmd.NoDownload, kernelCmd.Force, !kernelCmd.NoHeaders, + kernelCmd.Shuffle, ) if err != nil { return @@ -111,6 +113,7 @@ func (cmd *KernelGenallCmd) Run(kernelCmd *KernelCmd, g *Globals) (err error) { !kernelCmd.NoDownload, kernelCmd.Force, !kernelCmd.NoHeaders, + kernelCmd.Shuffle, ) if err != nil { return @@ -143,6 +146,7 @@ func (cmd *KernelInstallCmd) Run(kernelCmd *KernelCmd, g *Globals) (err error) { !kernelCmd.NoDownload, kernelCmd.Force, !kernelCmd.NoHeaders, + kernelCmd.Shuffle, ) if err != nil { return @@ -670,7 +674,7 @@ func hasKernel(ki config.KernelInfo, kcfg config.KernelConfig) bool { return false } -func shuffle(a []string) []string { +func shuffleStrings(a []string) []string { // Fisher–Yates shuffle for i := len(a) - 1; i > 0; i-- { j := rand.Intn(i + 1) @@ -681,7 +685,7 @@ func shuffle(a []string) []string { func generateKernels(km config.KernelMask, registry string, commands []config.DockerCommand, max int64, - download, force, headers bool) (err error) { + download, force, headers, shuffle bool) (err error) { log.Info().Msgf("Generating for kernel mask %v", km) @@ -711,7 +715,10 @@ func generateKernels(km config.KernelMask, registry string, return } - for i, pkg := range shuffle(pkgs) { + if shuffle { + pkgs = shuffleStrings(pkgs) + } + for i, pkg := range pkgs { if max <= 0 { log.Print("Max is reached") break diff --git a/pack.go b/pack.go index 0c84cbb..c79cf6f 100644 --- a/pack.go +++ b/pack.go @@ -63,7 +63,7 @@ func (cmd *PackCmd) Run(g *Globals) (err error) { log.Print(f.Name()) - PewCmd{ + pew := PewCmd{ Max: cmd.KernelRuns, Runs: cmd.ExploitRuns, Threads: cmd.Threads, @@ -72,7 +72,9 @@ func (cmd *PackCmd) Run(g *Globals) (err error) { QemuTimeout: cmd.QemuTimeout, DockerTimeout: cmd.DockerTimeout, Dist: pathDevNull, - }.Run(&Globals{ + } + + pew.Run(&Globals{ Config: g.Config, WorkDir: workPath, }) diff --git a/pew.go b/pew.go index 2c68c4f..1d253cb 100644 --- a/pew.go +++ b/pew.go @@ -32,6 +32,7 @@ type PewCmd struct { Runs int64 `help:"runs per each kernel" default:"1"` Kernel string `help:"override kernel regex"` Guess bool `help:"try all defined kernels"` + Shuffle bool `help:"randomize kernels test order"` Binary string `help:"use binary, do not build"` Test string `help:"override path for test"` Dist string `help:"build result path" default:"/dev/null"` @@ -45,26 +46,29 @@ type PewCmd struct { DockerTimeout time.Duration `help:"timeout for docker"` Threshold float64 `help:"reliablity threshold for exit code" default:"1.00"` + + db *sql.DB + kcfg config.KernelConfig + timeoutDeadline time.Time } -func (cmd PewCmd) Run(g *Globals) (err error) { - kcfg, err := config.ReadKernelConfig(g.Config.Kernels) +func (cmd *PewCmd) Run(g *Globals) (err error) { + cmd.kcfg, err = config.ReadKernelConfig(g.Config.Kernels) if err != nil { - log.Debug().Err(err).Msg("read kernels config") + log.Fatal().Err(err).Msg("read kernels config") } - stop := time.Time{} // never stop if cmd.Timeout != 0 { log.Info().Msgf("Set global timeout to %s", cmd.Timeout) - stop = time.Now().Add(cmd.Timeout) + cmd.timeoutDeadline = time.Now().Add(cmd.Timeout) } - db, err := openDatabase(g.Config.Database) + cmd.db, err = openDatabase(g.Config.Database) if err != nil { log.Fatal().Err(err). Msgf("Cannot open database %s", g.Config.Database) } - defer db.Close() + defer cmd.db.Close() var configPath string if cmd.ArtifactConfig == "" { @@ -98,16 +102,16 @@ func (cmd PewCmd) Run(g *Globals) (err error) { } } - qemuTimeout := g.Config.Qemu.Timeout.Duration if cmd.QemuTimeout != 0 { log.Info().Msgf("Set qemu timeout to %s", cmd.QemuTimeout) - qemuTimeout = cmd.QemuTimeout + } else { + cmd.QemuTimeout = g.Config.Qemu.Timeout.Duration } - dockerTimeout := g.Config.Docker.Timeout.Duration if cmd.DockerTimeout != 0 { log.Info().Msgf("Set docker timeout to %s", cmd.DockerTimeout) - dockerTimeout = cmd.DockerTimeout + } else { + cmd.DockerTimeout = g.Config.Docker.Timeout.Duration } if cmd.Tag == "" { @@ -115,10 +119,7 @@ func (cmd PewCmd) Run(g *Globals) (err error) { } log.Info().Str("tag", cmd.Tag).Msg("log") - err = performCI(ka, kcfg, cmd.Binary, cmd.Test, stop, - qemuTimeout, dockerTimeout, - cmd.Max, cmd.Runs, cmd.Dist, cmd.Tag, - cmd.Threads, db) + err = cmd.performCI(ka) if err != nil { return } @@ -518,10 +519,8 @@ func copyStandardModules(q *qemu.System, ki config.KernelInfo) (err error) { return } -func testArtifact(swg *sizedwaitgroup.SizedWaitGroup, ka config.Artifact, - ki config.KernelInfo, binaryPath, testPath string, - qemuTimeout, dockerTimeout time.Duration, dist, tag string, - db *sql.DB) { +func (cmd PewCmd) testArtifact(swg *sizedwaitgroup.SizedWaitGroup, + ka config.Artifact, ki config.KernelInfo) { defer swg.Done() @@ -539,7 +538,7 @@ func testArtifact(swg *sizedwaitgroup.SizedWaitGroup, ka config.Artifact, slog.Error().Err(err).Msg("qemu init") return } - q.Timeout = qemuTimeout + q.Timeout = cmd.QemuTimeout if ka.Qemu.Timeout.Duration != 0 { q.Timeout = ka.Qemu.Timeout.Duration @@ -552,7 +551,7 @@ func testArtifact(swg *sizedwaitgroup.SizedWaitGroup, ka config.Artifact, } if ka.Docker.Timeout.Duration != 0 { - dockerTimeout = ka.Docker.Timeout.Duration + cmd.DockerTimeout = ka.Docker.Timeout.Duration } q.SetKASLR(!ka.Mitigations.DisableKaslr) @@ -589,16 +588,16 @@ func testArtifact(swg *sizedwaitgroup.SizedWaitGroup, ka config.Artifact, defer os.RemoveAll(tmp) result := phasesResult{} - defer dumpResult(q, ka, ki, &result, dist, tag, binaryPath, db) + defer dumpResult(q, ka, ki, &result, cmd.Dist, cmd.Tag, cmd.Binary, cmd.db) if ka.Type == config.Script { result.Build.Ok = true - testPath = ka.Script - } else if binaryPath == "" { + cmd.Test = ka.Script + } else if cmd.Binary == "" { // TODO: build should return structure start := time.Now() result.BuildDir, result.BuildArtifact, result.Build.Output, err = - build(tmp, ka, ki, dockerTimeout) + build(tmp, ka, ki, cmd.DockerTimeout) slog.Debug().Str("duration", time.Now().Sub(start).String()). Msg("build done") if err != nil { @@ -607,23 +606,23 @@ func testArtifact(swg *sizedwaitgroup.SizedWaitGroup, ka config.Artifact, } result.Build.Ok = true } else { - result.BuildArtifact = binaryPath + result.BuildArtifact = cmd.Binary result.Build.Ok = true } - if testPath == "" { - testPath = result.BuildArtifact + "_test" - if !exists(testPath) { - testPath = tmp + "/source/" + "test.sh" + if cmd.Test == "" { + cmd.Test = result.BuildArtifact + "_test" + if !exists(cmd.Test) { + cmd.Test = tmp + "/source/" + "test.sh" } } - err = q.WaitForSSH(qemuTimeout) + err = q.WaitForSSH(cmd.QemuTimeout) if err != nil { return } - remoteTest, err := copyTest(q, testPath, ka) + remoteTest, err := copyTest(q, cmd.Test, ka) if err != nil { return } @@ -640,7 +639,7 @@ func testArtifact(swg *sizedwaitgroup.SizedWaitGroup, ka config.Artifact, Msg("copy standard modules") } - err = preloadModules(q, ka, ki, dockerTimeout) + err = preloadModules(q, ka, ki, cmd.DockerTimeout) if err != nil { slog.Error().Err(err).Msg("preload modules") return @@ -661,16 +660,15 @@ func shuffleKernels(a []config.KernelInfo) []config.KernelInfo { return a } -func performCI(ka config.Artifact, kcfg config.KernelConfig, binaryPath, - testPath string, stop time.Time, - qemuTimeout, dockerTimeout time.Duration, - max, runs int64, dist, tag string, threads int, - db *sql.DB) (err error) { - +func (cmd PewCmd) performCI(ka config.Artifact) (err error) { found := false + max := cmd.Max - swg := sizedwaitgroup.New(threads) - for _, kernel := range shuffleKernels(kcfg.Kernels) { + swg := sizedwaitgroup.New(cmd.Threads) + if cmd.Shuffle { + cmd.kcfg.Kernels = shuffleKernels(cmd.kcfg.Kernels) + } + for _, kernel := range cmd.kcfg.Kernels { if max <= 0 { break } @@ -684,14 +682,14 @@ func performCI(ka config.Artifact, kcfg config.KernelConfig, binaryPath, if supported { found = true max-- - for i := int64(0); i < runs; i++ { - if !stop.IsZero() && time.Now().After(stop) { + for i := int64(0); i < cmd.Runs; i++ { + if !cmd.timeoutDeadline.IsZero() && + time.Now().After(cmd.timeoutDeadline) { + break } swg.Add() - go testArtifact(&swg, ka, kernel, binaryPath, - testPath, qemuTimeout, dockerTimeout, - dist, tag, db) + go cmd.testArtifact(&swg, ka, kernel) } } }