feat: initial daemon implementation
This commit is contained in:
215
config/config.go
215
config/config.go
@ -5,214 +5,14 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"code.dumpstack.io/tools/out-of-tree/distro"
|
||||
|
||||
"github.com/naoina/toml"
|
||||
)
|
||||
|
||||
type Kernel struct {
|
||||
// TODO
|
||||
// Version string
|
||||
// From string
|
||||
// To string
|
||||
|
||||
// prev. ReleaseMask
|
||||
Regex string
|
||||
ExcludeRegex string
|
||||
}
|
||||
|
||||
// Target defines the kernel
|
||||
type Target struct {
|
||||
Distro distro.Distro
|
||||
|
||||
Kernel Kernel
|
||||
}
|
||||
|
||||
// DockerName is returns stable name for docker container
|
||||
func (km Target) DockerName() string {
|
||||
distro := strings.ToLower(km.Distro.ID.String())
|
||||
release := strings.Replace(km.Distro.Release, ".", "__", -1)
|
||||
return fmt.Sprintf("out_of_tree_%s_%s", distro, release)
|
||||
}
|
||||
|
||||
// ArtifactType is the kernel module or exploit
|
||||
type ArtifactType int
|
||||
|
||||
const (
|
||||
// KernelModule is any kind of kernel module
|
||||
KernelModule ArtifactType = iota
|
||||
// KernelExploit is the privilege escalation exploit
|
||||
KernelExploit
|
||||
// Script for information gathering or automation
|
||||
Script
|
||||
)
|
||||
|
||||
func (at ArtifactType) String() string {
|
||||
return [...]string{"module", "exploit", "script"}[at]
|
||||
}
|
||||
|
||||
// UnmarshalTOML is for support github.com/naoina/toml
|
||||
func (at *ArtifactType) UnmarshalTOML(data []byte) (err error) {
|
||||
stype := strings.Trim(string(data), `"`)
|
||||
stypelower := strings.ToLower(stype)
|
||||
if strings.Contains(stypelower, "module") {
|
||||
*at = KernelModule
|
||||
} else if strings.Contains(stypelower, "exploit") {
|
||||
*at = KernelExploit
|
||||
} else if strings.Contains(stypelower, "script") {
|
||||
*at = Script
|
||||
} else {
|
||||
err = fmt.Errorf("Type %s is unsupported", stype)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// MarshalTOML is for support github.com/naoina/toml
|
||||
func (at ArtifactType) MarshalTOML() (data []byte, err error) {
|
||||
s := ""
|
||||
switch at {
|
||||
case KernelModule:
|
||||
s = "module"
|
||||
case KernelExploit:
|
||||
s = "exploit"
|
||||
case Script:
|
||||
s = "script"
|
||||
default:
|
||||
err = fmt.Errorf("Cannot marshal %d", at)
|
||||
}
|
||||
data = []byte(`"` + s + `"`)
|
||||
return
|
||||
}
|
||||
|
||||
// Duration type with toml unmarshalling support
|
||||
type Duration struct {
|
||||
time.Duration
|
||||
}
|
||||
|
||||
// UnmarshalTOML for Duration
|
||||
func (d *Duration) UnmarshalTOML(data []byte) (err error) {
|
||||
duration := strings.Replace(string(data), "\"", "", -1)
|
||||
d.Duration, err = time.ParseDuration(duration)
|
||||
return
|
||||
}
|
||||
|
||||
// MarshalTOML for Duration
|
||||
func (d Duration) MarshalTOML() (data []byte, err error) {
|
||||
data = []byte(`"` + d.Duration.String() + `"`)
|
||||
return
|
||||
}
|
||||
|
||||
type PreloadModule struct {
|
||||
Repo string
|
||||
Path string
|
||||
TimeoutAfterLoad Duration
|
||||
}
|
||||
|
||||
// Extra test files to copy over
|
||||
type FileTransfer struct {
|
||||
User string
|
||||
Local string
|
||||
Remote string
|
||||
}
|
||||
|
||||
type Patch struct {
|
||||
Path string
|
||||
Source string
|
||||
Script string
|
||||
}
|
||||
|
||||
// Artifact is for .out-of-tree.toml
|
||||
type Artifact struct {
|
||||
Name string
|
||||
Type ArtifactType
|
||||
TestFiles []FileTransfer
|
||||
SourcePath string
|
||||
Targets []Target
|
||||
|
||||
Script string
|
||||
|
||||
Qemu struct {
|
||||
Cpus int
|
||||
Memory int
|
||||
Timeout Duration
|
||||
}
|
||||
|
||||
Docker struct {
|
||||
Timeout Duration
|
||||
}
|
||||
|
||||
Mitigations struct {
|
||||
DisableSmep bool
|
||||
DisableSmap bool
|
||||
DisableKaslr bool
|
||||
DisableKpti bool
|
||||
}
|
||||
|
||||
Patches []Patch
|
||||
|
||||
Make struct {
|
||||
Target string
|
||||
}
|
||||
|
||||
StandardModules bool
|
||||
|
||||
Preload []PreloadModule
|
||||
}
|
||||
|
||||
func (ka Artifact) checkSupport(ki distro.KernelInfo, target Target) (
|
||||
supported bool, err error) {
|
||||
|
||||
if target.Distro.Release == "" {
|
||||
if ki.Distro.ID != target.Distro.ID {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if !ki.Distro.Equal(target.Distro) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
r, err := regexp.Compile(target.Kernel.Regex)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
exr, err := regexp.Compile(target.Kernel.ExcludeRegex)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !r.MatchString(ki.KernelRelease) {
|
||||
return
|
||||
}
|
||||
|
||||
if target.Kernel.ExcludeRegex != "" && exr.MatchString(ki.KernelRelease) {
|
||||
return
|
||||
}
|
||||
|
||||
supported = true
|
||||
return
|
||||
}
|
||||
|
||||
// Supported returns true if given kernel is supported by artifact
|
||||
func (ka Artifact) Supported(ki distro.KernelInfo) (supported bool, err error) {
|
||||
for _, km := range ka.Targets {
|
||||
supported, err = ka.checkSupport(ki, km)
|
||||
if supported {
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// KernelConfig is the ~/.out-of-tree/kernels.toml configuration description
|
||||
type KernelConfig struct {
|
||||
Kernels []distro.KernelInfo
|
||||
@ -225,7 +25,7 @@ func readFileAll(path string) (buf []byte, err error) {
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
buf, err = ioutil.ReadAll(f)
|
||||
buf, err = io.ReadAll(f)
|
||||
return
|
||||
}
|
||||
|
||||
@ -243,14 +43,3 @@ func ReadKernelConfig(path string) (kernelCfg KernelConfig, err error) {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ReadArtifactConfig is for read .out-of-tree.toml
|
||||
func ReadArtifactConfig(path string) (ka Artifact, err error) {
|
||||
buf, err := readFileAll(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = toml.Unmarshal(buf, &ka)
|
||||
return
|
||||
}
|
||||
|
@ -1,40 +0,0 @@
|
||||
// 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 config
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"code.dumpstack.io/tools/out-of-tree/distro"
|
||||
|
||||
"github.com/naoina/toml"
|
||||
)
|
||||
|
||||
func TestMarshalUnmarshal(t *testing.T) {
|
||||
artifactCfg := Artifact{
|
||||
Name: "Put name here",
|
||||
Type: KernelModule,
|
||||
}
|
||||
artifactCfg.Targets = append(artifactCfg.Targets,
|
||||
Target{
|
||||
Distro: distro.Distro{
|
||||
ID: distro.Ubuntu,
|
||||
Release: "18.04",
|
||||
},
|
||||
Kernel: Kernel{
|
||||
Regex: ".*",
|
||||
},
|
||||
})
|
||||
buf, err := toml.Marshal(&artifactCfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var artifactCfgNew Artifact
|
||||
err = toml.Unmarshal(buf, &artifactCfgNew)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package config
|
||||
package dotfiles
|
||||
|
||||
import (
|
||||
"os"
|
@ -1,7 +1,6 @@
|
||||
package config
|
||||
package dotfiles
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
@ -18,7 +17,7 @@ func TestDirectory(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDir(t *testing.T) {
|
||||
tmpdir, err := ioutil.TempDir("", "out-of-tree_")
|
||||
tmpdir, err := os.MkdirTemp("", "out-of-tree_")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -64,7 +63,7 @@ func TestDir(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFile(t *testing.T) {
|
||||
tmpdir, err := ioutil.TempDir("", "out-of-tree_")
|
||||
tmpdir, err := os.MkdirTemp("", "out-of-tree_")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
@ -9,6 +9,8 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"code.dumpstack.io/tools/out-of-tree/artifact"
|
||||
"code.dumpstack.io/tools/out-of-tree/config/dotfiles"
|
||||
"code.dumpstack.io/tools/out-of-tree/distro"
|
||||
|
||||
"github.com/alecthomas/kong"
|
||||
@ -16,11 +18,6 @@ import (
|
||||
"github.com/naoina/toml"
|
||||
)
|
||||
|
||||
type DockerCommand struct {
|
||||
Distro distro.Distro
|
||||
Command string
|
||||
}
|
||||
|
||||
type OutOfTree struct {
|
||||
// Directory for all files if not explicitly specified
|
||||
Directory string
|
||||
@ -31,16 +28,16 @@ type OutOfTree struct {
|
||||
Database string
|
||||
|
||||
Qemu struct {
|
||||
Timeout Duration
|
||||
Timeout artifact.Duration
|
||||
}
|
||||
|
||||
Docker struct {
|
||||
Timeout Duration
|
||||
Timeout artifact.Duration
|
||||
Registry string
|
||||
|
||||
// Commands that will be executed before
|
||||
// the base layer of Dockerfile
|
||||
Commands []DockerCommand
|
||||
Commands []distro.Command
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,21 +79,21 @@ func ReadOutOfTreeConf(path string) (c OutOfTree, err error) {
|
||||
}
|
||||
|
||||
if c.Directory != "" {
|
||||
Directory = c.Directory
|
||||
dotfiles.Directory = c.Directory
|
||||
} else {
|
||||
c.Directory = Dir("")
|
||||
c.Directory = dotfiles.Dir("")
|
||||
}
|
||||
|
||||
if c.Kernels == "" {
|
||||
c.Kernels = File("kernels.toml")
|
||||
c.Kernels = dotfiles.File("kernels.toml")
|
||||
}
|
||||
|
||||
if c.UserKernels == "" {
|
||||
c.UserKernels = File("kernels.user.toml")
|
||||
c.UserKernels = dotfiles.File("kernels.user.toml")
|
||||
}
|
||||
|
||||
if c.Database == "" {
|
||||
c.Database = File("db.sqlite")
|
||||
c.Database = dotfiles.File("db.sqlite")
|
||||
}
|
||||
|
||||
if c.Qemu.Timeout.Duration == 0 {
|
||||
|
Reference in New Issue
Block a user