out-of-tree kernel {module, exploit} development tool
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

main.go 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. // Copyright 2018 Mikhail Klementev. All rights reserved.
  2. // Use of this source code is governed by a AGPLv3 license
  3. // (or later) that can be found in the LICENSE file.
  4. package main
  5. import (
  6. "log"
  7. "os"
  8. "os/exec"
  9. "os/user"
  10. "sort"
  11. kingpin "gopkg.in/alecthomas/kingpin.v2"
  12. "github.com/jollheef/out-of-tree/config"
  13. )
  14. func findFallback(kcfg config.KernelConfig, ki config.KernelInfo) (rootfs string) {
  15. for _, k := range kcfg.Kernels {
  16. if !exists(k.RootFS) || k.DistroType != ki.DistroType {
  17. continue
  18. }
  19. if k.RootFS < ki.RootFS {
  20. rootfs = k.RootFS
  21. return
  22. }
  23. }
  24. return
  25. }
  26. func handleFallbacks(kcfg config.KernelConfig) {
  27. sort.Sort(sort.Reverse(config.ByRootFS(kcfg.Kernels)))
  28. for i, k := range kcfg.Kernels {
  29. if !exists(k.RootFS) {
  30. newRootFS := findFallback(kcfg, k)
  31. s := k.RootFS + " does not exists "
  32. if newRootFS != "" {
  33. s += "(fallback to " + newRootFS + ")"
  34. } else {
  35. s += "(no fallback found)"
  36. }
  37. kcfg.Kernels[i].RootFS = newRootFS
  38. log.Println(s)
  39. }
  40. }
  41. }
  42. func main() {
  43. app := kingpin.New(
  44. "out-of-tree",
  45. "kernel {module, exploit} development tool",
  46. )
  47. app.Author("Mikhail Klementev <jollheef@riseup.net>")
  48. app.Version("0.2.0")
  49. pathFlag := app.Flag("path", "Path to work directory")
  50. path := pathFlag.Default(".").ExistingDir()
  51. usr, err := user.Current()
  52. if err != nil {
  53. return
  54. }
  55. defaultKcfgPath := usr.HomeDir + "/.out-of-tree/kernels.toml"
  56. kcfgPathFlag := app.Flag("kernels", "Path to main kernels config")
  57. kcfgPath := kcfgPathFlag.Default(defaultKcfgPath).String()
  58. defaultUserKcfgPath := usr.HomeDir + "/.out-of-tree/kernels.user.toml"
  59. userKcfgPathFlag := app.Flag("user-kernels", "User kernels config")
  60. userKcfgPathEnv := userKcfgPathFlag.Envar("OUT_OF_TREE_KCFG")
  61. userKcfgPath := userKcfgPathEnv.Default(defaultUserKcfgPath).String()
  62. qemuTimeoutFlag := app.Flag("qemu-timeout", "Timeout for qemu")
  63. qemuTimeout := qemuTimeoutFlag.Default("1m").Duration()
  64. dockerTimeoutFlag := app.Flag("docker-timeout", "Timeout for docker")
  65. dockerTimeout := dockerTimeoutFlag.Default("1m").Duration()
  66. pewCommand := app.Command("pew", "Build, run and test module/exploit")
  67. pewKernelFlag := pewCommand.Flag("kernel", "Override kernel regex")
  68. pewKernel := pewKernelFlag.String()
  69. pewGuessFlag := pewCommand.Flag("guess", "Try all defined kernels")
  70. pewGuess := pewGuessFlag.Bool()
  71. pewBinaryFlag := pewCommand.Flag("binary", "Use binary, do not build")
  72. pewBinary := pewBinaryFlag.String()
  73. pewTestFlag := pewCommand.Flag("test", "Override path test")
  74. pewTest := pewTestFlag.String()
  75. kernelCommand := app.Command("kernel", "Manipulate kernels")
  76. kernelListCommand := kernelCommand.Command("list", "List kernels")
  77. kernelAutogenCommand := kernelCommand.Command("autogen",
  78. "Generate kernels based on a current config")
  79. kernelDockerRegenCommand := kernelCommand.Command("docker-regen",
  80. "Regenerate kernels config from out_of_tree_* docker images")
  81. kernelGenallCommand := kernelCommand.Command("genall",
  82. "Generate all kernels for distro")
  83. genallDistroFlag := kernelGenallCommand.Flag("distro", "Distributive")
  84. distro := genallDistroFlag.Required().String()
  85. genallVerFlag := kernelGenallCommand.Flag("ver", "Distro version")
  86. version := genallVerFlag.Required().String()
  87. genCommand := app.Command("gen", "Generate .out-of-tree.toml skeleton")
  88. genModuleCommand := genCommand.Command("module",
  89. "Generate .out-of-tree.toml skeleton for kernel module")
  90. genExploitCommand := genCommand.Command("exploit",
  91. "Generate .out-of-tree.toml skeleton for kernel exploit")
  92. debugCommand := app.Command("debug", "Kernel debug environment")
  93. debugCommandFlag := debugCommand.Flag("kernel", "Regex (first match)")
  94. debugKernel := debugCommandFlag.Required().String()
  95. debugFlagGDB := debugCommand.Flag("gdb", "Set gdb listen address")
  96. debugGDB := debugFlagGDB.Default("tcp::1234").String()
  97. bootstrapCommand := app.Command("bootstrap",
  98. "Create directories && download images")
  99. // Check for required commands
  100. for _, cmd := range []string{"docker", "qemu-system-x86_64"} {
  101. _, err := exec.Command("which", cmd).CombinedOutput()
  102. if err != nil {
  103. log.Fatalln("Command not found:", cmd)
  104. }
  105. }
  106. if !exists(usr.HomeDir + "/.out-of-tree/images") {
  107. log.Println("No ~/.out-of-tree/images: " +
  108. "Probably you need to run `out-of-tree bootstrap`" +
  109. " for downloading basic images")
  110. }
  111. if !exists(usr.HomeDir + "/.out-of-tree/kernels.toml") {
  112. log.Println("No ~/.out-of-tree/kernels.toml: Probably you " +
  113. "need to run `out-of-tree kernel autogen` in " +
  114. "directory that contains .out-of-tree.toml " +
  115. "with defined kernel masks " +
  116. "(see docs at https://out-of-tree.io)")
  117. }
  118. kingpin.MustParse(app.Parse(os.Args[1:]))
  119. kcfg, err := config.ReadKernelConfig(*kcfgPath)
  120. if err != nil {
  121. log.Println(err)
  122. }
  123. if exists(*userKcfgPath) {
  124. userKcfg, err := config.ReadKernelConfig(*userKcfgPath)
  125. if err != nil {
  126. log.Fatalln(err)
  127. }
  128. for _, nk := range userKcfg.Kernels {
  129. if !hasKernel(nk, kcfg) {
  130. kcfg.Kernels = append(kcfg.Kernels, nk)
  131. }
  132. }
  133. }
  134. handleFallbacks(kcfg)
  135. switch kingpin.MustParse(app.Parse(os.Args[1:])) {
  136. case pewCommand.FullCommand():
  137. err = pewHandler(kcfg, *path, *pewKernel, *pewBinary,
  138. *pewTest, *pewGuess, *qemuTimeout, *dockerTimeout)
  139. case kernelListCommand.FullCommand():
  140. err = kernelListHandler(kcfg)
  141. case kernelAutogenCommand.FullCommand():
  142. err = kernelAutogenHandler(*path)
  143. case kernelDockerRegenCommand.FullCommand():
  144. err = kernelDockerRegenHandler()
  145. case kernelGenallCommand.FullCommand():
  146. err = kernelGenallHandler(*distro, *version)
  147. case genModuleCommand.FullCommand():
  148. err = genConfig(config.KernelModule)
  149. case genExploitCommand.FullCommand():
  150. err = genConfig(config.KernelExploit)
  151. case debugCommand.FullCommand():
  152. err = debugHandler(kcfg, *path, *debugKernel, *debugGDB,
  153. *dockerTimeout)
  154. case bootstrapCommand.FullCommand():
  155. err = bootstrapHandler()
  156. }
  157. if err != nil {
  158. log.Fatalln(err)
  159. }
  160. if somethingFailed {
  161. os.Exit(1)
  162. }
  163. }