[lxc-devel] [lxd/master] lxd: Make pongo2 look inside the container
stgraber on Github
lxc-bot at linuxcontainers.org
Sat Feb 17 01:26:32 UTC 2018
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 370 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20180217/96252ce0/attachment.bin>
-------------- next part --------------
From 979a7dedc7dfcdc97ca5e81355fee2bf5afd4973 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Fri, 16 Feb 2018 20:25:26 -0500
Subject: [PATCH] lxd: Make pongo2 look inside the container
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Closes #4209
Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
lxd/container_lxc.go | 24 +++++++++++---------
lxd/template/chroot.go | 51 ++++++++++++++++++++++++++++++++++++++++++
test/suites/static_analysis.sh | 1 +
3 files changed, 66 insertions(+), 10 deletions(-)
create mode 100644 lxd/template/chroot.go
diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index 301c69b26..528468d25 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -20,13 +20,14 @@ import (
"syscall"
"time"
- "gopkg.in/flosch/pongo2.v3"
+ "github.com/flosch/pongo2"
"gopkg.in/lxc/go-lxc.v2"
"gopkg.in/yaml.v2"
"github.com/lxc/lxd/lxd/db"
"github.com/lxc/lxd/lxd/maas"
"github.com/lxc/lxd/lxd/state"
+ "github.com/lxc/lxd/lxd/template"
"github.com/lxc/lxd/lxd/types"
"github.com/lxc/lxd/lxd/util"
"github.com/lxc/lxd/shared"
@@ -4998,12 +4999,12 @@ func (c *containerLXC) templateApplyNow(trigger string) error {
}
// Go through the templates
- for templatePath, template := range metadata.Templates {
+ for tplPath, tpl := range metadata.Templates {
var w *os.File
// Check if the template should be applied now
found := false
- for _, tplTrigger := range template.When {
+ for _, tplTrigger := range tpl.When {
if tplTrigger == trigger {
found = true
break
@@ -5015,9 +5016,9 @@ func (c *containerLXC) templateApplyNow(trigger string) error {
}
// Open the file to template, create if needed
- fullpath := filepath.Join(c.RootfsPath(), strings.TrimLeft(templatePath, "/"))
+ fullpath := filepath.Join(c.RootfsPath(), strings.TrimLeft(tplPath, "/"))
if shared.PathExists(fullpath) {
- if template.CreateOnly {
+ if tpl.CreateOnly {
continue
}
@@ -5059,12 +5060,15 @@ func (c *containerLXC) templateApplyNow(trigger string) error {
defer w.Close()
// Read the template
- tplString, err := ioutil.ReadFile(filepath.Join(c.TemplatesPath(), template.Template))
+ tplString, err := ioutil.ReadFile(filepath.Join(c.TemplatesPath(), tpl.Template))
if err != nil {
return err
}
- tpl, err := pongo2.FromString("{% autoescape off %}" + string(tplString) + "{% endautoescape %}")
+ // Restrict filesystem access to within the container's rootfs
+ tplSet := pongo2.NewSet(fmt.Sprintf("%s-%s", c.name, tpl.Template), template.ChrootLoader{Path: c.RootfsPath()})
+
+ tplRender, err := tplSet.FromString("{% autoescape off %}" + string(tplString) + "{% endautoescape %}")
if err != nil {
return err
}
@@ -5105,12 +5109,12 @@ func (c *containerLXC) templateApplyNow(trigger string) error {
}
// Render the template
- tpl.ExecuteWriter(pongo2.Context{"trigger": trigger,
- "path": templatePath,
+ tplRender.ExecuteWriter(pongo2.Context{"trigger": trigger,
+ "path": tplPath,
"container": containerMeta,
"config": c.expandedConfig,
"devices": c.expandedDevices,
- "properties": template.Properties,
+ "properties": tpl.Properties,
"config_get": configGet}, w)
}
diff --git a/lxd/template/chroot.go b/lxd/template/chroot.go
new file mode 100644
index 000000000..94a11e1db
--- /dev/null
+++ b/lxd/template/chroot.go
@@ -0,0 +1,51 @@
+package template
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "path/filepath"
+ "strings"
+)
+
+// ChrootLoader is a pong2 compatible file loader which restricts all accesses to a directory
+type ChrootLoader struct {
+ Path string
+}
+
+// Abs resolves a filename relative to the base directory. Absolute paths are allowed.
+// When there's no base dir set, the absolute path to the filename
+// will be calculated based on either the provided base directory (which
+// might be a path of a template which includes another template) or
+// the current working directory.
+func (l ChrootLoader) Abs(base string, name string) string {
+ return filepath.Clean(fmt.Sprintf("%s/%s", l.Path, name))
+}
+
+// Get reads the path's content from your local filesystem.
+func (l ChrootLoader) Get(path string) (io.Reader, error) {
+ // Get the full path
+ path, err := filepath.EvalSymlinks(path)
+ if err != nil {
+ return nil, err
+ }
+
+ basePath, err := filepath.EvalSymlinks(l.Path)
+ if err != nil {
+ return nil, err
+ }
+
+ // Validate that we're under the expected prefix
+ if !strings.HasPrefix(path, basePath) {
+ return nil, fmt.Errorf("Attempting to access a file outside the container")
+ }
+
+ // Open and read the file
+ buf, err := ioutil.ReadFile(path)
+ if err != nil {
+ return nil, err
+ }
+
+ return bytes.NewReader(buf), nil
+}
diff --git a/test/suites/static_analysis.sh b/test/suites/static_analysis.sh
index 425287a42..91c3ab5a6 100644
--- a/test/suites/static_analysis.sh
+++ b/test/suites/static_analysis.sh
@@ -57,6 +57,7 @@ test_static_analysis() {
if which golint >/dev/null 2>&1; then
golint -set_exit_status client/
golint -set_exit_status lxc/config/
+ golint -set_exit_status lxd/template/
golint -set_exit_status shared/api/
golint -set_exit_status shared/cancel/
golint -set_exit_status shared/cmd/
More information about the lxc-devel
mailing list