Skip to content

Commit 7157dcc

Browse files
committed
[workspacekit] Don't bogously filter proc mount targets
1 parent e68e76d commit 7157dcc

File tree

2 files changed

+31
-34
lines changed

2 files changed

+31
-34
lines changed

components/workspacekit/pkg/seccomp/notify.go

Lines changed: 28 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"fmt"
1010
"os"
1111
"path/filepath"
12+
"strconv"
1213
"strings"
1314
"time"
1415

@@ -225,56 +226,50 @@ func (h *InWorkspaceHandler) Mount(req *libseccomp.ScmpNotifReq) (val uint64, er
225226
"fstype": filesystem,
226227
}).Info("handling mount syscall")
227228

228-
if filesystem == "proc" {
229+
if filesystem == "proc" || filesystem == "sysfs" {
230+
// When a process wants to mount proc relative to `/proc/self` that path has no meaning outside of the processes' context.
231+
// runc started doing this in https://github.com/opencontainers/runc/commit/0ca91f44f1664da834bc61115a849b56d22f595f
232+
// TODO(cw): there must be a better way to handle this. Find one.
229233
target := filepath.Join(h.Ring2Rootfs, dest)
230-
stat, err := os.Lstat(target)
231-
if os.IsNotExist(err) {
232-
err = os.MkdirAll(target, 0755)
233-
}
234-
if err != nil {
235-
log.WithField("dest", dest).WithError(err).Error("cannot stat mountpoint")
236-
return Errno(unix.EFAULT)
237-
} else if stat != nil && stat.Mode()&os.ModeDir == 0 {
238-
log.WithField("dest", dest).WithError(err).Error("proc must be mounted on an ordinary directory")
239-
return Errno(unix.EPERM)
240-
}
241-
242-
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
243-
defer cancel()
244-
_, err = h.Daemon.MountProc(ctx, &daemonapi.MountProcRequest{
245-
Target: dest,
246-
Pid: int64(req.Pid),
247-
})
248-
if err != nil {
249-
log.WithField("target", target).WithError(err).Error("cannot mount proc")
250-
return Errno(unix.EFAULT)
234+
if strings.HasPrefix(dest, "/proc/self/") {
235+
target = filepath.Join("/proc", strconv.Itoa(int(req.Pid)), strings.TrimPrefix(dest, "/proc/self/"))
251236
}
252237

253-
return 0, 0, 0
254-
}
255-
256-
if filesystem == "sysfs" {
257-
target := filepath.Join(h.Ring2Rootfs, dest)
258238
stat, err := os.Lstat(target)
259239
if os.IsNotExist(err) {
260240
err = os.MkdirAll(target, 0755)
261241
}
262242
if err != nil {
263-
log.WithField("dest", dest).WithError(err).Error("cannot stat mountpoint")
243+
log.WithField("target", target).WithField("dest", dest).WithError(err).Error("cannot stat mountpoint")
264244
return Errno(unix.EFAULT)
265-
} else if stat != nil && stat.Mode()&os.ModeDir == 0 {
266-
log.WithField("dest", dest).WithError(err).Error("sysfs must be mounted on an ordinary directory")
267-
return Errno(unix.EPERM)
245+
}
246+
if stat != nil {
247+
if stat.Mode()&os.ModeSymlink != 0 {
248+
// The symlink is already expressed relative to the ring2 mount namespace, no need to faff with the rootfs paths.
249+
// In case this was a /proc relative symlink, we'll have that symlink resolved here, hence make it work in the mount namespace of ring2.
250+
dest, err = os.Readlink(target)
251+
if err != nil {
252+
log.WithField("target", target).WithField("dest", dest).WithError(err).Errorf("cannot resolve %s mount target symlink", filesystem)
253+
return Errno(unix.EFAULT)
254+
}
255+
} else if stat.Mode()&os.ModeDir == 0 {
256+
log.WithField("target", target).WithField("dest", dest).WithField("mode", stat.Mode()).WithError(err).Errorf("%s must be mounted on an ordinary directory", filesystem)
257+
return Errno(unix.EPERM)
258+
}
268259
}
269260

270261
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
271262
defer cancel()
272-
_, err = h.Daemon.MountSysfs(ctx, &daemonapi.MountProcRequest{
263+
call := h.Daemon.MountProc
264+
if filesystem == "sysfs" {
265+
call = h.Daemon.MountSysfs
266+
}
267+
_, err = call(ctx, &daemonapi.MountProcRequest{
273268
Target: dest,
274269
Pid: int64(req.Pid),
275270
})
276271
if err != nil {
277-
log.WithField("target", target).WithError(err).Error("cannot mount sysfs")
272+
log.WithField("target", dest).WithError(err).Errorf("cannot mount %s", filesystem)
278273
return Errno(unix.EFAULT)
279274
}
280275

components/ws-daemon/pkg/iws/iws.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -582,10 +582,12 @@ func moveMount(instanceID string, targetPid int, source, target string) error {
582582
mntf := os.NewFile(mntfd, "")
583583
defer mntf.Close()
584584

585+
// Note(cw): we also need to enter the target PID namespace because the mount target
586+
// might refer to proc.
585587
err = nsinsider(instanceID, targetPid, func(c *exec.Cmd) {
586588
c.Args = append(c.Args, "move-mount", "--target", target, "--pipe-fd", "3")
587589
c.ExtraFiles = append(c.ExtraFiles, mntf)
588-
})
590+
}, enterPidNS(true))
589591
if err != nil {
590592
return xerrors.Errorf("cannot move mount: %w", err)
591593
}

0 commit comments

Comments
 (0)