From 8ca77723e34b42ba5c5efefadba754c0d7808de1 Mon Sep 17 00:00:00 2001 From: xSmurf Date: Tue, 7 Jul 2015 00:30:34 +0000 Subject: [PATCH] Added mount/umount messages; readonly flag for oz-mount --- oz-daemon/client.go | 30 ++++++++++++++++ oz-daemon/daemon.go | 29 ++++++++++++++- oz-daemon/launch.go | 84 ++++++++++++++++++++++++++++++++----------- oz-daemon/protocol.go | 14 ++++++++ oz-mount/mount.go | 21 +++++++---- 5 files changed, 150 insertions(+), 28 deletions(-) diff --git a/oz-daemon/client.go b/oz-daemon/client.go index 5265f25..393cc10 100644 --- a/oz-daemon/client.go +++ b/oz-daemon/client.go @@ -102,6 +102,36 @@ func KillSandbox(id int) error { } } +func MountFiles(files []string) (error) { + resp, err := clientSend(&MountFilesMsg{Files: files}) + if err != nil { + return err + } + switch body := resp.Body.(type) { + case *ErrorMsg: + return errors.New(body.Msg) + case *OkMsg: + return nil + default: + return fmt.Errorf("Unexpected message received %+v", body) + } +} + +func UnmountFile(file string) (error) { + resp, err := clientSend(&UnmountFileMsg{File: file}) + if err != nil { + return err + } + switch body := resp.Body.(type) { + case *ErrorMsg: + return errors.New(body.Msg) + case *OkMsg: + return nil + default: + return fmt.Errorf("Unexpected message received %+v", body) + } +} + func parseProfileArg(arg string) (int, string, error) { if len(arg) == 0 { return 0, "", errors.New("profile argument needed") diff --git a/oz-daemon/daemon.go b/oz-daemon/daemon.go index 36492fa..23a2374 100644 --- a/oz-daemon/daemon.go +++ b/oz-daemon/daemon.go @@ -37,6 +37,8 @@ func Main() { d.handleLaunch, d.handleListSandboxes, d.handleKillSandbox, + d.handleMountFiles, + d.handleUnmountFile, d.handleLogs, ) if err != nil { @@ -257,6 +259,31 @@ func (d *daemonState) handleKillSandbox(msg *KillSandboxMsg, m *ipc.Message) err return m.Respond(&OkMsg{}) } +func (d *daemonState) handleMountFiles(msg *MountFilesMsg, m *ipc.Message) error { + sbox := d.sandboxById(msg.Id) + if sbox == nil { + return m.Respond(&ErrorMsg{fmt.Sprintf("no sandbox found with id = %d", msg.Id)}) + } + if err := sbox.MountFiles(msg.Files, msg.ReadOnly, d.config.PrefixPath, d.log); err != nil { + return m.Respond(&ErrorMsg{fmt.Sprintf("Unable to unmount file `%+s` from sandbox `%s`: %v", msg.Files, sbox.profile.Name, err)}) + } + return m.Respond(&OkMsg{}) +} + + +func (d *daemonState) handleUnmountFile(msg *UnmountFileMsg, m *ipc.Message) error { + sbox := d.sandboxById(msg.Id) + if sbox == nil { + return m.Respond(&ErrorMsg{fmt.Sprintf("no sandbox found with id = %d", msg.Id)}) + } + if err := sbox.UnmountFile(msg.File, d.config.PrefixPath, d.log); err != nil { + return m.Respond(&ErrorMsg{fmt.Sprintf("Unable to unmount file `%s` from sandbox `%s`: %v", msg.File, sbox.profile.Name, err)}) + } + return m.Respond(&OkMsg{}) +} + + + func (d *daemonState) sandboxById(id int) *Sandbox { for _, sb := range d.sandboxes { if sb.id == id { @@ -317,7 +344,7 @@ func (d *daemonState) getRunningSandboxByName(name string) *Sandbox { func (d *daemonState) handleListSandboxes(list *ListSandboxesMsg, msg *ipc.Message) error { r := new(ListSandboxesResp) for _, sb := range d.sandboxes { - r.Sandboxes = append(r.Sandboxes, SandboxInfo{Id: sb.id, Address: sb.addr, Profile: sb.profile.Name}) + r.Sandboxes = append(r.Sandboxes, SandboxInfo{Id: sb.id, Address: sb.addr, Mounts: sb.mountedFiles, Profile: sb.profile.Name}) } return msg.Respond(r) } diff --git a/oz-daemon/launch.go b/oz-daemon/launch.go index c0043e1..b8c317a 100644 --- a/oz-daemon/launch.go +++ b/oz-daemon/launch.go @@ -26,18 +26,19 @@ import ( ) type Sandbox struct { - daemon *daemonState - id int - display int - profile *oz.Profile - init *exec.Cmd - cred *syscall.Credential - fs *fs.Filesystem - stderr io.ReadCloser - addr string - xpra *xpra.Xpra - ready sync.WaitGroup - network *network.SandboxNetwork + daemon *daemonState + id int + display int + profile *oz.Profile + init *exec.Cmd + cred *syscall.Credential + fs *fs.Filesystem + stderr io.ReadCloser + addr string + xpra *xpra.Xpra + ready sync.WaitGroup + network *network.SandboxNetwork + mountedFiles []string } func createSocketPath(base string) (string, error) { @@ -208,6 +209,56 @@ func (sbox *Sandbox) launchProgram(binpath, cpath, pwd string, args []string, lo } } +func (sbox *Sandbox) MountFiles(files []string, readonly bool, binpath string, log *logging.Logger) error { + pmnt := path.Join(binpath, "bin", "oz-mount") + args := files + if readonly { + args = append([]string{"--readonly"}, files...) + } + cmnt := exec.Command(pmnt, args...) + cmnt.Env = []string{"_OZ_NSPID=" + strconv.Itoa(sbox.init.Process.Pid)} + pout, err := cmnt.CombinedOutput() + if err != nil { + log.Warning("Unable to bind files to sandbox: %v", err) + log.Warning("%s", string(pout)) + return err + } + for _, mfile := range files { + found := false + for _, mmfile := range sbox.mountedFiles { + if (mfile == mmfile) { + found = true + break; + } + } + if (!found) { + sbox.mountedFiles = append(sbox.mountedFiles, mfile) + } + } + log.Info("%s", string(pout)) + return nil +} + + +func (sbox *Sandbox) UnmountFile(file, binpath string, log *logging.Logger) error { + pmnt := path.Join(binpath, "bin", "oz-umount") + cmnt := exec.Command(pmnt, file) + cmnt.Env = []string{"_OZ_NSPID=" + strconv.Itoa(sbox.init.Process.Pid)} + pout, err := cmnt.CombinedOutput() + if err != nil { + log.Warning("Unable to unbind files from sandbox: %v", err) + log.Warning("%s", string(pout)) + return err + } + for i, item := range sbox.mountedFiles { + if item == file { + sbox.mountedFiles = append(sbox.mountedFiles[:i], sbox.mountedFiles[i+1:]...) + } + } + log.Info("%s", string(pout)) + return nil +} + func (sbox *Sandbox) whitelistArgumentFiles(binpath, pwd string, args []string, log *logging.Logger) { var files []string for _, fpath := range args { @@ -223,14 +274,7 @@ func (sbox *Sandbox) whitelistArgumentFiles(binpath, pwd string, args []string, } } if len(files) > 0 { - pmnt := path.Join(binpath, "bin", "oz-mount") - cmnt := exec.Command(pmnt, files...) - cmnt.Env = []string{"_OZ_NSPID=" + strconv.Itoa(sbox.init.Process.Pid)} - pout, err := cmnt.CombinedOutput() - if err != nil { - log.Warning("Unable to bind files to sandbox: %v", err) - log.Warning("%s", string(pout)) - } + sbox.MountFiles(files, false, binpath, log); } } diff --git a/oz-daemon/protocol.go b/oz-daemon/protocol.go index eb99075..d8ce56b 100644 --- a/oz-daemon/protocol.go +++ b/oz-daemon/protocol.go @@ -48,6 +48,7 @@ type SandboxInfo struct { Id int Address string Profile string + Mounts []string } type ListSandboxesResp struct { @@ -58,6 +59,17 @@ type KillSandboxMsg struct { Id int "KillSandbox" } +type MountFilesMsg struct { + Id int "MountFiles" + Files []string + ReadOnly bool +} + +type UnmountFileMsg struct { + Id int "UnmountFile" + File string +} + type LogsMsg struct { Count int "Logs" Follow bool @@ -77,6 +89,8 @@ var messageFactory = ipc.NewMsgFactory( new(ListSandboxesMsg), new(ListSandboxesResp), new(KillSandboxMsg), + new(MountFilesMsg), + new(UnmountFileMsg), new(LogsMsg), new(LogData), ) diff --git a/oz-mount/mount.go b/oz-mount/mount.go index 04cfb92..d7c217b 100644 --- a/oz-mount/mount.go +++ b/oz-mount/mount.go @@ -37,17 +37,20 @@ func Main(mode int) { } fsys := fs.NewFilesystem(config, log) - for fii, fpath := range os.Args { - if fii == 0 { - continue - } + start := 1; + readonly := false; + if os.Args[1] == "--readonly" { + start = 2; + readonly = true; + } + for _, fpath := range os.Args[start:] { if !strings.HasPrefix(fpath, "/home/") { log.Warning("Ignored `%s`, only files inside of home are permitted!", fpath) continue } switch mode { case MOUNT: - mount(fpath, fsys, log) + mount(fpath, readonly, fsys, log) case UMOUNT: unmount(fpath, fsys, log) } @@ -56,10 +59,14 @@ func Main(mode int) { os.Exit(0) } -func mount(fpath string, fsys *fs.Filesystem, log *logging.Logger) { +func mount(fpath string, readonly bool, fsys *fs.Filesystem, log *logging.Logger) { if _, err := os.Stat(fpath); err == nil { //log.Notice("Adding file `%s`.", fpath) - if err := fsys.BindPath(fpath, fs.BindCanCreate, nil); err != nil { + flags := fs.BindCanCreate + if readonly { + flags |= fs.BindReadOnly + } + if err := fsys.BindPath(fpath, flags, nil); err != nil { log.Error("%v while adding `%s`!", err, fpath) os.Exit(1) }