File: main.go

package info (click to toggle)
golang-github-landlock-lsm-go-landlock 0.0~git20250303.1544bcc-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 276 kB
  • sloc: makefile: 9
file content (118 lines) | stat: -rw-r--r-- 2,778 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"

	"github.com/landlock-lsm/go-landlock/landlock"
	llsys "github.com/landlock-lsm/go-landlock/landlock/syscall"
)

var (
	cfgFile = flag.String("cfg_file", "", "config file (JSON)")
)

type PathException struct {
	Paths           []string `json:"paths"`
	PermittedAccess []string `json:"permitted_access"`
}

type Config struct {
	ForbiddenAccess []string        `json:"forbidden_access"`
	Exceptions      []PathException `json:"exceptions"`
	BestEffort      bool            `json:"best_effort"`
}

func main() {
	flag.Parse()

	// Read configuration file.
	buf, err := os.ReadFile(*cfgFile)
	if err != nil {
		log.Fatalf("io.ReadAll: %v", err)
	}

	var jsonCfg Config
	err = json.Unmarshal(buf, &jsonCfg)
	if err != nil {
		log.Fatalf("json.Unmarshal: %v", err)
	}

	// Print config for debugging.
	b, err := json.MarshalIndent(jsonCfg, "", "  ")
	if err != nil {
		log.Fatalf("json.MarshalIndent: %v", err)
	}
	fmt.Println("JSON config:")
	fmt.Println(string(b))

	// Build Landlock config.
	forbiddenAccess := accessFSSet(jsonCfg.ForbiddenAccess)
	cfg, err := landlock.NewConfig(forbiddenAccess)
	if err != nil {
		log.Fatalf("landlock.NewConfig: %v", err)
	}
	if jsonCfg.BestEffort {
		cfg2 := cfg.BestEffort()
		cfg = &cfg2
	}

	// Enforce.
	err = cfg.RestrictPaths(exceptions(jsonCfg.Exceptions)...)
	if err != nil {
		log.Fatalf("RestrictPaths: %v", err)
	}

	// Run an executable.
	executable := "/bin/bash"

	os.Chdir("/")
	cmd := exec.Command(executable)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err := cmd.Run(); err != nil {
		log.Fatalf("execve: %v", err)
	}
}

func accessFSSet(names []string) (a landlock.AccessFSSet) {
	var table = map[string]landlock.AccessFSSet{
		"execute":     llsys.AccessFSExecute,
		"write_file":  llsys.AccessFSWriteFile,
		"read_file":   llsys.AccessFSReadFile,
		"read_dir":    llsys.AccessFSReadDir,
		"remove_dir":  llsys.AccessFSRemoveDir,
		"remove_file": llsys.AccessFSRemoveFile,
		"make_char":   llsys.AccessFSMakeChar,
		"make_dir":    llsys.AccessFSMakeDir,
		"make_reg":    llsys.AccessFSMakeReg,
		"make_sock":   llsys.AccessFSMakeSock,
		"make_fifo":   llsys.AccessFSMakeFifo,
		"make_block":  llsys.AccessFSMakeBlock,
		"make_sym":    llsys.AccessFSMakeSym,
		"refer":       llsys.AccessFSRefer,
		"truncate":    llsys.AccessFSTruncate,
	}
	for _, n := range names {
		x, ok := table[n]
		if !ok {
			log.Fatalf("unknown access fs flag %q", n)
		}
		a |= x
	}
	return a
}

func exceptions(es []PathException) (opts []landlock.Rule) {
	for _, e := range es {
		permittedAccess := accessFSSet(e.PermittedAccess)
		po := landlock.PathAccess(permittedAccess, e.Paths...)
		opts = append(opts, po)
	}
	return opts
}