Added tentative restricted /dev using mknod, and configuration to disable the feature

master
xSmurf 10 years ago
parent 914ff955d7
commit e20be3ea0a

@ -11,6 +11,7 @@ type Config struct {
SandboxPath string `json:"sandbox_path"` SandboxPath string `json:"sandbox_path"`
BridgeMACAddr string `json:"bridge_mac"` BridgeMACAddr string `json:"bridge_mac"`
NMIgnoreFile string `json:"nm_ignore_file"` NMIgnoreFile string `json:"nm_ignore_file"`
UseFullDev bool `json:"use_full_dev"`
AllowRootShell bool `json:"allow_root_shell"` AllowRootShell bool `json:"allow_root_shell"`
LogXpra bool `json:"log_xpra"` LogXpra bool `json:"log_xpra"`
} }
@ -24,6 +25,7 @@ func NewDefaultConfig() *Config {
SandboxPath: "/srv/oz", SandboxPath: "/srv/oz",
NMIgnoreFile: "/etc/NetworkManager/conf.d/oz.conf", NMIgnoreFile: "/etc/NetworkManager/conf.d/oz.conf",
BridgeMACAddr: "6A:A8:2E:56:E8:9C", BridgeMACAddr: "6A:A8:2E:56:E8:9C",
UseFullDev: false,
AllowRootShell: false, AllowRootShell: false,
LogXpra: false, LogXpra: false,
} }

@ -2,11 +2,14 @@ package fs
import ( import (
"errors" "errors"
"github.com/op/go-logging"
"io/ioutil" "io/ioutil"
"os"
"sort" "sort"
"strings" "strings"
"syscall" "syscall"
// External
"github.com/op/go-logging"
) )
func (fs *Filesystem) Cleanup() error { func (fs *Filesystem) Cleanup() error {
@ -36,6 +39,10 @@ func (mnts mountEntries) unmountAll(log *logging.Logger) (bool, error) {
reterr := error(nil) reterr := error(nil)
atLeastOne := false atLeastOne := false
for _, m := range mnts { for _, m := range mnts {
log.Debug("Unmounting mountpoint: %s", m.dir)
if _, err := os.Stat(m.dir); os.IsNotExist(err) {
continue
}
if err := syscall.Unmount(m.dir, 0); err != nil { if err := syscall.Unmount(m.dir, 0); err != nil {
log.Warning("Failed to unmount mountpoint %s: %v", m.dir, err) log.Warning("Failed to unmount mountpoint %s: %v", m.dir, err)
reterr = err reterr = err

@ -28,6 +28,7 @@ type Filesystem struct {
userID string userID string
noDefaults bool noDefaults bool
noSysAndProc bool noSysAndProc bool
fullDevices bool
whitelist []*mountItem whitelist []*mountItem
blacklist []*mountItem blacklist []*mountItem
} }
@ -75,7 +76,7 @@ func (fs *Filesystem) newItem(path, target string, readonly bool) (*mountItem, e
}, nil }, nil
} }
func NewFromProfile(profile *oz.Profile, user *user.User, basePath string, log *logging.Logger) *Filesystem { func NewFromProfile(profile *oz.Profile, user *user.User, basePath string, UseFullDev bool, log *logging.Logger) *Filesystem {
fs := NewFilesystem(profile.Name, user, basePath, log) fs := NewFilesystem(profile.Name, user, basePath, log)
for _, wl := range profile.Whitelist { for _, wl := range profile.Whitelist {
fs.addWhitelist(wl.Path, wl.Path, wl.ReadOnly) fs.addWhitelist(wl.Path, wl.Path, wl.ReadOnly)
@ -85,6 +86,7 @@ func NewFromProfile(profile *oz.Profile, user *user.User, basePath string, log *
} }
fs.noDefaults = profile.NoDefaults fs.noDefaults = profile.NoDefaults
fs.noSysAndProc = profile.NoSysProc fs.noSysAndProc = profile.NoSysProc
fs.fullDevices = UseFullDev
if profile.XServer.Enabled { if profile.XServer.Enabled {
fs.xpra = path.Join(user.HomeDir, ".Xoz", profile.Name) fs.xpra = path.Join(user.HomeDir, ".Xoz", profile.Name)
} }

@ -24,20 +24,24 @@ func (fs *Filesystem) OzInit() error {
} }
func (fs *Filesystem) ozinitMountDev() error { func (fs *Filesystem) ozinitMountDev() error {
flags := uintptr(syscall.MS_NOSUID | syscall.MS_REC | syscall.MS_NOEXEC) if fs.fullDevices {
if err := syscall.Mount("none", "/dev", "devtmpfs", flags, ""); err != nil { flags := uintptr(syscall.MS_NOSUID | syscall.MS_REC | syscall.MS_NOEXEC)
fs.log.Warning("Failed to mount devtmpfs: %v", err) if err := syscall.Mount("none", "/dev", "devtmpfs", flags, ""); err != nil {
return err fs.log.Warning("Failed to mount devtmpfs: %v", err)
} return err
}
if err := mountSpecial("/dev/shm", "tmpfs"); err != nil { if err := mountSpecial("/dev/shm", "tmpfs"); err != nil {
fs.log.Warning("Failed to mount shm directory: %v", err) fs.log.Warning("Failed to mount shm directory: %v", err)
return err return err
}
} }
if err := mountSpecial("/dev/pts", "devpts"); err != nil { if err := mountSpecial("/dev/pts", "devpts"); err != nil {
fs.log.Warning("Failed to mount pts directory: %v", err) fs.log.Warning("Failed to mount pts directory: %v", err)
return err return err
} }
return nil return nil
} }
@ -87,6 +91,15 @@ func (fs *Filesystem) ozinitCreateSymlinks() error {
return err return err
} }
} }
if fs.fullDevices == false {
for _, sl := range deviceSymlinks {
if err := syscall.Symlink(sl[0], sl[1]); err != nil {
return err
}
}
}
return nil return nil
} }

