From 4e12488ca5cdc7fe1d8566325fb2210ffb423906 Mon Sep 17 00:00:00 2001 From: brl Date: Thu, 25 Jun 2015 14:17:24 -0400 Subject: [PATCH] resolve vars and globbing internally in fs package --- fs/fs.go | 98 ++++++++++++++++++++++++++++++++++++--------- fs/resolve.go | 8 +++- oz-daemon/rootfs.go | 10 +---- oz-init/init.go | 22 ++++------ 4 files changed, 94 insertions(+), 44 deletions(-) diff --git a/fs/fs.go b/fs/fs.go index 9a299f2..7cbc1fa 100644 --- a/fs/fs.go +++ b/fs/fs.go @@ -68,34 +68,81 @@ func (fs *Filesystem) CreateSymlink(oldpath, newpath string) error { return nil } -func (fs *Filesystem) BindPath(path, target string, readonly bool) error { - return fs.BindOrCreate(path, target, readonly, nil) +func (fs *Filesystem) BindPath(target string, flags int, u *user.User) error { + return fs.bindResolve(target, "", flags, u) } -func (fs *Filesystem) BindOrCreate(p, target string, readonly bool, u *user.User) error { - src, err := filepath.EvalSymlinks(p) +func (fs *Filesystem) BindTo(from string, to string, flags int, u *user.User) error { + return fs.bindResolve(from, to, flags, u) +} + +const ( + BindReadOnly = 1 << iota + BindCanCreate +) + +func (fs *Filesystem) bindResolve(from string, to string, flags int, u *user.User) error { + if (to == "") || (from == to) { + return fs.bindSame(from, flags, u) + } + if isGlobbed(to) { + return fmt.Errorf("bind target (%s) cannot have globbed path", to) + } + t, err := resolveVars(to, u) + if err != nil { + return err + } + if isGlobbed(from) { + return fmt.Errorf("bind src (%s) cannot have globbed path with separate target path (%s)", from, to) + } + f, err := resolveVars(from, u) + if err != nil { + return err + } + return fs.bind(f, t, flags, u) +} + +func (fs *Filesystem) bindSame(p string, flags int, u *user.User) error { + ps, err := resolvePath(p, u) + if err != nil { + return err + } + for _, p := range ps { + if err := fs.bind(p, p, flags, u); err != nil { + return err + } + } + return nil +} + +func (fs *Filesystem) bind(from string, to string, flags int, u *user.User) error { + src, err := filepath.EvalSymlinks(from) if err != nil { - return fmt.Errorf("error resolving symlinks for path (%s): %v", p, err) + return fmt.Errorf("error resolving symlinks for path (%s): %v", from, err) } - sinfo, err := readSourceInfo(src, u) + cc := flags&BindCanCreate != 0 + sinfo, err := readSourceInfo(src, cc, u) if err != nil { return fmt.Errorf("failed to bind path (%s): %v", src, err) } - target = path.Join(fs.Root(), target) + if to == "" { + to = from + } + to = path.Join(fs.Root(), to) - _, err = os.Stat(target) + _, err = os.Stat(to) if err == nil || !os.IsNotExist(err) { - fs.log.Warning("Target (%s > %s) already exists, ignoring", src, target) + fs.log.Warning("Target (%s > %s) already exists, ignoring", src, to) return nil } if sinfo.IsDir() { - if err := os.MkdirAll(target, sinfo.Mode().Perm()); err != nil { + if err := os.MkdirAll(to, sinfo.Mode().Perm()); err != nil { return err } } else { - if err := createEmptyFile(target, 0750); err != nil { + if err := createEmptyFile(to, 0750); err != nil { return err } } @@ -103,24 +150,24 @@ func (fs *Filesystem) BindOrCreate(p, target string, readonly bool, u *user.User if err := copyPathPermissions(fs.Root(), src); err != nil { return fmt.Errorf("failed to copy path permissions for (%s): %v", src, err) } - fs.log.Info("bind mounting %s -> %s", src, target) - flags := syscall.MS_NOSUID | syscall.MS_NODEV - if readonly { - flags |= syscall.MS_RDONLY + fs.log.Info("bind mounting %s -> %s", src, to) + mntflags := syscall.MS_NOSUID | syscall.MS_NODEV + if flags&BindReadOnly != 0 { + mntflags |= syscall.MS_RDONLY } else { flags |= syscall.MS_NOEXEC } - return bindMount(src, target, flags) + return bindMount(src, to, mntflags) } -func readSourceInfo(src string, u *user.User) (os.FileInfo, error) { +func readSourceInfo(src string, cancreate bool, u *user.User) (os.FileInfo, error) { if fi, err := os.Stat(src); err == nil { return fi, nil } else if !os.IsNotExist(err) { return nil, err } - if u == nil { + if u == nil || !cancreate { return nil, fmt.Errorf("source path (%s) does not exist", src) } @@ -145,7 +192,20 @@ func readSourceInfo(src string, u *user.User) (os.FileInfo, error) { return os.Stat(src) } -func (fs *Filesystem) BlacklistPath(target string) error { +func (fs *Filesystem) BlacklistPath(target string, u *user.User) error { + ps, err := resolvePath(target, u) + if err != nil { + return err + } + for _, p := range ps { + if err := fs.blacklist(p); err != nil { + return err + } + } + return nil +} + +func (fs *Filesystem) blacklist(target string) error { t, err := filepath.EvalSymlinks(target) if err != nil { return fmt.Errorf("symlink evaluation failed while blacklisting path %s: %v", target, err) diff --git a/fs/resolve.go b/fs/resolve.go index 913ae9d..4b73676 100644 --- a/fs/resolve.go +++ b/fs/resolve.go @@ -9,7 +9,7 @@ import ( "strings" ) -func ResolvePath(p string, u *user.User) ([]string, error) { +func resolvePath(p string, u *user.User) ([]string, error) { p, err := resolveVars(p, u) if err != nil { return nil, err @@ -52,8 +52,12 @@ func resolveVars(p string, u *user.User) (string, error) { return p, nil } +func isGlobbed(p string) bool { + return strings.Contains(p, "*") +} + func resolveGlob(p string) ([]string, error) { - if !strings.Contains(p, "*") { + if !isGlobbed(p) { return []string{p}, nil } list, err := filepath.Glob(p) diff --git a/oz-daemon/rootfs.go b/oz-daemon/rootfs.go index 9ee4e6f..98815da 100644 --- a/oz-daemon/rootfs.go +++ b/oz-daemon/rootfs.go @@ -102,7 +102,7 @@ func setupRootfs(fsys *fs.Filesystem) error { } for _, p := range basicBindDirs { - if err := fsys.BindPath(p, p, true); err != nil { + if err := fsys.BindPath(p, fs.BindReadOnly, nil); err != nil { return fmt.Errorf("failed to bind directory '%s': %v", p, err) } } @@ -135,15 +135,9 @@ func setupRootfs(fsys *fs.Filesystem) error { } for _, bl := range basicBlacklist { - ps, err := fs.ResolvePath(bl, nil) - if err != nil { + if err := fsys.BlacklistPath(bl, nil); err != nil { return err } - for _, p := range ps { - if err := fsys.BlacklistPath(p); err != nil { - return err - } - } } return nil } diff --git a/oz-init/init.go b/oz-init/init.go index 3383df0..0761994 100644 --- a/oz-init/init.go +++ b/oz-init/init.go @@ -521,7 +521,7 @@ func (st *initState) setupFilesystem(extra []oz.WhitelistItem) error { if err != nil { return err } - if err := fs.BindPath(xprapath, xprapath, false); err != nil { + if err := fs.BindPath(xprapath, 0, nil); err != nil { return err } } @@ -546,14 +546,12 @@ func (st *initState) bindWhitelist(fsys *fs.Filesystem, wlist []oz.WhitelistItem return nil } for _, wl := range wlist { - paths, err := fs.ResolvePath(wl.Path, st.user) - if err != nil { - return err + flags := fs.BindCanCreate + if wl.ReadOnly { + flags |= fs.BindReadOnly } - for _, p := range paths { - if err := fsys.BindOrCreate(p, p, wl.ReadOnly, st.user); err != nil { - return err - } + if err := fsys.BindPath(wl.Path, flags, st.user); err != nil { + return err } } return nil @@ -564,15 +562,9 @@ func (st *initState) applyBlacklist(fsys *fs.Filesystem, blist []oz.BlacklistIte return nil } for _, bl := range blist { - paths, err := fs.ResolvePath(bl.Path, st.user) - if err != nil { + if err := fsys.BlacklistPath(bl.Path, st.user); err != nil { return err } - for _, p := range paths { - if err := fsys.BlacklistPath(p); err != nil { - return err - } - } } return nil }