Speedofmastery commited on
Commit
a2f5849
·
1 Parent(s): 4e1982a

Auto-commit: Dockerfile updated

Browse files
Files changed (1) hide show
  1. landrun-main/cmd/landrun/main.go +176 -0
landrun-main/cmd/landrun/main.go ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package main
2
+
3
+ import (
4
+ "os"
5
+ osexec "os/exec"
6
+ "strings"
7
+
8
+ "github.com/urfave/cli/v2"
9
+ "github.com/zouuup/landrun/internal/elfdeps"
10
+ "github.com/zouuup/landrun/internal/exec"
11
+ "github.com/zouuup/landrun/internal/log"
12
+ "github.com/zouuup/landrun/internal/sandbox"
13
+ )
14
+
15
+ // Version is the current version of landrun
16
+ const Version = "0.1.15"
17
+
18
+ func main() {
19
+ app := &cli.App{
20
+ Name: "landrun",
21
+ Usage: "Run a command in a Landlock sandbox",
22
+ Version: Version,
23
+ Flags: []cli.Flag{
24
+ &cli.StringFlag{
25
+ Name: "log-level",
26
+ Usage: "Set logging level (error, info, debug)",
27
+ Value: "error",
28
+ EnvVars: []string{"LANDRUN_LOG_LEVEL"},
29
+ },
30
+ &cli.StringSliceFlag{
31
+ Name: "ro",
32
+ Usage: "Allow read-only access to this path",
33
+ },
34
+ &cli.StringSliceFlag{
35
+ Name: "rox",
36
+ Usage: "Allow read-only access with execution to this path",
37
+ },
38
+ &cli.StringSliceFlag{
39
+ Name: "rw",
40
+ Usage: "Allow read-write access to this path",
41
+ },
42
+ &cli.StringSliceFlag{
43
+ Name: "rwx",
44
+ Usage: "Allow read-write access with execution to this path",
45
+ },
46
+ &cli.IntSliceFlag{
47
+ Name: "bind-tcp",
48
+ Usage: "Allow binding to these TCP ports",
49
+ Hidden: false,
50
+ },
51
+ &cli.IntSliceFlag{
52
+ Name: "connect-tcp",
53
+ Usage: "Allow connecting to these TCP ports",
54
+ Hidden: false,
55
+ },
56
+ &cli.BoolFlag{
57
+ Name: "best-effort",
58
+ Usage: "Use best effort mode (fall back to less restrictive sandbox if necessary)",
59
+ Value: false,
60
+ },
61
+ &cli.StringSliceFlag{
62
+ Name: "env",
63
+ Usage: "Environment variables to pass to the sandboxed command (KEY=VALUE or just KEY to pass current value)",
64
+ Value: cli.NewStringSlice(),
65
+ },
66
+ &cli.BoolFlag{
67
+ Name: "unrestricted-filesystem",
68
+ Usage: "Allow unrestricted filesystem access",
69
+ Value: false,
70
+ },
71
+ &cli.BoolFlag{
72
+ Name: "unrestricted-network",
73
+ Usage: "Allow unrestricted network access",
74
+ Value: false,
75
+ },
76
+ &cli.BoolFlag{
77
+ Name: "ldd",
78
+ Usage: "Automatically detect and add library dependencies to --rox",
79
+ Value: false,
80
+ },
81
+ &cli.BoolFlag{
82
+ Name: "add-exec",
83
+ Usage: "Automatically add the executable path to --rox",
84
+ Value: false,
85
+ },
86
+ },
87
+ Before: func(c *cli.Context) error {
88
+ log.SetLevel(c.String("log-level"))
89
+ return nil
90
+ },
91
+ Action: func(c *cli.Context) error {
92
+ args := c.Args().Slice()
93
+ if len(args) == 0 {
94
+ log.Fatal("Missing command to run")
95
+ }
96
+
97
+ // Combine --ro and --rox paths for read-only access
98
+ readOnlyPaths := append([]string{}, c.StringSlice("ro")...)
99
+ readOnlyPaths = append(readOnlyPaths, c.StringSlice("rox")...)
100
+
101
+ // Combine --rw and --rwx paths for read-write access
102
+ readWritePaths := append([]string{}, c.StringSlice("rw")...)
103
+ readWritePaths = append(readWritePaths, c.StringSlice("rwx")...)
104
+
105
+ // Combine --rox and --rwx paths for executable permissions
106
+ readOnlyExecutablePaths := append([]string{}, c.StringSlice("rox")...)
107
+ readWriteExecutablePaths := append([]string{}, c.StringSlice("rwx")...)
108
+
109
+ binary, err := osexec.LookPath(args[0])
110
+ if err != nil {
111
+ log.Fatal("Failed to find binary: %v", err)
112
+ }
113
+
114
+ // Add command to readOnlyExecutablePaths
115
+ if c.Bool("add-exec") {
116
+ readOnlyExecutablePaths = append(readOnlyExecutablePaths, binary)
117
+ log.Debug("Added executable path: %v", binary)
118
+ }
119
+
120
+ // If --ldd flag is set, detect and add library dependencies
121
+ if c.Bool("ldd") {
122
+ libPaths, err := elfdeps.GetLibraryDependencies(binary)
123
+ if err != nil {
124
+ log.Fatal("Failed to detect library dependencies: %v", err)
125
+ }
126
+ // Add library directories to readOnlyExecutablePaths
127
+ readOnlyExecutablePaths = append(readOnlyExecutablePaths, libPaths...)
128
+ log.Debug("Added library paths: %v", libPaths)
129
+ }
130
+
131
+ cfg := sandbox.Config{
132
+ ReadOnlyPaths: readOnlyPaths,
133
+ ReadWritePaths: readWritePaths,
134
+ ReadOnlyExecutablePaths: readOnlyExecutablePaths,
135
+ ReadWriteExecutablePaths: readWriteExecutablePaths,
136
+ BindTCPPorts: c.IntSlice("bind-tcp"),
137
+ ConnectTCPPorts: c.IntSlice("connect-tcp"),
138
+ BestEffort: c.Bool("best-effort"),
139
+ UnrestrictedFilesystem: c.Bool("unrestricted-filesystem"),
140
+ UnrestrictedNetwork: c.Bool("unrestricted-network"),
141
+ }
142
+
143
+ // Process environment variables
144
+ envVars := processEnvironmentVars(c.StringSlice("env"))
145
+
146
+ if err := sandbox.Apply(cfg); err != nil {
147
+ log.Fatal("Failed to apply sandbox: %v", err)
148
+ }
149
+
150
+ return exec.Run(args, envVars)
151
+ },
152
+ }
153
+
154
+ if err := app.Run(os.Args); err != nil {
155
+ log.Fatal("%v", err)
156
+ }
157
+ }
158
+
159
+ // processEnvironmentVars processes the env flag values
160
+ func processEnvironmentVars(envFlags []string) []string {
161
+ result := []string{}
162
+
163
+ for _, env := range envFlags {
164
+ // If the flag is just a key (no = sign), get the value from the current environment
165
+ if !strings.Contains(env, "=") {
166
+ if val, exists := os.LookupEnv(env); exists {
167
+ result = append(result, env+"="+val)
168
+ }
169
+ } else {
170
+ // Flag already contains the value (KEY=VALUE format)
171
+ result = append(result, env)
172
+ }
173
+ }
174
+
175
+ return result
176
+ }