@ -18,9 +18,10 @@ var basicEmptyDirs = []string{
"/sbin", "/var", "/var/lib", "/sbin", "/var", "/var/lib",
"/var/cache", "/home", "/boot", "/var/cache", "/home", "/boot",
"/tmp", "/run", "/run/user", "/tmp", "/run", "/run/user",
"/run/shm", "/run/lock", "/root", "/run/lock", "/root",
"/opt", "/srv", "/dev", "/proc", "/opt", "/srv", "/dev", "/proc",
"/sys", "/mnt", "/media", "/sys", "/mnt", "/media",
//"/run/shm",
} }
var basicBlacklist = []string{ var basicBlacklist = []string{
@ -37,6 +38,47 @@ var basicSymlinks = [][2]string{
{"/run", "/var/run"}, {"/run", "/var/run"},
{"/tmp", "/var/tmp"}, {"/tmp", "/var/tmp"},
{"/run/lock", "/var/lock"}, {"/run/lock", "/var/lock"},
// Devices
}
var deviceSymlinks = [][2]string{
{"/proc/self/fd", "/dev/fd"},
{"/proc/self/fd/2", "/dev/stderr"},
{"/proc/self/fd/0", "/dev/stdin"},
{"/proc/self/fd/1", "/dev/stdout"},
{"/dev/pts/ptmx", "/dev/ptmx"},
{"/dev/shm", "/run/shm"},
}
type fsDeviceDefinition struct {
path string
mode uint32
dev int
perm uint32
}
const ugorw = syscall.S_IRUSR|syscall.S_IWUSR | syscall.S_IRGRP|syscall.S_IWGRP | syscall.S_IROTH|syscall.S_IWOTH
const urwgr = syscall.S_IRUSR|syscall.S_IWUSR | syscall.S_IRGRP
const urw = syscall.S_IRUSR|syscall.S_IWUSR
var basicDevices = []fsDeviceDefinition{
{path: "/dev/full", mode: syscall.S_IFCHR|ugorw, dev: _makedev(1, 7), perm: 0666},
{path: "/dev/null", mode: syscall.S_IFCHR|ugorw, dev: _makedev(1, 3), perm: 0666},
{path: "/dev/random", mode: syscall.S_IFCHR|ugorw, dev: _makedev(1, 8), perm: 0666},
{path: "/dev/console", mode: syscall.S_IFCHR|urw, dev: _makedev(5, 1), perm: 0600},
{path: "/dev/tty", mode: syscall.S_IFCHR|ugorw, dev: _makedev(5, 0), perm: 0666},
{path: "/dev/tty1", mode: syscall.S_IFREG|urwgr, dev: 0, perm: 0640},
{path: "/dev/tty2", mode: syscall.S_IFREG|urwgr, dev: 0, perm: 0640},
{path: "/dev/tty3", mode: syscall.S_IFREG|urwgr, dev: 0, perm: 0640},
{path: "/dev/tty4", mode: syscall.S_IFREG|urwgr, dev: 0, perm: 0640},
{path: "/dev/urandom", mode: syscall.S_IFCHR|ugorw, dev: _makedev(1, 9), perm: 0666},
{path: "/dev/zero", mode: syscall.S_IFCHR|ugorw, dev: _makedev(1, 5), perm: 0666},
}
func _makedev(x, y int) int {
return (((x)<<8) | (y))
} }
func (fs *Filesystem) Setup(profilesPath string) error { func (fs *Filesystem) Setup(profilesPath string) error {
@ -68,6 +110,12 @@ func (fs *Filesystem) Setup(profilesPath string) error {
if err := fs.setupChroot(); err != nil { if err := fs.setupChroot(); err != nil {
return err return err
} }
if fs.fullDevices == false {
if err := fs.setupDev(); err != nil {
return err
}
}
return fs.setupMountItems() return fs.setupMountItems()
} }
@ -104,14 +152,17 @@ func (fs *Filesystem) setupRootfs() error {
if err := syscall.Mount(fs.base, fs.base, "tmpfs", flags, data); err != nil { if err := syscall.Mount(fs.base, fs.base, "tmpfs", flags, data); err != nil {
return fmt.Errorf("failed to create base tmpfs at %s: %v", fs.base, err) return fmt.Errorf("failed to create base tmpfs at %s: %v", fs.base, err)
} }
/*
// Currently unused
// create extra directories // create extra directories
extra := []string{"sockets"} extra := []string{"sockets", "dev"}
for _, sub := range extra { for _, sub := range extra {
d := path.Join(fs.base, sub) d := path.Join(fs.base, sub)
if err := os.Mkdir(d, 0755); err != nil { if err := os.Mkdir(d, 0755); err != nil {
return fmt.Errorf("unable to create directory (%s): %v", d, err) return fmt.Errorf("unable to create directory (%s): %v", d, err)
} }
} }
*/
return nil return nil
} }
@ -132,6 +183,33 @@ func (fs *Filesystem) setupChroot() error {
return setupTmp(fs.root) return setupTmp(fs.root)
} }
func (fs *Filesystem) setupDev() error {
devPath := path.Join(fs.root, "dev")
flags := uintptr(syscall.MS_NOSUID | syscall.MS_NOEXEC)
if err := syscall.Mount("none", devPath, "tmpfs", flags, ""); err != nil {
fs.log.Warning("Failed to mount devtmpfs: %v", err)
return err
}
for _, dev := range basicDevices {
path := path.Join(fs.root, dev.path)
if err := syscall.Mknod(path, dev.mode, dev.dev); err != nil {
return fmt.Errorf("Failed to mknod device %s: %+v", path, err)
}
if err := os.Chmod(path, os.FileMode(dev.perm)); err != nil {
return fmt.Errorf("Unable to set permissions for device %s: %+v", dev.path, err)
}
}
shmPath := path.Join(devPath, "shm")
if err := mountSpecial(shmPath, "tmpfs"); err != nil {
fs.log.Warning("Failed to mount shm directory: %v", err)
return err
}
return nil
}
func bindBasicDirectories(root string, dirs []string) error { func bindBasicDirectories(root string, dirs []string) error {
for _, src := range dirs { for _, src := range dirs {
st, err := os.Lstat(src) st, err := os.Lstat(src)

@ -170,7 +170,7 @@ func (d *daemonState) handleClean(clean *CleanMsg, msg *ipc.Message) error {
} }
// XXX // XXX
u, _ := user.Current() u, _ := user.Current()
fs := fs.NewFromProfile(p, u, d.config.SandboxPath, d.log) fs := fs.NewFromProfile(p, u, d.config.SandboxPath, d.config.UseFullDev, d.log)
if err := fs.Cleanup(); err != nil { if err := fs.Cleanup(); err != nil {
return msg.Respond(&ErrorMsg{err.Error()}) return msg.Respond(&ErrorMsg{err.Error()})
} }

@ -85,7 +85,7 @@ func (d *daemonState) launch(p *oz.Profile, uid, gid uint32, log *logging.Logger
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to lookup user for uid=%d: %v", uid, err) return nil, fmt.Errorf("failed to lookup user for uid=%d: %v", uid, err)
} }
fs := fs.NewFromProfile(p, u, d.config.SandboxPath, d.log) fs := fs.NewFromProfile(p, u, d.config.SandboxPath, d.config.UseFullDev, d.log)
if err := fs.Setup(d.config.ProfileDir); err != nil { if err := fs.Setup(d.config.ProfileDir); err != nil {
return nil, err return nil, err
} }

@ -132,7 +132,7 @@ func parseArgs() *initState {
gid: gid, gid: gid,
user: u, user: u,
display: display, display: display,
fs: fs.NewFromProfile(p, u, config.SandboxPath, log), fs: fs.NewFromProfile(p, u, config.SandboxPath, config.UseFullDev, log),
network: stn, network: stn,
} }
} }

Loading…
Cancel
Save