[lxc-devel] [lxd/master] seccomp: retry with mount hotplug

brauner on Github lxc-bot at linuxcontainers.org
Mon Jun 17 18:05:09 UTC 2019


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 438 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20190617/a49b2628/attachment.bin>
-------------- next part --------------
From 8f33d911f2bd74f943d0b029d644fe9df939385b Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Mon, 17 Jun 2019 19:58:57 +0200
Subject: [PATCH 1/2] container_lxc: add insertMount() helpers

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 lxd/container_lxc.go | 119 ++++++++++++++++++++++++-------------------
 1 file changed, 66 insertions(+), 53 deletions(-)

diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index f5cad36e9e..1c8b113c2e 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -7064,76 +7064,89 @@ func (c *containerLXC) StorageStop() (bool, error) {
 }
 
 // Mount handling
-func (c *containerLXC) insertMount(source, target, fstype string, flags int) error {
-	var err error
-
-	// Get the init PID
-	pid := c.InitPID()
-	if pid == -1 {
-		// Container isn't running
-		return fmt.Errorf("Can't insert mount into stopped container")
-	}
+func (c *containerLXC) insertMountLXD(source, target, fstype string, flags int, mntnsPID int) error {
 
-	if c.state.OS.LXCFeatures["mount_injection_file"] {
-		cname := projectPrefix(c.Project(), c.Name())
-		configPath := filepath.Join(c.LogPath(), "lxc.conf")
-		if fstype == "" {
-			fstype = "none"
-		}
-
-		if !strings.HasPrefix(target, "/") {
-			target = "/" + target
+	pid := mntnsPID
+	if pid <= 0 {
+		// Get the init PID
+		pid = c.InitPID()
+		if pid == -1 {
+			// Container isn't running
+			return fmt.Errorf("Can't insert mount into stopped container")
 		}
+	}
 
-		_, err := shared.RunCommand(c.state.OS.ExecPath, "forkmount", "lxc-mount", cname, c.state.OS.LxcPath, configPath, source, target, fstype, fmt.Sprintf("%d", flags))
+	// Create the temporary mount target
+	var tmpMount string
+	var err error
+	if shared.IsDir(source) {
+		tmpMount, err = ioutil.TempDir(c.ShmountsPath(), "lxdmount_")
 		if err != nil {
-			return err
+			return fmt.Errorf("Failed to create shmounts path: %s", err)
 		}
 	} else {
-		// Create the temporary mount target
-		var tmpMount string
-		if shared.IsDir(source) {
-			tmpMount, err = ioutil.TempDir(c.ShmountsPath(), "lxdmount_")
-			if err != nil {
-				return fmt.Errorf("Failed to create shmounts path: %s", err)
-			}
-		} else {
-			f, err := ioutil.TempFile(c.ShmountsPath(), "lxdmount_")
-			if err != nil {
-				return fmt.Errorf("Failed to create shmounts path: %s", err)
-			}
-
-			tmpMount = f.Name()
-			f.Close()
-		}
-		defer os.Remove(tmpMount)
-
-		// Mount the filesystem
-		err = unix.Mount(source, tmpMount, fstype, uintptr(flags), "")
+		f, err := ioutil.TempFile(c.ShmountsPath(), "lxdmount_")
 		if err != nil {
-			return fmt.Errorf("Failed to setup temporary mount: %s", err)
+			return fmt.Errorf("Failed to create shmounts path: %s", err)
 		}
-		defer unix.Unmount(tmpMount, unix.MNT_DETACH)
 
-		// Move the mount inside the container
-		mntsrc := filepath.Join("/dev/.lxd-mounts", filepath.Base(tmpMount))
-		pidStr := fmt.Sprintf("%d", pid)
+		tmpMount = f.Name()
+		f.Close()
+	}
+	defer os.Remove(tmpMount)
 
-		out, err := shared.RunCommand(c.state.OS.ExecPath, "forkmount", "lxd-mount", pidStr, mntsrc, target)
+	// Mount the filesystem
+	err = unix.Mount(source, tmpMount, fstype, uintptr(flags), "")
+	if err != nil {
+		return fmt.Errorf("Failed to setup temporary mount: %s", err)
+	}
+	defer unix.Unmount(tmpMount, unix.MNT_DETACH)
 
-		if out != "" {
-			for _, line := range strings.Split(strings.TrimRight(out, "\n"), "\n") {
-				logger.Debugf("forkmount: %s", line)
-			}
-		}
-		if err != nil {
-			return err
+	// Move the mount inside the container
+	mntsrc := filepath.Join("/dev/.lxd-mounts", filepath.Base(tmpMount))
+	pidStr := fmt.Sprintf("%d", pid)
+
+	out, err := shared.RunCommand(c.state.OS.ExecPath, "forkmount", "lxd-mount", pidStr, mntsrc, target)
+
+	if out != "" {
+		for _, line := range strings.Split(strings.TrimRight(out, "\n"), "\n") {
+			logger.Debugf("forkmount: %s", line)
 		}
 	}
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (c *containerLXC) insertMountLXC(source, target, fstype string, flags int) error {
+	cname := projectPrefix(c.Project(), c.Name())
+	configPath := filepath.Join(c.LogPath(), "lxc.conf")
+	if fstype == "" {
+		fstype = "none"
+	}
+
+	if !strings.HasPrefix(target, "/") {
+		target = "/" + target
+	}
+
+	_, err := shared.RunCommand(c.state.OS.ExecPath, "forkmount", "lxc-mount", cname, c.state.OS.LxcPath, configPath, source, target, fstype, fmt.Sprintf("%d", flags))
+	if err != nil {
+		return err
+	}
 
 	return nil
 }
 
+func (c *containerLXC) insertMount(source, target, fstype string, flags int) error {
+	if c.state.OS.LXCFeatures["mount_injection_file"] {
+		return c.insertMountLXC(source, target, fstype, flags)
+	}
+
+	return c.insertMountLXD(source, target, fstype, flags, -1)
+}
+
 func (c *containerLXC) removeMount(mount string) error {
 	// Get the init PID
 	pid := c.InitPID()

From 41df0a784ff1376c3a77cc95556d6ed4afc5dfa0 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Mon, 17 Jun 2019 19:59:55 +0200
Subject: [PATCH 2/2] seccomp: retry with mount hotplug

When device creation via mknod fails, fallback to messing with mounts.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 lxd/container.go     |  2 ++
 lxd/container_lxc.go | 24 ++++++++++++++++++++++++
 lxd/seccomp.go       | 37 +++++++++++++++++++++++++++++--------
 3 files changed, 55 insertions(+), 8 deletions(-)

diff --git a/lxd/container.go b/lxd/container.go
index a526d2bee6..3fba380612 100644
--- a/lxd/container.go
+++ b/lxd/container.go
@@ -729,6 +729,8 @@ type container interface {
 	CurrentIdmap() (*idmap.IdmapSet, error)
 	DiskIdmap() (*idmap.IdmapSet, error)
 	NextIdmap() (*idmap.IdmapSet, error)
+
+	InsertSeccompUnixDevice(prefix string, m types.Device, pid int) error
 }
 
 // Loader functions
diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index 1c8b113c2e..97227025c1 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -7400,6 +7400,30 @@ func (c *containerLXC) insertUnixDevice(prefix string, m types.Device, defaultMo
 	return nil
 }
 
+func (c *containerLXC) InsertSeccompUnixDevice(prefix string, m types.Device, pid int) error {
+
+	if pid < 0 {
+		return fmt.Errorf("Invalid request PID specified")
+	}
+
+	cwdLink := fmt.Sprintf("/proc/%d/cwd", pid)
+	prefixPath, err := os.Readlink(cwdLink)
+	if err != nil {
+		return err
+	}
+
+	m["path"] = fmt.Sprintf("%s/%s", prefixPath, m["path"])
+	paths, err := c.createUnixDevice(prefix, m, true)
+	if err != nil {
+		return fmt.Errorf("Failed to setup device: %s", err)
+	}
+	devPath := paths[0]
+	tgtPath := paths[1]
+
+	// Bind-mount it into the container
+	return c.insertMountLXD(devPath, tgtPath, "none", unix.MS_BIND, pid)
+}
+
 func (c *containerLXC) insertUnixDeviceNum(name string, m types.Device, major int, minor int, path string, defaultMode bool) error {
 	temp := types.Device{}
 	if err := shared.DeepCopy(&m, &temp); err != nil {
diff --git a/lxd/seccomp.go b/lxd/seccomp.go
index 32397b9729..b0766ea63d 100644
--- a/lxd/seccomp.go
+++ b/lxd/seccomp.go
@@ -15,6 +15,7 @@ import (
 
 	"golang.org/x/sys/unix"
 
+	"github.com/lxc/lxd/lxd/types"
 	"github.com/lxc/lxd/lxd/util"
 	"github.com/lxc/lxd/shared"
 	"github.com/lxc/lxd/shared/logger"
@@ -130,6 +131,7 @@ static int seccomp_notify_mknod_set_response(int fd_mem, struct seccomp_notify_p
 	resp->id = req->id;
 	resp->flags = req->flags;
 	resp->val = 0;
+	resp->error = 0;
 
 	switch (req->data.nr) {
 #ifdef LXD_MUST_CHECK_MKNOD
@@ -457,21 +459,40 @@ func (s *SeccompServer) Handler(c net.Conn, ucred *ucred, buf []byte, fdMem int)
 		unix.PathMax, &cMode,
 		&cDev, &cPid)
 	if ret == 0 {
+		devPath := C.GoString(&cPathBuf[0])
 		errnoMsg, err := shared.RunCommand(util.GetExecPath(),
 			"forkmknod",
 			fmt.Sprintf("%d", cPid),
-			C.GoString(&cPathBuf[0]),
+			devPath,
 			fmt.Sprintf("%d", cMode),
 			fmt.Sprintf("%d", cDev))
 		if err != nil {
-			cErrno := C.int(-C.EPERM)
-			goErrno, err2 := strconv.Atoi(errnoMsg)
-			if err2 == nil {
-				cErrno = -C.int(goErrno)
-			}
+			// Do not call functions that would call into liblxc since this would timeout the seccomp notifier
+			c, err := findContainerForPid(int32(msg.monitor_pid), s.d)
+			if err != nil {
+				cErrno := C.int(-C.EPERM)
+				goErrno, err2 := strconv.Atoi(errnoMsg)
+				if err2 == nil {
+					cErrno = -C.int(goErrno)
+				}
+
+				C.seccomp_notify_mknod_update_response(&msg, cErrno)
+				logger.Errorf("Failed to create device node: %s", err)
+			} else {
+				dev := types.Device{}
+				dev["type"] = "unix-char"
+				dev["path"] = devPath
+				dev["major"] = fmt.Sprintf("%d", unix.Major(uint64(cDev)))
+				dev["minor"] = fmt.Sprintf("%d", unix.Minor(uint64(cDev)))
 
-			C.seccomp_notify_mknod_update_response(&msg, cErrno)
-			logger.Errorf("Failed to create device node: %s", err)
+				err = c.InsertSeccompUnixDevice("forkmknod-unix-char", dev, int(cPid))
+				if err != nil {
+					C.seccomp_notify_mknod_update_response(&msg, C.ENOSYS)
+					logger.Errorf("Failed to create device node: %s", err)
+				}
+
+				os.Remove(dev["hostpath"])
+			}
 		}
 	}
 


More information about the lxc-devel mailing list