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 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
package main
import (
"fmt"
"log"
"os"
"strings"
"syscall"
"github.com/landlock-lsm/go-landlock/landlock"
)
func parseFlags(args []string) (verbose bool, cfg landlock.Config, opts []landlock.Rule, cmd []string) {
cfg = landlock.V5
takeArgs := func(makeOpt func(...string) landlock.FSRule) landlock.Rule {
var paths []string
needRefer := false
needIoctlDev := false
for len(args) > 0 && !strings.HasPrefix(args[0], "-") {
switch args[0] {
case "+refer":
needRefer = true
case "+ioctl_dev":
needIoctlDev = true
default:
paths = append(paths, args[0])
}
args = args[1:]
}
opt := makeOpt(paths...)
if verbose {
fmt.Println("Path option:", opt)
}
if needRefer {
opt = opt.WithRefer()
}
if needIoctlDev {
opt = opt.WithIoctlDev()
}
if verbose {
fmt.Println("Path option:", opt)
}
return opt
}
bestEffort := true
ArgParsing:
for len(args) > 0 {
switch args[0] {
case "-5":
cfg = landlock.V5
args = args[1:]
continue
case "-4":
cfg = landlock.V4
args = args[1:]
continue
case "-3":
cfg = landlock.V3
args = args[1:]
continue
case "-2":
cfg = landlock.V2
args = args[1:]
continue
case "-1":
cfg = landlock.V1
args = args[1:]
continue
case "-strict":
bestEffort = false
args = args[1:]
continue
case "-v":
verbose = true
args = args[1:]
continue
case "-ro":
args = args[1:]
opts = append(opts, takeArgs(landlock.RODirs))
continue
case "-rw":
args = args[1:]
opts = append(opts, takeArgs(landlock.RWDirs))
continue
case "-rofiles":
args = args[1:]
opts = append(opts, takeArgs(landlock.ROFiles))
continue
case "-rwfiles":
args = args[1:]
opts = append(opts, takeArgs(landlock.RWFiles))
continue
case "--":
args = args[1:]
// Remaining args are the command
break ArgParsing
default:
log.Fatalf("Unrecognized option %q", args[0])
}
}
cmd = args
if bestEffort {
cfg = cfg.BestEffort()
}
return verbose, cfg, opts, cmd
}
func main() {
verbose, cfg, opts, cmdArgs := parseFlags(os.Args[1:])
if verbose {
fmt.Println("Args: ", os.Args)
fmt.Println()
fmt.Printf("Config: %v\n", cfg)
fmt.Println()
fmt.Printf("Executing command %v\n", cmdArgs)
}
if len(cmdArgs) < 1 {
fmt.Println("Usage:")
fmt.Println(" landlock-restrict")
fmt.Println(" [-v]")
fmt.Println(" [-1] [-2] [-3] [-4] [-5] [-strict]")
fmt.Println(" [-ro [+refer] PATH...] [-rw [+refer] [+ioctl_dev] PATH...]")
fmt.Println(" [-rofiles [+refer] PATH] [-rwfiles [+refer] PATH]")
fmt.Println(" -- COMMAND...")
fmt.Println()
fmt.Println("Options:")
fmt.Println(" -ro, -rw, -rofiles, -rwfiles paths to restrict to")
fmt.Println(" -1, -2, -3, -4, -5 select Landlock version")
fmt.Println(" -strict use strict mode (instead of best effort)")
fmt.Println(" -v verbose logging")
fmt.Println()
fmt.Println("A path list that contains the word '+refer' will additionally grant the refer access right.")
fmt.Println()
fmt.Println("Default mode for Landlock is V5 in best effort mode (best compatibility)")
fmt.Println()
log.Fatalf("Need proper command, got %v", cmdArgs)
}
if !strings.HasPrefix(cmdArgs[0], "/") {
log.Fatalf("Need absolute binary path, got %q", cmdArgs[0])
}
err := cfg.RestrictPaths(opts...)
if err != nil {
log.Fatalf("landlock: %v", err)
}
if err := syscall.Exec(cmdArgs[0], cmdArgs, os.Environ()); err != nil {
log.Fatalf("execve: %v", err)
}
}
|