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

master
xSmurf 9 years ago
parent 914ff955d7
commit e20be3ea0a

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

@ -2,11 +2,14 @@ package fs
import (
"errors"
"github.com/op/go-logging"
"io/ioutil"
"os"
"sort"
"strings"
"syscall"
// External
"github.com/op/go-logging"
)
func (fs *Filesystem) Cleanup() error {
@ -36,6 +39,10 @@ func (mnts mountEntries) unmountAll(log *logging.Logger) (bool, error) {
reterr := error(nil)
atLeastOne := false
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 {
log.Warning("Failed to unmount mountpoint %s: %v", m.dir, err)
reterr = err

@ -28,6 +28,7 @@ type Filesystem struct {
userID string
noDefaults bool
noSysAndProc bool
fullDevices bool
whitelist []*mountItem
blacklist []*mountItem
}
@ -75,7 +76,7 @@ func (fs *Filesystem) newItem(path, target string, readonly bool) (*mountItem, e
}, 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)
for _, wl := range profile.Whitelist {
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.noSysAndProc = profile.NoSysProc
fs.fullDevices = UseFullDev
if profile.XServer.Enabled {
fs.xpra = path.Join(user.HomeDir, ".Xoz", profile.Name)
}

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

@ -18,9 +18,10 @@ var basicEmptyDirs = []string{
"/sbin", "/var", "/var/lib",
"/var/cache", "/home", "/boot",
"/tmp", "/run", "/run/user",
"/run/shm", "/run/lock", "/root",
"/run/lock", "/root",
"/opt", "/srv", "/dev", "/proc",
"/sys", "/mnt", "/media",
//"/run/shm",
}
var basicBlacklist = []string{
@ -37,6 +38,47 @@ var basicSymlinks = [][2]string{
{"/run", "/var/run"},
{"/tmp", "/var/tmp"},
{"/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 {
@ -68,6 +110,12 @@ func (fs *Filesystem) Setup(profilesPath string) error {
if err := fs.setupChroot(); err != nil {
return err
}
if fs.fullDevices == false {
if err := fs.setupDev(); err != nil {
return err
}
}
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 {
return fmt.Errorf("failed to create base tmpfs at %s: %v", fs.base, err)
}
/*
// Currently unused
// create extra directories
extra := []string{"sockets"}
extra := []string{"sockets", "dev"}
for _, sub := range extra {
d := path.Join(fs.base, sub)
if err := os.Mkdir(d, 0755); err != nil {
return fmt.Errorf("unable to create directory (%s): %v", d, err)
}
}
*/
return nil
}
@ -132,6 +183,33 @@ func (fs *Filesystem) setupChroot() error {
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 {
for _, src := range dirs {
st, err := os.Lstat(src)

@ -170,7 +170,7 @@ func (d *daemonState) handleClean(clean *CleanMsg, msg *ipc.Message) error {
}
// XXX
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 {
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 {
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 {
return nil, err
}

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

Loading…
Cancel
Save