2018-10-06 19:25:03 +00:00
|
|
|
// Copyright 2018 Mikhail Klementev. All rights reserved.
|
2018-10-08 20:51:32 +00:00
|
|
|
// Use of this source code is governed by a AGPLv3 license
|
2018-10-06 19:25:03 +00:00
|
|
|
// (or later) that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2018-12-10 02:51:15 +00:00
|
|
|
"fmt"
|
2018-10-06 19:25:03 +00:00
|
|
|
"log"
|
2019-08-12 22:58:34 +00:00
|
|
|
"math/rand"
|
2018-10-06 19:25:03 +00:00
|
|
|
"os"
|
2018-11-19 15:31:25 +00:00
|
|
|
"os/exec"
|
2018-11-17 13:44:03 +00:00
|
|
|
"os/user"
|
2019-08-16 07:02:51 +00:00
|
|
|
"runtime"
|
2018-12-01 20:18:43 +00:00
|
|
|
"sort"
|
2019-08-16 07:02:51 +00:00
|
|
|
"strconv"
|
2019-08-12 22:58:34 +00:00
|
|
|
"time"
|
2018-10-06 19:25:03 +00:00
|
|
|
|
2018-10-26 18:26:43 +00:00
|
|
|
kingpin "gopkg.in/alecthomas/kingpin.v2"
|
2018-11-17 20:18:50 +00:00
|
|
|
|
2019-02-02 21:24:29 +00:00
|
|
|
"code.dumpstack.io/tools/out-of-tree/config"
|
2018-10-06 19:25:03 +00:00
|
|
|
)
|
|
|
|
|
2018-12-01 20:18:43 +00:00
|
|
|
func findFallback(kcfg config.KernelConfig, ki config.KernelInfo) (rootfs string) {
|
|
|
|
for _, k := range kcfg.Kernels {
|
|
|
|
if !exists(k.RootFS) || k.DistroType != ki.DistroType {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if k.RootFS < ki.RootFS {
|
|
|
|
rootfs = k.RootFS
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func handleFallbacks(kcfg config.KernelConfig) {
|
|
|
|
sort.Sort(sort.Reverse(config.ByRootFS(kcfg.Kernels)))
|
|
|
|
|
|
|
|
for i, k := range kcfg.Kernels {
|
|
|
|
if !exists(k.RootFS) {
|
|
|
|
newRootFS := findFallback(kcfg, k)
|
|
|
|
|
|
|
|
s := k.RootFS + " does not exists "
|
|
|
|
if newRootFS != "" {
|
|
|
|
s += "(fallback to " + newRootFS + ")"
|
|
|
|
} else {
|
|
|
|
s += "(no fallback found)"
|
|
|
|
}
|
|
|
|
|
|
|
|
kcfg.Kernels[i].RootFS = newRootFS
|
|
|
|
log.Println(s)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-10 02:51:15 +00:00
|
|
|
func checkRequiredUtils() (err error) {
|
|
|
|
// Check for required commands
|
|
|
|
for _, cmd := range []string{"docker", "qemu-system-x86_64"} {
|
|
|
|
_, err := exec.Command("which", cmd).CombinedOutput()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Command not found: %s", cmd)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-07-10 22:08:04 +00:00
|
|
|
func checkDockerPermissions() (err error) {
|
|
|
|
output, err := exec.Command("docker", "ps").CombinedOutput()
|
|
|
|
if err != nil {
|
2019-08-14 17:36:36 +00:00
|
|
|
err = fmt.Errorf("%s", output)
|
2019-07-10 22:08:04 +00:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-10-26 18:26:43 +00:00
|
|
|
func main() {
|
2019-08-16 00:04:57 +00:00
|
|
|
log.SetFlags(log.Lshortfile)
|
|
|
|
|
2019-08-12 22:58:34 +00:00
|
|
|
rand.Seed(time.Now().UnixNano())
|
|
|
|
|
2018-10-27 08:14:10 +00:00
|
|
|
app := kingpin.New(
|
|
|
|
"out-of-tree",
|
|
|
|
"kernel {module, exploit} development tool",
|
|
|
|
)
|
|
|
|
|
2019-08-13 21:57:01 +00:00
|
|
|
app.Author("Mikhail Klementev <root@dumpstack.io>")
|
2018-12-01 18:12:44 +00:00
|
|
|
app.Version("0.2.0")
|
2018-10-27 08:14:10 +00:00
|
|
|
|
|
|
|
pathFlag := app.Flag("path", "Path to work directory")
|
2018-10-27 07:48:06 +00:00
|
|
|
path := pathFlag.Default(".").ExistingDir()
|
|
|
|
|
2018-11-17 13:44:03 +00:00
|
|
|
usr, err := user.Current()
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
2019-08-14 07:15:04 +00:00
|
|
|
os.MkdirAll(usr.HomeDir+"/.out-of-tree", os.ModePerm)
|
|
|
|
|
2018-11-17 13:44:03 +00:00
|
|
|
defaultKcfgPath := usr.HomeDir + "/.out-of-tree/kernels.toml"
|
|
|
|
|
2018-12-01 16:57:15 +00:00
|
|
|
kcfgPathFlag := app.Flag("kernels", "Path to main kernels config")
|
2018-12-02 20:23:48 +00:00
|
|
|
kcfgPath := kcfgPathFlag.Default(defaultKcfgPath).String()
|
2018-12-01 16:57:15 +00:00
|
|
|
|
2019-08-13 21:54:59 +00:00
|
|
|
defaultDbPath := usr.HomeDir + "/.out-of-tree/db.sqlite"
|
|
|
|
dbPathFlag := app.Flag("db", "Path to database")
|
|
|
|
dbPath := dbPathFlag.Default(defaultDbPath).String()
|
|
|
|
|
2018-12-01 16:57:15 +00:00
|
|
|
defaultUserKcfgPath := usr.HomeDir + "/.out-of-tree/kernels.user.toml"
|
|
|
|
userKcfgPathFlag := app.Flag("user-kernels", "User kernels config")
|
|
|
|
userKcfgPathEnv := userKcfgPathFlag.Envar("OUT_OF_TREE_KCFG")
|
|
|
|
userKcfgPath := userKcfgPathEnv.Default(defaultUserKcfgPath).String()
|
2018-10-27 07:48:06 +00:00
|
|
|
|
2018-10-27 19:06:24 +00:00
|
|
|
qemuTimeoutFlag := app.Flag("qemu-timeout", "Timeout for qemu")
|
|
|
|
qemuTimeout := qemuTimeoutFlag.Default("1m").Duration()
|
|
|
|
|
|
|
|
dockerTimeoutFlag := app.Flag("docker-timeout", "Timeout for docker")
|
|
|
|
dockerTimeout := dockerTimeoutFlag.Default("1m").Duration()
|
2019-08-16 18:50:34 +00:00
|
|
|
|
2018-10-27 08:14:10 +00:00
|
|
|
pewCommand := app.Command("pew", "Build, run and test module/exploit")
|
2019-08-16 18:50:34 +00:00
|
|
|
|
2019-08-12 23:21:38 +00:00
|
|
|
pewMax := pewCommand.Flag("max", "Test no more than X kernels").
|
|
|
|
PlaceHolder("X").Default(fmt.Sprint(KERNELS_ALL)).Int64()
|
2019-08-16 18:50:34 +00:00
|
|
|
|
|
|
|
pewRuns := pewCommand.Flag("runs", "Runs per each kernel").
|
|
|
|
Default("1").Int64()
|
|
|
|
|
2018-10-27 15:09:28 +00:00
|
|
|
pewKernelFlag := pewCommand.Flag("kernel", "Override kernel regex")
|
|
|
|
pewKernel := pewKernelFlag.String()
|
2018-10-26 18:26:43 +00:00
|
|
|
|
2018-10-27 15:33:54 +00:00
|
|
|
pewGuessFlag := pewCommand.Flag("guess", "Try all defined kernels")
|
|
|
|
pewGuess := pewGuessFlag.Bool()
|
|
|
|
|
2018-10-27 19:35:47 +00:00
|
|
|
pewBinaryFlag := pewCommand.Flag("binary", "Use binary, do not build")
|
|
|
|
pewBinary := pewBinaryFlag.String()
|
|
|
|
|
|
|
|
pewTestFlag := pewCommand.Flag("test", "Override path test")
|
|
|
|
pewTest := pewTestFlag.String()
|
|
|
|
|
2019-08-14 17:36:36 +00:00
|
|
|
pewDistFlag := pewCommand.Flag("dist", "Build result path")
|
|
|
|
pewDist := pewDistFlag.Default(PATH_DEV_NULL).String()
|
|
|
|
|
2019-08-16 07:02:51 +00:00
|
|
|
pewThreadsFlag := pewCommand.Flag("threads", "Build result path")
|
|
|
|
pewThreads := pewThreadsFlag.Default(strconv.Itoa(runtime.NumCPU())).Int()
|
|
|
|
|
2019-08-16 18:30:46 +00:00
|
|
|
pewTagFlag := pewCommand.Flag("tag", "Log tagging")
|
|
|
|
pewTag := pewTagFlag.String()
|
|
|
|
|
2018-11-17 13:20:29 +00:00
|
|
|
kernelCommand := app.Command("kernel", "Manipulate kernels")
|
2019-08-16 05:05:26 +00:00
|
|
|
kernelUseHost := kernelCommand.Flag("host", "Use also host kernels").Bool()
|
2018-11-17 13:20:29 +00:00
|
|
|
kernelListCommand := kernelCommand.Command("list", "List kernels")
|
2018-11-28 22:41:17 +00:00
|
|
|
kernelAutogenCommand := kernelCommand.Command("autogen",
|
|
|
|
"Generate kernels based on a current config")
|
2019-08-12 22:58:34 +00:00
|
|
|
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(KERNELS_ALL)).Int64()
|
2018-12-01 15:11:43 +00:00
|
|
|
kernelDockerRegenCommand := kernelCommand.Command("docker-regen",
|
|
|
|
"Regenerate kernels config from out_of_tree_* docker images")
|
2018-12-02 19:54:09 +00:00
|
|
|
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()
|
2018-11-17 13:20:29 +00:00
|
|
|
|
2018-11-23 09:11:18 +00:00
|
|
|
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")
|
|
|
|
|
2018-11-25 14:46:29 +00:00
|
|
|
debugCommand := app.Command("debug", "Kernel debug environment")
|
|
|
|
debugCommandFlag := debugCommand.Flag("kernel", "Regex (first match)")
|
|
|
|
debugKernel := debugCommandFlag.Required().String()
|
2018-11-25 14:53:56 +00:00
|
|
|
debugFlagGDB := debugCommand.Flag("gdb", "Set gdb listen address")
|
|
|
|
debugGDB := debugFlagGDB.Default("tcp::1234").String()
|
2018-11-25 14:46:29 +00:00
|
|
|
|
2019-08-16 05:25:16 +00:00
|
|
|
kaslr := debugCommand.Flag("enable-kaslr", "Enable KASLR").Default("false").Bool()
|
|
|
|
nosmep := debugCommand.Flag("disable-smep", "Disable SMEP").Default("false").Bool()
|
|
|
|
nosmap := debugCommand.Flag("disable-smap", "Disable SMAP").Default("false").Bool()
|
|
|
|
|
2018-12-01 17:34:57 +00:00
|
|
|
bootstrapCommand := app.Command("bootstrap",
|
|
|
|
"Create directories && download images")
|
|
|
|
|
2019-08-13 23:54:45 +00:00
|
|
|
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()
|
2019-08-16 18:30:46 +00:00
|
|
|
logTag := logQueryCommand.Flag("tag", "Filter tag").String()
|
2019-08-13 23:54:45 +00:00
|
|
|
|
|
|
|
logDumpCommand := logCommand.Command("dump",
|
|
|
|
"Show all info for log entry with ID")
|
|
|
|
logDumpID := logDumpCommand.Arg("ID", "").Required().Int()
|
2019-08-13 23:33:52 +00:00
|
|
|
|
2019-08-16 19:31:58 +00:00
|
|
|
logJsonCommand := logCommand.Command("json", "Generate json statistics")
|
|
|
|
logJsonTag := logJsonCommand.Flag("tag", "Filter tag").Required().String()
|
|
|
|
|
2019-08-16 20:11:35 +00:00
|
|
|
logMarkdownCommand := logCommand.Command("markdown", "Generate markdown statistics")
|
|
|
|
logMarkdownTag := logMarkdownCommand.Flag("tag", "Filter tag").Required().String()
|
|
|
|
|
2018-12-10 02:51:15 +00:00
|
|
|
err = checkRequiredUtils()
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalln(err)
|
2018-11-19 15:31:25 +00:00
|
|
|
}
|
|
|
|
|
2019-07-10 22:08:04 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2018-12-02 03:39:54 +00:00
|
|
|
if !exists(usr.HomeDir + "/.out-of-tree/images") {
|
|
|
|
log.Println("No ~/.out-of-tree/images: " +
|
|
|
|
"Probably you need to run `out-of-tree bootstrap`" +
|
|
|
|
" for downloading basic images")
|
|
|
|
}
|
|
|
|
|
|
|
|
if !exists(usr.HomeDir + "/.out-of-tree/kernels.toml") {
|
|
|
|
log.Println("No ~/.out-of-tree/kernels.toml: Probably you " +
|
2018-12-02 20:25:33 +00:00
|
|
|
"need to run `out-of-tree kernel autogen` in " +
|
2018-12-02 03:39:54 +00:00
|
|
|
"directory that contains .out-of-tree.toml " +
|
|
|
|
"with defined kernel masks " +
|
|
|
|
"(see docs at https://out-of-tree.io)")
|
2018-12-02 03:19:41 +00:00
|
|
|
}
|
|
|
|
|
2018-11-17 13:44:03 +00:00
|
|
|
kingpin.MustParse(app.Parse(os.Args[1:]))
|
|
|
|
|
2018-11-17 20:18:50 +00:00
|
|
|
kcfg, err := config.ReadKernelConfig(*kcfgPath)
|
2018-11-17 13:17:28 +00:00
|
|
|
if err != nil {
|
2018-12-02 20:20:59 +00:00
|
|
|
log.Println(err)
|
2018-11-17 13:17:28 +00:00
|
|
|
}
|
|
|
|
|
2018-12-01 16:57:15 +00:00
|
|
|
if exists(*userKcfgPath) {
|
|
|
|
userKcfg, err := config.ReadKernelConfig(*userKcfgPath)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalln(err)
|
|
|
|
}
|
|
|
|
|
2018-12-01 17:13:38 +00:00
|
|
|
for _, nk := range userKcfg.Kernels {
|
|
|
|
if !hasKernel(nk, kcfg) {
|
|
|
|
kcfg.Kernels = append(kcfg.Kernels, nk)
|
|
|
|
}
|
|
|
|
}
|
2018-12-01 16:57:15 +00:00
|
|
|
}
|
|
|
|
|
2018-12-01 20:18:43 +00:00
|
|
|
handleFallbacks(kcfg)
|
|
|
|
|
2019-08-13 21:54:59 +00:00
|
|
|
db, err := openDatabase(*dbPath)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalln(err)
|
|
|
|
}
|
|
|
|
defer db.Close()
|
|
|
|
|
2018-10-27 08:14:10 +00:00
|
|
|
switch kingpin.MustParse(app.Parse(os.Args[1:])) {
|
|
|
|
case pewCommand.FullCommand():
|
2018-11-17 13:17:28 +00:00
|
|
|
err = pewHandler(kcfg, *path, *pewKernel, *pewBinary,
|
2019-08-12 23:21:38 +00:00
|
|
|
*pewTest, *pewGuess, *qemuTimeout, *dockerTimeout,
|
2019-08-16 18:50:34 +00:00
|
|
|
*pewMax, *pewRuns, *pewDist, *pewTag, *pewThreads, db)
|
2018-11-17 13:20:29 +00:00
|
|
|
case kernelListCommand.FullCommand():
|
|
|
|
err = kernelListHandler(kcfg)
|
2018-11-28 22:41:17 +00:00
|
|
|
case kernelAutogenCommand.FullCommand():
|
2019-08-16 05:05:26 +00:00
|
|
|
err = kernelAutogenHandler(*path, *kernelAutogenMax, *kernelUseHost)
|
2018-12-01 15:11:43 +00:00
|
|
|
case kernelDockerRegenCommand.FullCommand():
|
2019-08-16 05:05:26 +00:00
|
|
|
err = kernelDockerRegenHandler(*kernelUseHost)
|
2018-12-02 19:54:09 +00:00
|
|
|
case kernelGenallCommand.FullCommand():
|
2019-08-16 05:05:26 +00:00
|
|
|
err = kernelGenallHandler(*distro, *version, *kernelUseHost)
|
2018-11-23 09:11:18 +00:00
|
|
|
case genModuleCommand.FullCommand():
|
|
|
|
err = genConfig(config.KernelModule)
|
|
|
|
case genExploitCommand.FullCommand():
|
|
|
|
err = genConfig(config.KernelExploit)
|
2018-11-25 14:46:29 +00:00
|
|
|
case debugCommand.FullCommand():
|
2018-11-25 14:53:56 +00:00
|
|
|
err = debugHandler(kcfg, *path, *debugKernel, *debugGDB,
|
2019-08-16 05:25:16 +00:00
|
|
|
*dockerTimeout, *kaslr, !*nosmep, !*nosmap)
|
2018-12-01 17:34:57 +00:00
|
|
|
case bootstrapCommand.FullCommand():
|
|
|
|
err = bootstrapHandler()
|
2019-08-13 23:54:45 +00:00
|
|
|
case logQueryCommand.FullCommand():
|
2019-08-16 18:30:46 +00:00
|
|
|
err = logHandler(db, *path, *logTag, *logNum, *logRate)
|
2019-08-13 23:54:45 +00:00
|
|
|
case logDumpCommand.FullCommand():
|
|
|
|
err = logDumpHandler(db, *logDumpID)
|
2019-08-16 19:31:58 +00:00
|
|
|
case logJsonCommand.FullCommand():
|
|
|
|
err = logJsonHandler(db, *path, *logJsonTag)
|
2019-08-16 20:11:35 +00:00
|
|
|
case logMarkdownCommand.FullCommand():
|
|
|
|
err = logMarkdownHandler(db, *path, *logMarkdownTag)
|
2018-10-26 18:26:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
2018-11-17 13:28:56 +00:00
|
|
|
log.Fatalln(err)
|
2018-10-26 18:26:43 +00:00
|
|
|
}
|
2018-12-07 03:14:10 +00:00
|
|
|
|
|
|
|
if somethingFailed {
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
2018-10-06 19:25:03 +00:00
|
|
|
}
|