From 66a72d9283475770707adc3f2be04a3b48635fd7 Mon Sep 17 00:00:00 2001
From: Matthew Heon <matthew.heon@pm.me>
Date: Fri, 8 Mar 2019 15:33:12 -0500
Subject: [PATCH] Ensure that tmpfs mounts do not have symlinks

When mounting a tmpfs, runc attempts to make the directory it
will be mounted at. Unfortunately, Golang's os.MkdirAll deals
very poorly with symlinks being part of the path. I looked into
fixing this in runc, but it's honestly much easier to just ensure
we don't trigger the issue on our end.

Fixes BZ #1686610

Signed-off-by: Matthew Heon <matthew.heon@pm.me>
---
 libpod/container_internal_linux.go | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index c9f35dd753..3f3b22b6b6 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -26,6 +26,7 @@ import (
 	"github.com/containers/libpod/pkg/resolvconf"
 	"github.com/containers/libpod/pkg/rootless"
 	"github.com/containers/storage/pkg/idtools"
+	"github.com/cyphar/filepath-securejoin"
 	"github.com/opencontainers/runc/libcontainer/user"
 	spec "github.com/opencontainers/runtime-spec/specs-go"
 	"github.com/opencontainers/runtime-tools/generate"
@@ -366,6 +367,18 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
 	// For private volumes any root propagation value should work.
 	rootPropagation := ""
 	for _, m := range mounts {
+		// We need to remove all symlinks from tmpfs mounts.
+		// Runc and other runtimes may choke on them.
+		// Easy solution: use securejoin to do a scoped evaluation of
+		// the links, then trim off the mount prefix.
+		if m.Type == "tmpfs" {
+			finalPath, err := securejoin.SecureJoin(c.state.Mountpoint, m.Destination)
+			if err != nil {
+				return nil, errors.Wrapf(err, "error resolving symlinks for mount destination %s", m.Destination)
+			}
+			trimmedPath := strings.TrimPrefix(finalPath, strings.TrimSuffix(c.state.Mountpoint, "/"))
+			m.Destination = trimmedPath
+		}
 		g.AddMount(m)
 		for _, opt := range m.Options {
 			switch opt {