-
Notifications
You must be signed in to change notification settings - Fork 57
/
profile.go
322 lines (284 loc) · 7.51 KB
/
profile.go
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
package oz
import (
"bufio"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path"
"regexp"
"strings"
"github.com/subgraph/oz/network"
)
type Profile struct {
// Name of this profile
Name string
// Path to binary to launch
Path string
// List of path to binaries matching this sandbox
Paths []string
// Path of the config file
ProfilePath string `json:"-"`
// Default parameters to pass to the program
DefaultParams []string `json:"default_params"`
// Pass command-line arguments
RejectUserArgs bool `json:"reject_user_args"`
// Autoshutdown the sandbox when the process exits. One of (no, yes, soft), defaults to yes
AutoShutdown ShutdownMode `json:"auto_shutdown"`
// Optional list of executable names to watch for exit in case initial command spawns and exit
Watchdog []string
// Optional wrapper binary to use when launching command (ex: tsocks)
Wrapper string
// If true launch one sandbox per instance, otherwise run all instances in same sandbox
Multi bool
// Disable mounting of sys and proc inside the sandbox
NoSysProc bool
// Disable bind mounting of default directories (etc,usr,bin,lib,lib64)
// Also disables default blacklist items (/sbin, /usr/sbin, /usr/bin/sudo)
// Normally not used
NoDefaults bool
// Allow bind mounting of files passed as arguments inside the sandbox
AllowFiles bool `json:"allow_files"`
AllowedGroups []string `json:"allowed_groups"`
// Optional directory where per-process logs will be output
LogDir string `json:"log_dir"`
// List of paths to bind mount inside jail
Whitelist []WhitelistItem
// List of paths to blacklist inside jail
Blacklist []BlacklistItem
// Shared Folders
SharedFolders []string `json:"shared_folders"`
// Optional XServer config
XServer XServerConf
// List of environment variables
Environment []EnvVar
// Networking
Networking NetworkProfile
// Firewall
Firewall []FWRule
// Seccomp
Seccomp SeccompConf
// External Forwarders
ExternalForwarders []ExternalForwarder `json:"external_forwarders"`
}
type ShutdownMode string
const (
PROFILE_SHUTDOWN_NO ShutdownMode = "no"
PROFILE_SHUTDOWN_YES ShutdownMode = "yes"
//PROFILE_SHUTDOWN_SOFT ShutdownMode = "soft" // Unimplemented
)
type AudioMode string
const (
PROFILE_AUDIO_NONE AudioMode = "none"
PROFILE_AUDIO_SPEAKER AudioMode = "speaker"
PROFILE_AUDIO_FULL AudioMode = "full"
PROFILE_AUDIO_PULSE AudioMode = "pulseaudio"
)
type XServerConf struct {
Enabled bool
TrayIcon string `json:"tray_icon"`
WindowIcon string `json:"window_icon"`
EnableTray bool `json:"enable_tray"`
EnableNotifications bool `json:"enable_notifications"`
DisableClipboard bool `json:"disable_clipboard"`
AudioMode AudioMode `json:"audio_mode"`
PulseAudio bool `json:"pulseaudio"`
Border bool `json:"border"`
Environment []EnvVar `json:"env"`
}
type SeccompMode string
const (
PROFILE_SECCOMP_TRAIN SeccompMode = "train"
PROFILE_SECCOMP_WHITELIST SeccompMode = "whitelist"
PROFILE_SECCOMP_BLACKLIST SeccompMode = "blacklist"
PROFILE_SECCOMP_DISABLED SeccompMode = "disabled"
)
type SeccompConf struct {
Mode SeccompMode
Enforce bool
Debug bool
Train bool
TrainOutput string `json:"train_output"`
Whitelist string
Blacklist string
ExtraDefs []string
}
type VPNConf struct {
VpnType string `json:"type"`
ConfigPath string
DNS []string
UserPassFilePath string `json:"authfile"`
}
type ExternalForwarder struct {
Name string
Dynamic bool
Multi bool
ExtProto string
Proto string
Addr string
TargetHost string
TargetPort string
SocketOwner string
}
type WhitelistItem struct {
Path string
Target string
Symlink string `json:-"`
ReadOnly bool `json:"read_only"`
CanCreate bool `json:"can_create"`
Ignore bool `json:"ignore"`
Force bool
NoFollow bool `json:"no_follow"`
AllowSetuid bool `json:"allow_suid"`
}
type BlacklistItem struct {
Path string
NoFollow bool `json:"no_follow"`
}
type FWRule struct {
Whitelist bool `json:"whitelist"`
DstHost string `json:"dst_host"`
DstPort int `json:"dst_port"`
}
type EnvVar struct {
Name string
Value string
}
type DNSMode string
const (
PROFILE_NETWORK_DNS_NONE DNSMode = "none"
PROFILE_NETWORK_DNS_PASS DNSMode = "pass"
PROFILE_NETWORK_DNS_DHCP DNSMode = "dhcp"
)
// Sandbox network definition
type NetworkProfile struct {
// One of empty, host, bridge
Nettype network.NetType `json:"type"`
// Name of the bridge to attach to
Bridge string
// VPN type
VPNConf VPNConf `json:"vpn"`
// List of Sockets we want to attach to the jail
// Applies to Nettype: bridge and empty only
Sockets []network.ProxyConfig
// Hardcoded least significant byte of the IP address
// Applies to Nettype: bridge only
IpByte uint `json:"ip_byte"`
// DNS Mode one of: pass, none, dhcp
// Applies to Nettype: bridge only
DNSMode DNSMode `json:"dns_mode"`
// Additional data for the hosts file
Hosts string
}
const defaultProfileDirectory = "/var/lib/oz/cells.d"
var loadedProfiles []*Profile
type Profiles []*Profile
func NewDefaultProfile() *Profile {
return &Profile{
Multi: false,
AllowFiles: false,
AllowedGroups: []string{},
XServer: XServerConf{
Enabled: true,
EnableTray: false,
EnableNotifications: false,
AudioMode: PROFILE_AUDIO_NONE,
Border: false,
},
}
}
func (ps Profiles) GetProfileByName(name string) (*Profile, error) {
if loadedProfiles == nil {
ps, err := LoadProfiles(defaultProfileDirectory)
if err != nil {
return nil, err
}
loadedProfiles = ps
}
for _, p := range loadedProfiles {
if p.Name == name {
return p, nil
}
}
return nil, nil
}
func (ps Profiles) GetProfileByPath(bpath string) (*Profile, error) {
if loadedProfiles == nil {
ps, err := LoadProfiles(defaultProfileDirectory)
if err != nil {
return nil, err
}
loadedProfiles = ps
}
for _, p := range loadedProfiles {
if p.Path == bpath {
return p, nil
}
for _, pp := range p.Paths {
if pp == bpath {
return p, nil
}
}
}
return nil, nil
}
func LoadProfiles(dir string) (Profiles, error) {
fs, err := ioutil.ReadDir(dir)
if err != nil {
return nil, err
}
ps := []*Profile{}
for _, f := range fs {
if !f.IsDir() {
name := path.Join(dir, f.Name())
if strings.HasSuffix(f.Name(), ".json") {
p, err := loadProfileFile(name)
if err != nil {
return nil, fmt.Errorf("error loading '%s': %v", f.Name(), err)
}
ps = append(ps, p)
}
}
}
loadedProfiles = ps
return ps, nil
}
var commentRegexp = regexp.MustCompile("^[ \t]*#")
func loadProfileFile(fpath string) (*Profile, error) {
if err := checkConfigPermissions(fpath); err != nil {
return nil, err
}
file, err := os.Open(fpath)
if err != nil {
return nil, err
}
scanner := bufio.NewScanner(file)
bs := ""
for scanner.Scan() {
line := scanner.Text()
if !commentRegexp.MatchString(line) {
bs += line + "\n"
}
}
p := new(Profile)
if err := json.Unmarshal([]byte(bs), p); err != nil {
return nil, err
}
if p.Name == "" {
p.Name = path.Base(p.Path)
}
if p.AutoShutdown == "" {
p.AutoShutdown = PROFILE_SHUTDOWN_YES
}
if p.XServer.AudioMode == "" {
p.XServer.AudioMode = PROFILE_AUDIO_NONE
}
if p.Seccomp.Mode == "" {
p.Seccomp.Mode = PROFILE_SECCOMP_DISABLED
}
if p.Networking.IpByte <= 1 || p.Networking.IpByte > 254 {
p.Networking.IpByte = 0
}
p.ProfilePath = fpath
return p, nil
}