| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | // Copyright 2018 Mikhail Klementev. All rights reserved. | 
					
						
							|  |  |  |  | // Use of this source code is governed by a AGPLv3 license | 
					
						
							|  |  |  |  | // (or later) that can be found in the LICENSE file. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | package main | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2019-08-13 21:54:59 +00:00
										 |  |  |  | 	"database/sql" | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 	"errors" | 
					
						
							|  |  |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2019-08-14 17:36:36 +00:00
										 |  |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 	"io/ioutil" | 
					
						
							|  |  |  |  | 	"log" | 
					
						
							|  |  |  |  | 	"math/rand" | 
					
						
							|  |  |  |  | 	"os" | 
					
						
							|  |  |  |  | 	"os/exec" | 
					
						
							| 
									
										
										
										
											2019-08-16 04:43:29 +00:00
										 |  |  |  | 	"os/user" | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 	"strings" | 
					
						
							|  |  |  |  | 	"time" | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	"github.com/otiai10/copy" | 
					
						
							|  |  |  |  | 	"github.com/remeh/sizedwaitgroup" | 
					
						
							| 
									
										
										
										
											2020-05-17 18:40:34 +03:00
										 |  |  |  | 	"gopkg.in/logrusorgru/aurora.v2" | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-02 21:24:29 +00:00
										 |  |  |  | 	"code.dumpstack.io/tools/out-of-tree/config" | 
					
						
							|  |  |  |  | 	"code.dumpstack.io/tools/out-of-tree/qemu" | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | ) | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-31 07:13:33 +00:00
										 |  |  |  | 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"` | 
					
						
							| 
									
										
										
										
											2023-01-31 09:05:43 +00:00
										 |  |  |  | 	Threads int           `help:"threads" default:"1"` | 
					
						
							| 
									
										
										
										
											2023-01-31 07:13:33 +00:00
										 |  |  |  | 	Tag     string        `help:"log tagging"` | 
					
						
							|  |  |  |  | 	Verbose bool          `help:"show more information"` | 
					
						
							|  |  |  |  | 	Timeout time.Duration `help:"timeout after tool will not spawn new tests"` | 
					
						
							| 
									
										
										
										
											2023-01-31 09:05:43 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-01 07:37:08 +00:00
										 |  |  |  | 	ArtifactConfig string `help:"path to artifact config" type:"path"` | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-31 09:05:43 +00:00
										 |  |  |  | 	QemuTimeout   time.Duration `help:"timeout for qemu"` | 
					
						
							|  |  |  |  | 	DockerTimeout time.Duration `help:"timeout for docker"` | 
					
						
							| 
									
										
										
										
											2023-01-31 09:34:12 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-31 09:57:53 +00:00
										 |  |  |  | 	Threshold float64 `help:"reliablity threshold for exit code" default:"1.00"` | 
					
						
							| 
									
										
										
										
											2023-01-31 07:13:33 +00:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-31 09:05:43 +00:00
										 |  |  |  | func (cmd PewCmd) Run(g *Globals) (err error) { | 
					
						
							| 
									
										
										
										
											2023-01-31 07:13:33 +00:00
										 |  |  |  | 	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() | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-01 07:37:08 +00:00
										 |  |  |  | 	var configPath string | 
					
						
							|  |  |  |  | 	if cmd.ArtifactConfig == "" { | 
					
						
							|  |  |  |  | 		configPath = g.WorkDir + "/.out-of-tree.toml" | 
					
						
							|  |  |  |  | 	} else { | 
					
						
							|  |  |  |  | 		configPath = cmd.ArtifactConfig | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	ka, err := config.ReadArtifactConfig(configPath) | 
					
						
							| 
									
										
										
										
											2023-01-31 09:05:43 +00:00
										 |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if ka.SourcePath == "" { | 
					
						
							|  |  |  |  | 		ka.SourcePath = g.WorkDir | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if cmd.Kernel != "" { | 
					
						
							|  |  |  |  | 		var km config.KernelMask | 
					
						
							|  |  |  |  | 		km, err = kernelMask(cmd.Kernel) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			return | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		ka.SupportedKernels = []config.KernelMask{km} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if cmd.Guess { | 
					
						
							|  |  |  |  | 		ka.SupportedKernels, err = genAllKernels() | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			return | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	qemuTimeout := g.Config.Qemu.Timeout.Duration | 
					
						
							|  |  |  |  | 	if cmd.QemuTimeout != 0 { | 
					
						
							|  |  |  |  | 		qemuTimeout = cmd.QemuTimeout | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	dockerTimeout := g.Config.Docker.Timeout.Duration | 
					
						
							|  |  |  |  | 	if cmd.DockerTimeout != 0 { | 
					
						
							|  |  |  |  | 		dockerTimeout = cmd.DockerTimeout | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-16 09:41:49 +00:00
										 |  |  |  | 	if cmd.Tag == "" { | 
					
						
							|  |  |  |  | 		cmd.Tag = fmt.Sprintf("%d", time.Now().Unix()) | 
					
						
							|  |  |  |  | 		log.Println("Tag: " + cmd.Tag) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-31 09:05:43 +00:00
										 |  |  |  | 	err = performCI(ka, kcfg, cmd.Binary, cmd.Test, stop, | 
					
						
							|  |  |  |  | 		qemuTimeout, dockerTimeout, | 
					
						
							|  |  |  |  | 		cmd.Max, cmd.Runs, cmd.Dist, cmd.Tag, | 
					
						
							|  |  |  |  | 		cmd.Threads, db, cmd.Verbose) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-31 09:56:49 +00:00
										 |  |  |  | 	if successRate(state) < cmd.Threshold { | 
					
						
							| 
									
										
										
										
											2023-01-31 09:34:12 +00:00
										 |  |  |  | 		err = errors.New("reliability threshold not met") | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-01-31 09:05:43 +00:00
										 |  |  |  | 	return | 
					
						
							| 
									
										
										
										
											2023-01-31 07:13:33 +00:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-30 00:33:43 +00:00
										 |  |  |  | type runstate struct { | 
					
						
							|  |  |  |  | 	Overall, Success float64 | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | var ( | 
					
						
							|  |  |  |  | 	state runstate | 
					
						
							|  |  |  |  | ) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func successRate(state runstate) float64 { | 
					
						
							|  |  |  |  | 	return state.Success / state.Overall | 
					
						
							|  |  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-12-07 03:14:10 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-17 09:05:06 +00:00
										 |  |  |  | const pathDevNull = "/dev/null" | 
					
						
							| 
									
										
										
										
											2019-08-14 17:36:36 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-08 02:53:29 +00:00
										 |  |  |  | func dockerRun(timeout time.Duration, container, workdir, command string) ( | 
					
						
							|  |  |  |  | 	output string, err error) { | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-16 09:42:07 +00:00
										 |  |  |  | 	cmd := exec.Command("docker", "run", "--rm", "-v", workdir+":/work", | 
					
						
							| 
									
										
										
										
											2018-12-08 02:53:29 +00:00
										 |  |  |  | 		container, "bash", "-c", "cd /work && "+command) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	timer := time.AfterFunc(timeout, func() { | 
					
						
							|  |  |  |  | 		cmd.Process.Kill() | 
					
						
							|  |  |  |  | 	}) | 
					
						
							|  |  |  |  | 	defer timer.Stop() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	raw, err := cmd.CombinedOutput() | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2019-08-12 22:58:34 +00:00
										 |  |  |  | 		e := fmt.Sprintf("error `%v` for cmd `%v` with output `%v`", | 
					
						
							|  |  |  |  | 			err, command, string(raw)) | 
					
						
							|  |  |  |  | 		err = errors.New(e) | 
					
						
							| 
									
										
										
										
											2018-12-08 02:53:29 +00:00
										 |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	output = string(raw) | 
					
						
							|  |  |  |  | 	return | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-16 10:21:44 +00:00
										 |  |  |  | func sh(workdir, cmd string) (output string, err error) { | 
					
						
							|  |  |  |  | 	command := exec.Command("sh", "-c", "cd "+workdir+" && "+cmd) | 
					
						
							|  |  |  |  | 	raw, err := command.CombinedOutput() | 
					
						
							|  |  |  |  | 	output = string(raw) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		e := fmt.Sprintf("%v %v output: %v", cmd, err, output) | 
					
						
							|  |  |  |  | 		err = errors.New(e) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	return | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func applyPatches(src string, ka config.Artifact) (err error) { | 
					
						
							|  |  |  |  | 	for i, patch := range ka.Patches { | 
					
						
							|  |  |  |  | 		name := fmt.Sprintf("patch_%02d", i) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		path := src + "/" + name + ".diff" | 
					
						
							|  |  |  |  | 		if patch.Source != "" && patch.Path != "" { | 
					
						
							|  |  |  |  | 			err = errors.New("path and source are mutually exclusive") | 
					
						
							|  |  |  |  | 			return | 
					
						
							|  |  |  |  | 		} else if patch.Source != "" { | 
					
						
							|  |  |  |  | 			err = os.WriteFile(path, []byte(patch.Source), 0644) | 
					
						
							|  |  |  |  | 			if err != nil { | 
					
						
							|  |  |  |  | 				return | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 		} else if patch.Path != "" { | 
					
						
							|  |  |  |  | 			err = copy.Copy(patch.Path, path) | 
					
						
							|  |  |  |  | 			if err != nil { | 
					
						
							|  |  |  |  | 				return | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		if patch.Source != "" || patch.Path != "" { | 
					
						
							|  |  |  |  | 			_, err = sh(src, "patch < "+path) | 
					
						
							|  |  |  |  | 			if err != nil { | 
					
						
							|  |  |  |  | 				return | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		if patch.Script != "" { | 
					
						
							|  |  |  |  | 			script := src + "/" + name + ".sh" | 
					
						
							|  |  |  |  | 			err = os.WriteFile(script, []byte(patch.Script), 0755) | 
					
						
							|  |  |  |  | 			if err != nil { | 
					
						
							|  |  |  |  | 				return | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 			_, err = sh(src, script) | 
					
						
							|  |  |  |  | 			if err != nil { | 
					
						
							|  |  |  |  | 				return | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	return | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-17 20:18:50 +00:00
										 |  |  |  | func build(tmp string, ka config.Artifact, ki config.KernelInfo, | 
					
						
							| 
									
										
										
										
											2023-02-16 10:46:24 +00:00
										 |  |  |  | 	dockerTimeout time.Duration) (outdir, outpath, output string, err error) { | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	target := fmt.Sprintf("%d_%s", rand.Int(), ki.KernelRelease) | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-16 10:46:24 +00:00
										 |  |  |  | 	outdir = tmp + "/source" | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-16 10:46:24 +00:00
										 |  |  |  | 	err = copy.Copy(ka.SourcePath, outdir) | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-16 10:46:24 +00:00
										 |  |  |  | 	err = applyPatches(outdir, ka) | 
					
						
							| 
									
										
										
										
											2023-02-16 10:21:44 +00:00
										 |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-16 10:46:24 +00:00
										 |  |  |  | 	outpath = outdir + "/" + target | 
					
						
							| 
									
										
										
										
											2018-11-17 20:18:50 +00:00
										 |  |  |  | 	if ka.Type == config.KernelModule { | 
					
						
							| 
									
										
										
										
											2023-02-16 10:46:24 +00:00
										 |  |  |  | 		outpath += ".ko" | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	kernel := "/lib/modules/" + ki.KernelRelease + "/build" | 
					
						
							| 
									
										
										
										
											2019-08-16 05:05:26 +00:00
										 |  |  |  | 	if ki.KernelSource != "" { | 
					
						
							|  |  |  |  | 		kernel = ki.KernelSource | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-15 16:54:46 +00:00
										 |  |  |  | 	buildCommand := "make KERNEL=" + kernel + " TARGET=" + target | 
					
						
							|  |  |  |  | 	if ka.Make.Target != "" { | 
					
						
							|  |  |  |  | 		buildCommand += " " + ka.Make.Target | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-16 05:05:26 +00:00
										 |  |  |  | 	if ki.ContainerName != "" { | 
					
						
							|  |  |  |  | 		output, err = dockerRun(dockerTimeout, ki.ContainerName, | 
					
						
							| 
									
										
										
										
											2023-02-16 10:46:24 +00:00
										 |  |  |  | 			outdir, buildCommand+" && chmod -R 777 /work") | 
					
						
							| 
									
										
										
										
											2019-08-16 05:05:26 +00:00
										 |  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2023-02-16 10:46:24 +00:00
										 |  |  |  | 		cmd := exec.Command("bash", "-c", "cd "+outdir+" && "+ | 
					
						
							| 
									
										
										
										
											2023-02-15 16:54:46 +00:00
										 |  |  |  | 			buildCommand) | 
					
						
							| 
									
										
										
										
											2019-08-16 05:05:26 +00:00
										 |  |  |  | 		timer := time.AfterFunc(dockerTimeout, func() { | 
					
						
							|  |  |  |  | 			cmd.Process.Kill() | 
					
						
							|  |  |  |  | 		}) | 
					
						
							|  |  |  |  | 		defer timer.Stop() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		var raw []byte | 
					
						
							|  |  |  |  | 		raw, err = cmd.CombinedOutput() | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			e := fmt.Sprintf("error `%v` for cmd `%v` with output `%v`", | 
					
						
							| 
									
										
										
										
											2023-02-15 16:54:46 +00:00
										 |  |  |  | 				err, buildCommand, string(raw)) | 
					
						
							| 
									
										
										
										
											2019-08-16 05:05:26 +00:00
										 |  |  |  | 			err = errors.New(e) | 
					
						
							|  |  |  |  | 			return | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		output = string(raw) | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 	return | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-17 09:05:06 +00:00
										 |  |  |  | func testKernelModule(q *qemu.System, ka config.Artifact, | 
					
						
							| 
									
										
										
										
											2018-11-17 20:18:50 +00:00
										 |  |  |  | 	test string) (output string, err error) { | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 	output, err = q.Command("root", test) | 
					
						
							|  |  |  |  | 	// TODO generic checks for WARNING's and so on | 
					
						
							|  |  |  |  | 	return | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-17 09:05:06 +00:00
										 |  |  |  | func testKernelExploit(q *qemu.System, ka config.Artifact, | 
					
						
							| 
									
										
										
										
											2018-11-17 20:18:50 +00:00
										 |  |  |  | 	test, exploit string) (output string, err error) { | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 	output, err = q.Command("user", "chmod +x "+exploit) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	randFilePath := fmt.Sprintf("/root/%d", rand.Int()) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	cmd := fmt.Sprintf("%s %s %s", test, exploit, randFilePath) | 
					
						
							|  |  |  |  | 	output, err = q.Command("user", cmd) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	_, err = q.Command("root", "stat "+randFilePath) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	return | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-10 02:41:45 +00:00
										 |  |  |  | func genOkFail(name string, ok bool) (aurv aurora.Value) { | 
					
						
							| 
									
										
										
										
											2019-08-30 00:33:43 +00:00
										 |  |  |  | 	state.Overall += 1 | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 	if ok { | 
					
						
							| 
									
										
										
										
											2019-08-30 00:33:43 +00:00
										 |  |  |  | 		state.Success += 1 | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 		s := " " + name + " SUCCESS " | 
					
						
							| 
									
										
										
										
											2018-12-10 02:41:45 +00:00
										 |  |  |  | 		aurv = aurora.BgGreen(aurora.Black(s)) | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 	} else { | 
					
						
							|  |  |  |  | 		s := " " + name + " FAILURE " | 
					
						
							| 
									
										
										
										
											2020-05-17 18:40:34 +03:00
										 |  |  |  | 		aurv = aurora.BgRed(aurora.White(aurora.Bold(s))) | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-12-10 02:41:45 +00:00
										 |  |  |  | 	return | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-13 21:54:59 +00:00
										 |  |  |  | type phasesResult struct { | 
					
						
							| 
									
										
										
										
											2023-02-16 10:46:24 +00:00
										 |  |  |  | 	BuildDir         string | 
					
						
							| 
									
										
										
										
											2019-08-14 17:36:36 +00:00
										 |  |  |  | 	BuildArtifact    string | 
					
						
							| 
									
										
										
										
											2019-08-13 21:54:59 +00:00
										 |  |  |  | 	Build, Run, Test struct { | 
					
						
							|  |  |  |  | 		Output string | 
					
						
							|  |  |  |  | 		Ok     bool | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 17:36:36 +00:00
										 |  |  |  | func copyFile(sourcePath, destinationPath string) (err error) { | 
					
						
							|  |  |  |  | 	sourceFile, err := os.Open(sourcePath) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer sourceFile.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	destinationFile, err := os.Create(destinationPath) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		return err | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if _, err := io.Copy(destinationFile, sourceFile); err != nil { | 
					
						
							|  |  |  |  | 		destinationFile.Close() | 
					
						
							|  |  |  |  | 		return err | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	return destinationFile.Close() | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-17 09:05:06 +00:00
										 |  |  |  | func dumpResult(q *qemu.System, ka config.Artifact, ki config.KernelInfo, | 
					
						
							| 
									
										
										
										
											2019-08-16 18:30:46 +00:00
										 |  |  |  | 	res *phasesResult, dist, tag, binary string, db *sql.DB) { | 
					
						
							| 
									
										
										
										
											2018-11-17 20:18:50 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-13 23:33:52 +00:00
										 |  |  |  | 	// TODO merge (problem is it's not 100% same) with log.go:logLogEntry | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 	distroInfo := fmt.Sprintf("%s-%s {%s}", ki.DistroType, | 
					
						
							|  |  |  |  | 		ki.DistroRelease, ki.KernelRelease) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	colored := "" | 
					
						
							| 
									
										
										
										
											2018-11-17 20:18:50 +00:00
										 |  |  |  | 	if ka.Type == config.KernelExploit { | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 		colored = aurora.Sprintf("[*] %40s: %s %s", distroInfo, | 
					
						
							| 
									
										
										
										
											2019-08-13 21:54:59 +00:00
										 |  |  |  | 			genOkFail("BUILD", res.Build.Ok), | 
					
						
							|  |  |  |  | 			genOkFail("LPE", res.Test.Ok)) | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 	} else { | 
					
						
							|  |  |  |  | 		colored = aurora.Sprintf("[*] %40s: %s %s %s", distroInfo, | 
					
						
							| 
									
										
										
										
											2019-08-13 21:54:59 +00:00
										 |  |  |  | 			genOkFail("BUILD", res.Build.Ok), | 
					
						
							|  |  |  |  | 			genOkFail("INSMOD", res.Run.Ok), | 
					
						
							|  |  |  |  | 			genOkFail("TEST", res.Test.Ok)) | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	additional := "" | 
					
						
							|  |  |  |  | 	if q.KernelPanic { | 
					
						
							|  |  |  |  | 		additional = "(panic)" | 
					
						
							|  |  |  |  | 	} else if q.KilledByTimeout { | 
					
						
							|  |  |  |  | 		additional = "(timeout)" | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if additional != "" { | 
					
						
							|  |  |  |  | 		fmt.Println(colored, additional) | 
					
						
							|  |  |  |  | 	} else { | 
					
						
							|  |  |  |  | 		fmt.Println(colored) | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-13 21:54:59 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-16 18:30:46 +00:00
										 |  |  |  | 	err := addToLog(db, q, ka, ki, res, tag) | 
					
						
							| 
									
										
										
										
											2019-08-13 21:54:59 +00:00
										 |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		log.Println("[db] addToLog (", ka, ") error:", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-14 17:36:36 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-17 09:05:06 +00:00
										 |  |  |  | 	if binary == "" && dist != pathDevNull { | 
					
						
							| 
									
										
										
										
											2019-08-14 17:36:36 +00:00
										 |  |  |  | 		err = os.MkdirAll(dist, os.ModePerm) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			log.Println("os.MkdirAll (", ka, ") error:", err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		path := fmt.Sprintf("%s/%s-%s-%s", dist, ki.DistroType, | 
					
						
							|  |  |  |  | 			ki.DistroRelease, ki.KernelRelease) | 
					
						
							|  |  |  |  | 		if ka.Type != config.KernelExploit { | 
					
						
							|  |  |  |  | 			path += ".ko" | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		err = copyFile(res.BuildArtifact, path) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			log.Println("copyFile (", ka, ") error:", err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-17 10:00:01 +00:00
										 |  |  |  | func copyArtifactAndTest(q *qemu.System, ka config.Artifact, | 
					
						
							|  |  |  |  | 	res *phasesResult, remoteTest string) (err error) { | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	switch ka.Type { | 
					
						
							|  |  |  |  | 	case config.KernelModule: | 
					
						
							|  |  |  |  | 		res.Run.Output, err = q.CopyAndInsmod(res.BuildArtifact) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			log.Println(res.Run.Output, err) | 
					
						
							|  |  |  |  | 			return | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		res.Run.Ok = true | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-13 03:31:00 +00:00
										 |  |  |  | 		// Copy all test files to the remote machine | 
					
						
							| 
									
										
										
										
											2023-01-29 22:27:24 +00:00
										 |  |  |  | 		for _, f := range ka.TestFiles { | 
					
						
							| 
									
										
										
										
											2023-02-16 10:46:24 +00:00
										 |  |  |  | 			if f.Local[0] != '/' { | 
					
						
							|  |  |  |  | 				f.Local = res.BuildDir + "/" + f.Local | 
					
						
							|  |  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-01-29 22:27:24 +00:00
										 |  |  |  | 			err = q.CopyFile(f.User, f.Local, f.Remote) | 
					
						
							| 
									
										
										
										
											2020-09-13 03:31:00 +00:00
										 |  |  |  | 			if err != nil { | 
					
						
							|  |  |  |  | 				log.Println("error copy err:", err, f.Local, f.Remote) | 
					
						
							|  |  |  |  | 				return | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-17 10:00:01 +00:00
										 |  |  |  | 		res.Test.Output, err = testKernelModule(q, ka, remoteTest) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			log.Println(res.Test.Output, err) | 
					
						
							|  |  |  |  | 			return | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		res.Test.Ok = true | 
					
						
							|  |  |  |  | 	case config.KernelExploit: | 
					
						
							|  |  |  |  | 		remoteExploit := fmt.Sprintf("/tmp/exploit_%d", rand.Int()) | 
					
						
							|  |  |  |  | 		err = q.CopyFile("user", res.BuildArtifact, remoteExploit) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			return | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		res.Test.Output, err = testKernelExploit(q, ka, remoteTest, | 
					
						
							|  |  |  |  | 			remoteExploit) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			log.Println(res.Test.Output) | 
					
						
							|  |  |  |  | 			return | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		res.Run.Ok = true // does not really used | 
					
						
							|  |  |  |  | 		res.Test.Ok = true | 
					
						
							|  |  |  |  | 	default: | 
					
						
							|  |  |  |  | 		log.Println("Unsupported artifact type") | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	return | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func copyTest(q *qemu.System, testPath string, ka config.Artifact) ( | 
					
						
							|  |  |  |  | 	remoteTest string, err error) { | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	remoteTest = fmt.Sprintf("/tmp/test_%d", rand.Int()) | 
					
						
							|  |  |  |  | 	err = q.CopyFile("user", testPath, remoteTest) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		if ka.Type == config.KernelExploit { | 
					
						
							|  |  |  |  | 			q.Command("user", | 
					
						
							|  |  |  |  | 				"echo -e '#!/bin/sh\necho touch $2 | $1' "+ | 
					
						
							|  |  |  |  | 					"> "+remoteTest+ | 
					
						
							|  |  |  |  | 					" && chmod +x "+remoteTest) | 
					
						
							|  |  |  |  | 		} else { | 
					
						
							|  |  |  |  | 			q.Command("user", "echo '#!/bin/sh' "+ | 
					
						
							|  |  |  |  | 				"> "+remoteTest+" && chmod +x "+remoteTest) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	_, err = q.Command("root", "chmod +x "+remoteTest) | 
					
						
							|  |  |  |  | 	return | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-15 11:48:25 +00:00
										 |  |  |  | func copyStandardModules(q *qemu.System, ki config.KernelInfo) (err error) { | 
					
						
							|  |  |  |  | 	_, err = q.Command("root", "mkdir -p /lib/modules") | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	return q.CopyDirectory("root", ki.ModulesPath, "/lib/modules/") | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-17 20:18:50 +00:00
										 |  |  |  | func whatever(swg *sizedwaitgroup.SizedWaitGroup, ka config.Artifact, | 
					
						
							|  |  |  |  | 	ki config.KernelInfo, binaryPath, testPath string, | 
					
						
							| 
									
										
										
										
											2019-08-16 18:30:46 +00:00
										 |  |  |  | 	qemuTimeout, dockerTimeout time.Duration, dist, tag string, | 
					
						
							| 
									
										
										
										
											2019-11-14 15:38:16 +00:00
										 |  |  |  | 	db *sql.DB, verbose bool) { | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	defer swg.Done() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	kernel := qemu.Kernel{KernelPath: ki.KernelPath, InitrdPath: ki.InitrdPath} | 
					
						
							| 
									
										
										
										
											2019-08-17 09:05:06 +00:00
										 |  |  |  | 	q, err := qemu.NewSystem(qemu.X86x64, kernel, ki.RootFS) | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2018-12-01 14:30:28 +00:00
										 |  |  |  | 		log.Println("Qemu creation error:", err) | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	q.Timeout = qemuTimeout | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-19 18:34:13 +00:00
										 |  |  |  | 	if ka.Qemu.Timeout.Duration != 0 { | 
					
						
							|  |  |  |  | 		q.Timeout = ka.Qemu.Timeout.Duration | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-19 19:03:59 +00:00
										 |  |  |  | 	if ka.Qemu.Cpus != 0 { | 
					
						
							|  |  |  |  | 		q.Cpus = ka.Qemu.Cpus | 
					
						
							| 
									
										
										
										
											2019-08-19 18:34:13 +00:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if ka.Qemu.Memory != 0 { | 
					
						
							|  |  |  |  | 		q.Memory = ka.Qemu.Memory | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-14 17:32:57 +00:00
										 |  |  |  | 	if ka.Docker.Timeout.Duration != 0 { | 
					
						
							|  |  |  |  | 		dockerTimeout = ka.Docker.Timeout.Duration | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-19 19:03:59 +00:00
										 |  |  |  | 	q.SetKASLR(!ka.Mitigations.DisableKaslr) | 
					
						
							|  |  |  |  | 	q.SetSMEP(!ka.Mitigations.DisableSmep) | 
					
						
							|  |  |  |  | 	q.SetSMAP(!ka.Mitigations.DisableSmap) | 
					
						
							| 
									
										
										
										
											2019-11-14 15:37:34 +00:00
										 |  |  |  | 	q.SetKPTI(!ka.Mitigations.DisableKpti) | 
					
						
							| 
									
										
										
										
											2019-08-19 18:34:13 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 	err = q.Start() | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2018-12-01 14:30:28 +00:00
										 |  |  |  | 		log.Println("Qemu start error:", err) | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer q.Stop() | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-14 15:38:16 +00:00
										 |  |  |  | 	if verbose { | 
					
						
							|  |  |  |  | 		go func() { | 
					
						
							|  |  |  |  | 			for !q.Died { | 
					
						
							|  |  |  |  | 				time.Sleep(time.Minute) | 
					
						
							|  |  |  |  | 				log.Println(ka.Name, ki.DistroType, | 
					
						
							|  |  |  |  | 					ki.DistroRelease, ki.KernelRelease, | 
					
						
							|  |  |  |  | 					"still alive") | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 		}() | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-16 04:43:29 +00:00
										 |  |  |  | 	usr, err := user.Current() | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	tmpdir := usr.HomeDir + "/.out-of-tree/tmp" | 
					
						
							|  |  |  |  | 	os.MkdirAll(tmpdir, os.ModePerm) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	tmp, err := ioutil.TempDir(tmpdir, "out-of-tree_") | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2018-12-01 14:30:28 +00:00
										 |  |  |  | 		log.Println("Temporary directory creation error:", err) | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer os.RemoveAll(tmp) | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-13 21:54:59 +00:00
										 |  |  |  | 	result := phasesResult{} | 
					
						
							| 
									
										
										
										
											2019-08-16 18:30:46 +00:00
										 |  |  |  | 	defer dumpResult(q, ka, ki, &result, dist, tag, binaryPath, db) | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if binaryPath == "" { | 
					
						
							| 
									
										
										
										
											2023-02-16 10:46:24 +00:00
										 |  |  |  | 		// TODO: build should return structure | 
					
						
							|  |  |  |  | 		result.BuildDir, result.BuildArtifact, result.Build.Output, err = | 
					
						
							|  |  |  |  | 			build(tmp, ka, ki, dockerTimeout) | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2019-08-16 04:43:29 +00:00
										 |  |  |  | 			log.Println(err) | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 			return | 
					
						
							|  |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-08-13 21:54:59 +00:00
										 |  |  |  | 		result.Build.Ok = true | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2019-08-14 17:36:36 +00:00
										 |  |  |  | 		result.BuildArtifact = binaryPath | 
					
						
							| 
									
										
										
										
											2019-08-13 21:54:59 +00:00
										 |  |  |  | 		result.Build.Ok = true | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if testPath == "" { | 
					
						
							| 
									
										
										
										
											2019-08-14 17:36:36 +00:00
										 |  |  |  | 		testPath = result.BuildArtifact + "_test" | 
					
						
							| 
									
										
										
										
											2019-08-18 15:04:24 +00:00
										 |  |  |  | 		if !exists(testPath) { | 
					
						
							| 
									
										
										
										
											2023-01-29 22:27:35 +00:00
										 |  |  |  | 			testPath = tmp + "/source/" + "test.sh" | 
					
						
							| 
									
										
										
										
											2019-08-18 15:04:24 +00:00
										 |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-16 06:27:17 +00:00
										 |  |  |  | 	err = q.WaitForSSH(qemuTimeout) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-17 10:00:01 +00:00
										 |  |  |  | 	remoteTest, err := copyTest(q, testPath, ka) | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2019-08-17 10:00:01 +00:00
										 |  |  |  | 		return | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-15 11:48:25 +00:00
										 |  |  |  | 	if ka.StandardModules { | 
					
						
							|  |  |  |  | 		// Module depends on one of the standard modules | 
					
						
							|  |  |  |  | 		err = copyStandardModules(q, ki) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			log.Println(err) | 
					
						
							|  |  |  |  | 			return | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-14 20:14:59 +00:00
										 |  |  |  | 	err = preloadModules(q, ka, ki, dockerTimeout) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		log.Println(err) | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-17 10:00:01 +00:00
										 |  |  |  | 	copyArtifactAndTest(q, ka, &result, remoteTest) | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-12 23:21:38 +00:00
										 |  |  |  | func shuffleKernels(a []config.KernelInfo) []config.KernelInfo { | 
					
						
							|  |  |  |  | 	// Fisher–Yates shuffle | 
					
						
							|  |  |  |  | 	for i := len(a) - 1; i > 0; i-- { | 
					
						
							|  |  |  |  | 		j := rand.Intn(i + 1) | 
					
						
							|  |  |  |  | 		a[i], a[j] = a[j], a[i] | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	return a | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-17 20:18:50 +00:00
										 |  |  |  | func performCI(ka config.Artifact, kcfg config.KernelConfig, binaryPath, | 
					
						
							| 
									
										
										
										
											2019-08-30 00:34:14 +00:00
										 |  |  |  | 	testPath string, stop time.Time, | 
					
						
							|  |  |  |  | 	qemuTimeout, dockerTimeout time.Duration, | 
					
						
							| 
									
										
										
										
											2019-08-16 18:50:34 +00:00
										 |  |  |  | 	max, runs int64, dist, tag string, threads int, | 
					
						
							| 
									
										
										
										
											2019-11-14 15:38:16 +00:00
										 |  |  |  | 	db *sql.DB, verbose bool) (err error) { | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	found := false | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-16 07:02:51 +00:00
										 |  |  |  | 	swg := sizedwaitgroup.New(threads) | 
					
						
							| 
									
										
										
										
											2019-08-12 23:21:38 +00:00
										 |  |  |  | 	for _, kernel := range shuffleKernels(kcfg.Kernels) { | 
					
						
							|  |  |  |  | 		if max <= 0 { | 
					
						
							|  |  |  |  | 			break | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 		var supported bool | 
					
						
							|  |  |  |  | 		supported, err = ka.Supported(kernel) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			return | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		if supported { | 
					
						
							|  |  |  |  | 			found = true | 
					
						
							| 
									
										
										
										
											2019-08-17 09:35:36 +00:00
										 |  |  |  | 			max-- | 
					
						
							| 
									
										
										
										
											2019-08-16 18:50:34 +00:00
										 |  |  |  | 			for i := int64(0); i < runs; i++ { | 
					
						
							| 
									
										
										
										
											2019-08-30 00:34:14 +00:00
										 |  |  |  | 				if !stop.IsZero() && time.Now().After(stop) { | 
					
						
							|  |  |  |  | 					break | 
					
						
							|  |  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2019-08-16 18:50:34 +00:00
										 |  |  |  | 				swg.Add() | 
					
						
							|  |  |  |  | 				go whatever(&swg, ka, kernel, binaryPath, | 
					
						
							|  |  |  |  | 					testPath, qemuTimeout, dockerTimeout, | 
					
						
							| 
									
										
										
										
											2019-11-14 15:38:16 +00:00
										 |  |  |  | 					dist, tag, db, verbose) | 
					
						
							| 
									
										
										
										
											2019-08-16 18:50:34 +00:00
										 |  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-11-17 19:37:04 +00:00
										 |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	swg.Wait() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if !found { | 
					
						
							|  |  |  |  | 		err = errors.New("No supported kernels found") | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	return | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func exists(path string) bool { | 
					
						
							|  |  |  |  | 	if _, err := os.Stat(path); err != nil { | 
					
						
							|  |  |  |  | 		return false | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	return true | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-25 14:43:58 +00:00
										 |  |  |  | func kernelMask(kernel string) (km config.KernelMask, err error) { | 
					
						
							|  |  |  |  | 	parts := strings.Split(kernel, ":") | 
					
						
							|  |  |  |  | 	if len(parts) != 2 { | 
					
						
							|  |  |  |  | 		err = errors.New("Kernel is not 'distroType:regex'") | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	dt, err := config.NewDistroType(parts[0]) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	km = config.KernelMask{DistroType: dt, ReleaseMask: parts[1]} | 
					
						
							|  |  |  |  | 	return | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-10 03:00:26 +00:00
										 |  |  |  | func genAllKernels() (sk []config.KernelMask, err error) { | 
					
						
							|  |  |  |  | 	for _, dType := range config.DistroTypeStrings { | 
					
						
							|  |  |  |  | 		var dt config.DistroType | 
					
						
							|  |  |  |  | 		dt, err = config.NewDistroType(dType) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			return | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		sk = append(sk, config.KernelMask{ | 
					
						
							|  |  |  |  | 			DistroType:  dt, | 
					
						
							|  |  |  |  | 			ReleaseMask: ".*", | 
					
						
							|  |  |  |  | 		}) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	return | 
					
						
							|  |  |  |  | } |