173 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			173 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// 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 (
 | 
						|
	"log"
 | 
						|
	"os"
 | 
						|
	"os/exec"
 | 
						|
	"os/user"
 | 
						|
	"sort"
 | 
						|
 | 
						|
	kingpin "gopkg.in/alecthomas/kingpin.v2"
 | 
						|
 | 
						|
	"github.com/jollheef/out-of-tree/config"
 | 
						|
)
 | 
						|
 | 
						|
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)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func main() {
 | 
						|
	app := kingpin.New(
 | 
						|
		"out-of-tree",
 | 
						|
		"kernel {module, exploit} development tool",
 | 
						|
	)
 | 
						|
 | 
						|
	app.Author("Mikhail Klementev <jollheef@riseup.net>")
 | 
						|
	app.Version("0.2.0")
 | 
						|
 | 
						|
	pathFlag := app.Flag("path", "Path to work directory")
 | 
						|
	path := pathFlag.Default(".").ExistingDir()
 | 
						|
 | 
						|
	usr, err := user.Current()
 | 
						|
	if err != nil {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	defaultKcfgPath := usr.HomeDir + "/.out-of-tree/kernels.toml"
 | 
						|
 | 
						|
	kcfgPathFlag := app.Flag("kernels", "Path to main kernels config")
 | 
						|
	kcfgPath := kcfgPathFlag.Default(defaultKcfgPath).ExistingFile()
 | 
						|
 | 
						|
	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()
 | 
						|
 | 
						|
	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()
 | 
						|
	pewCommand := app.Command("pew", "Build, run and test module/exploit")
 | 
						|
	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()
 | 
						|
 | 
						|
	kernelCommand := app.Command("kernel", "Manipulate kernels")
 | 
						|
	kernelListCommand := kernelCommand.Command("list", "List kernels")
 | 
						|
	kernelAutogenCommand := kernelCommand.Command("autogen",
 | 
						|
		"Generate kernels based on a current config")
 | 
						|
	kernelDockerRegenCommand := kernelCommand.Command("docker-regen",
 | 
						|
		"Regenerate kernels config from out_of_tree_* docker images")
 | 
						|
 | 
						|
	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()
 | 
						|
 | 
						|
	bootstrapCommand := app.Command("bootstrap",
 | 
						|
		"Create directories && download images")
 | 
						|
 | 
						|
	// Check for required commands
 | 
						|
	for _, cmd := range []string{"timeout", "docker", "qemu"} {
 | 
						|
		_, err := exec.Command("which", cmd).CombinedOutput()
 | 
						|
		if err != nil {
 | 
						|
			log.Fatalln("Command not found:", cmd)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	kingpin.MustParse(app.Parse(os.Args[1:]))
 | 
						|
 | 
						|
	kcfg, err := config.ReadKernelConfig(*kcfgPath)
 | 
						|
	if err != nil {
 | 
						|
		log.Fatalln(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)
 | 
						|
 | 
						|
	switch kingpin.MustParse(app.Parse(os.Args[1:])) {
 | 
						|
	case pewCommand.FullCommand():
 | 
						|
		err = pewHandler(kcfg, *path, *pewKernel, *pewBinary,
 | 
						|
			*pewTest, *pewGuess, *qemuTimeout, *dockerTimeout)
 | 
						|
	case kernelListCommand.FullCommand():
 | 
						|
		err = kernelListHandler(kcfg)
 | 
						|
	case kernelAutogenCommand.FullCommand():
 | 
						|
		err = kernelAutogenHandler(*path)
 | 
						|
	case kernelDockerRegenCommand.FullCommand():
 | 
						|
		err = kernelDockerRegenHandler()
 | 
						|
	case genModuleCommand.FullCommand():
 | 
						|
		err = genConfig(config.KernelModule)
 | 
						|
	case genExploitCommand.FullCommand():
 | 
						|
		err = genConfig(config.KernelExploit)
 | 
						|
	case debugCommand.FullCommand():
 | 
						|
		err = debugHandler(kcfg, *path, *debugKernel, *debugGDB,
 | 
						|
			*dockerTimeout)
 | 
						|
	case bootstrapCommand.FullCommand():
 | 
						|
		err = bootstrapHandler()
 | 
						|
	}
 | 
						|
 | 
						|
	if err != nil {
 | 
						|
		log.Fatalln(err)
 | 
						|
	}
 | 
						|
}
 |