Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions os/mkosi/components/sysbox/sysbox-build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ checkout https://github.com/nestybox/sysbox-mgr.git "$SYSBOX_MGR_REVISION" "$B/s
checkout https://github.com/nestybox/sysbox-ipc.git "$SYSBOX_IPC_REVISION" "$B/sysbox-ipc"
checkout https://github.com/nestybox/sysbox-libs.git "$SYSBOX_LIBS_REVISION" "$B/sysbox-libs"
checkout https://github.com/Dstack-TEE/fuse.git "$SYSBOX_FUSE_REVISION" "$B/sysbox-fuse"
for repo in sysbox-libs sysbox-ipc sysbox-mgr sysbox-runc; do
patch -d "$B/$repo" -p1 --fuzz=0 < "$ROOT/os/yocto/layers/meta-dstack/recipes-core/dstack-sysbox/files/$repo-idmapped-overlayfs.patch"
done
rm -rf "$B/sysbox-fs/bazil"; ln -s "$B/sysbox-fuse" "$B/sysbox-fs/bazil"
install -m0644 "$ROOT/os/yocto/layers/meta-dstack/recipes-core/dstack-sysbox/files/sysboxFsProtobuf.pb.go" \
"$B/sysbox-ipc/sysboxFsGrpc/sysboxFsProtobuf/"
Expand Down
6 changes: 6 additions & 0 deletions os/mkosi/tests/acceptance.sh
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,12 @@ grep -q '^STARGZ_VERSION=0.18.2$' "$D/versions.env"
grep -q '^NERDCTL_VERSION=2.3.5$' "$D/versions.env"
grep -q '^[[:space:]]*docker-cli$' "$D/mkosi.conf"
grep -q '^SYSBOX_VERSION=0.7.1$' "$D/versions.env"
grep -q 'idmapped-overlayfs.patch' "$D/components/sysbox/sysbox-build.sh"
if grep -q -- '--disable-ovfs-on-idmapped-mount' \
"$D/../yocto/layers/meta-dstack/recipes-core/dstack-sysbox/files/sysbox-mgr.service"; then
echo "sysbox-mgr must not disable ID-mapped overlayfs" >&2
exit 1
fi
grep -q '^ZFS_VERSION=2.4.0$' "$D/versions.env"
grep -q -- '--fuzz=0' "$D/components/zfs/zfs-build.sh"
# ZFS 2.4.0 declares Linux-Maximum 6.18; no out-of-tree compat patch is carried.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ SRC_URI = " \
git://github.com/nestybox/sysbox-ipc.git;nobranch=1;name=sysbox-ipc;protocol=https;destsuffix=sysbox-ipc \
git://github.com/nestybox/sysbox-libs.git;nobranch=1;name=sysbox-libs;protocol=https;destsuffix=sysbox-libs \
git://github.com/Dstack-TEE/fuse.git;branch=master;name=sysbox-fuse;protocol=https;destsuffix=sysbox-fuse \
file://sysbox-libs-idmapped-overlayfs.patch;patchdir=../sysbox-libs \
file://sysbox-ipc-idmapped-overlayfs.patch;patchdir=../sysbox-ipc \
file://sysbox-mgr-idmapped-overlayfs.patch;patchdir=../sysbox-mgr \
file://sysbox-runc-idmapped-overlayfs.patch;patchdir=../sysbox-runc \
file://sysbox.service \
file://sysbox-fs.service \
file://sysbox-mgr.service \
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Kevin Wang <wy721@qq.com>
Date: Mon, 26 Oct 2026 19:54:55 -0700
Subject: [PATCH] sysbox-mgr: report ID-mapped overlayfs support to sysbox-runc

Add ContainerConfig.IDMapMountOnOverlayfsOk so sysbox-runc can choose
the ID-mapped overlayfs rootfs mode.

Signed-off-by: Kevin Wang <wy721@qq.com>
---
sysboxMgrGrpc/grpcClient.go | 1 +
sysboxMgrGrpc/grpcServer.go | 1 +
sysboxMgrGrpc/sysboxMgrProtobuf/sysboxMgrProtobuf.proto | 1 +
sysboxMgrLib/sysboxMgrLib.go | 1 +
4 files changed, 4 insertions(+)

diff --git a/sysboxMgrGrpc/grpcClient.go b/sysboxMgrGrpc/grpcClient.go
index ec38e82..e860d3c 100644
--- a/sysboxMgrGrpc/grpcClient.go
+++ b/sysboxMgrGrpc/grpcClient.go
@@ -84,6 +84,7 @@ func Register(regInfo *ipcLib.RegistrationInfo) (*ipcLib.ContainerConfig, error)
ShiftfsOnOverlayfsOk: resp.ContainerConfig.GetShiftfsOnOverlayfsOk(),
IDMapMountOk: resp.ContainerConfig.GetIDMapMountOk(),
OverlayfsOnIDMapMountOk: resp.ContainerConfig.GetOverlayfsOnIDMapMountOk(),
+ IDMapMountOnOverlayfsOk: resp.ContainerConfig.GetIDMapMountOnOverlayfsOk(),
NoRootfsCloning: resp.ContainerConfig.GetNoRootfsCloning(),
IgnoreSysfsChown: resp.ContainerConfig.GetIgnoreSysfsChown(),
AllowTrustedXattr: resp.ContainerConfig.GetAllowTrustedXattr(),
diff --git a/sysboxMgrGrpc/grpcServer.go b/sysboxMgrGrpc/grpcServer.go
index 009fb6b..177db64 100644
--- a/sysboxMgrGrpc/grpcServer.go
+++ b/sysboxMgrGrpc/grpcServer.go
@@ -128,6 +128,7 @@ func (s *ServerStub) Register(ctx context.Context, req *pb.RegisterReq) (*pb.Reg
ShiftfsOnOverlayfsOk: config.ShiftfsOnOverlayfsOk,
IDMapMountOk: config.IDMapMountOk,
OverlayfsOnIDMapMountOk: config.OverlayfsOnIDMapMountOk,
+ IDMapMountOnOverlayfsOk: config.IDMapMountOnOverlayfsOk,
NoRootfsCloning: config.NoRootfsCloning,
IgnoreSysfsChown: config.IgnoreSysfsChown,
AllowTrustedXattr: config.AllowTrustedXattr,
diff --git a/sysboxMgrGrpc/sysboxMgrProtobuf/sysboxMgrProtobuf.proto b/sysboxMgrGrpc/sysboxMgrProtobuf/sysboxMgrProtobuf.proto
index 392e4fe..7960641 100644
--- a/sysboxMgrGrpc/sysboxMgrProtobuf/sysboxMgrProtobuf.proto
+++ b/sysboxMgrGrpc/sysboxMgrProtobuf/sysboxMgrProtobuf.proto
@@ -90,6 +90,7 @@ message ContainerConfig {
uint32 rootfsUidShiftType = 15;
bool noShiftfsOnFuse = 16;
bool relaxedReadOnly = 17;
+ bool IDMapMountOnOverlayfsOk = 18;
}

message RegisterResp {
diff --git a/sysboxMgrLib/sysboxMgrLib.go b/sysboxMgrLib/sysboxMgrLib.go
index 9f8272d..d9ed601 100644
--- a/sysboxMgrLib/sysboxMgrLib.go
+++ b/sysboxMgrLib/sysboxMgrLib.go
@@ -51,6 +51,7 @@ type ContainerConfig struct {
NoShiftfsOnFuse bool
IDMapMountOk bool
OverlayfsOnIDMapMountOk bool
+ IDMapMountOnOverlayfsOk bool
NoRootfsCloning bool
IgnoreSysfsChown bool
AllowTrustedXattr bool
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Kevin Wang <wy721@qq.com>
Date: Mon, 26 Oct 2026 19:54:55 -0700
Subject: [PATCH] idMap: add ID-mapped overlayfs shift type and probe

Add the IDMappedOverlayfs shift type, appended so existing values keep
their meaning, and IDMapMountSupportedOnOverlayfs(), which mounts a test
overlay and ID-maps the merged mount. The kernel rejects that with
EINVAL unless overlayfs supports ID-mapped mounts (Linux 7.3, or a
backport), so EINVAL reports the feature as unsupported.

IDMapMount now wraps the mount_setattr errno so callers can inspect it.

Signed-off-by: Kevin Wang <wy721@qq.com>
---
idMap/idMapMount.go | 63 +++++++++++++++++++++++++++---------
idShiftUtils/idShiftUtils.go | 1 +
2 files changed, 49 insertions(+), 15 deletions(-)

diff --git a/idMap/idMapMount.go b/idMap/idMapMount.go
index aaff4c9..9fe790b 100644
--- a/idMap/idMapMount.go
+++ b/idMap/idMapMount.go
@@ -86,7 +86,7 @@ func IDMapMount(usernsPath, mountPath string, unmountFirst bool) error {

err = unix.MountSetattr(int(fdTree), "", unix.AT_EMPTY_PATH|unix.AT_RECURSIVE, mountAttr)
if err != nil {
- return fmt.Errorf("Failed to set mount attr: %s", err)
+ return fmt.Errorf("Failed to set mount attr: %w", err)
}

// Unmount the original mountPath mount to prevent redundant / stacked mounting
@@ -120,7 +120,7 @@ func IDMapMountSupported(dir string) (bool, error) {
return false, nil
}

- return runIDMapMountCheckOnHost(dir, false)
+ return runIDMapMountCheckOnHost(dir, idMapCheckDir)
}

// OverlayfsOnIDMapMountSupported checks if overlayfs over ID-mapped lower
@@ -137,13 +137,37 @@ func OverlayfsOnIDMapMountSupported(dir string) (bool, error) {
return false, nil
}

- return runIDMapMountCheckOnHost(dir, true)
+ return runIDMapMountCheckOnHost(dir, idMapCheckOverlayfsLower)
}

-// runIDMapMountCheckOnHost runs a quick test on the host to check if ID-mapping is
-// supported. dir is the path where the test will run. If checkOnOverlayfs
-// is true, the test checks if overlayfs supports ID-mapped lower layers.
-func runIDMapMountCheckOnHost(dir string, checkOnOverlayfs bool) (bool, error) {
+// IDMapMountSupportedOnOverlayfs checks if an overlayfs mount itself (i.e., the
+// merged mount rather than its lower layers) can be ID-mapped on the host.
+func IDMapMountSupportedOnOverlayfs(dir string) (bool, error) {
+
+ // This builds on overlayfs over ID-mapped lower layers (Linux >= 5.19)
+ kernelOK, err := checkKernelVersion(5, 19)
+ if err != nil {
+ return false, err
+ }
+
+ if !kernelOK {
+ return false, nil
+ }
+
+ return runIDMapMountCheckOnHost(dir, idMapCheckOverlayfsMerged)
+}
+
+type idMapCheck int
+
+const (
+ idMapCheckDir idMapCheck = iota
+ idMapCheckOverlayfsLower
+ idMapCheckOverlayfsMerged
+)
+
+// runIDMapMountCheckOnHost runs a quick test on the host to check if the given
+// kind of ID-mapping is supported. dir is the path where the test will run.
+func runIDMapMountCheckOnHost(dir string, check idMapCheck) (bool, error) {
var (
lowerDir, upperDir, workDir, idMapDir string
)
@@ -161,7 +185,7 @@ func runIDMapMountCheckOnHost(dir string, checkOnOverlayfs bool) (bool, error) {
return false, err
}

- if checkOnOverlayfs {
+ if check != idMapCheckDir {
lowerDir = filepath.Join(tmpDir, "lower")
upperDir = filepath.Join(tmpDir, "upper")
workDir = filepath.Join(tmpDir, "work")
@@ -202,25 +226,34 @@ func runIDMapMountCheckOnHost(dir string, checkOnOverlayfs bool) (bool, error) {
// Create the ID mapped mount associated with the child process user-ns
usernsPath := fmt.Sprintf("/proc/%d/ns/user", pid)

- if checkOnOverlayfs {
+ opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", lowerDir, upperDir, workDir)
+
+ switch check {
+ case idMapCheckDir:
+ idMapDir = testDir
+ case idMapCheckOverlayfsLower:
idMapDir = lowerDir
- } else {
+ case idMapCheckOverlayfsMerged:
+ if err := unix.Mount("overlay", testDir, "overlay", 0, opts); err != nil {
+ return false, err
+ }
+ defer unix.Unmount(testDir, unix.MNT_DETACH)
idMapDir = testDir
}

if err := IDMapMount(usernsPath, idMapDir, false); err != nil {
+ if check == idMapCheckOverlayfsMerged && errors.Is(err, unix.EINVAL) {
+ return false, nil
+ }
return false, errors.Wrap(err, "create mapped mount")
}
defer unix.Unmount(idMapDir, unix.MNT_DETACH)

- if checkOnOverlayfs {
- opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", lowerDir, upperDir, workDir)
- flags := uintptr(0)
- if err := unix.Mount("overlay", testDir, "overlay", flags, opts); err != nil {
+ if check == idMapCheckOverlayfsLower {
+ if err := unix.Mount("overlay", testDir, "overlay", 0, opts); err != nil {
return false, err
}
unix.Unmount(testDir, unix.MNT_DETACH)
- return true, nil
}

return true, nil
diff --git a/idShiftUtils/idShiftUtils.go b/idShiftUtils/idShiftUtils.go
index 9e9b410..78d33a3 100644
--- a/idShiftUtils/idShiftUtils.go
+++ b/idShiftUtils/idShiftUtils.go
@@ -42,6 +42,7 @@ const (
IDMappedMount
IDMappedMountOrShiftfs
Chown
+ IDMappedOverlayfs
)

type aclType int
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Kevin Wang <wy721@qq.com>
Date: Mon, 26 Oct 2026 19:54:55 -0700
Subject: [PATCH] mgr: probe ID-mapped overlayfs support

Probe whether the merged overlayfs mount can be ID-mapped and pass the
result to sysbox-runc. --disable-idmapped-mount and
--disable-ovfs-on-idmapped-mount also disable it.

A rootfs in this mode keeps its on-disk ownership, so mount syncing
needs no chown, and update/pause/resume/unregister leave it alone:
they only revert the upper-layer chown of the IDMappedMount mode.

Signed-off-by: Kevin Wang <wy721@qq.com>
---
mgr.go | 10 ++++++++--
utils.go | 19 ++++++++++++-------
2 files changed, 20 insertions(+), 9 deletions(-)

diff --git a/mgr.go b/mgr.go
index 87e6a85..b99ab8d 100644
--- a/mgr.go
+++ b/mgr.go
@@ -95,6 +95,7 @@ type mgrConfig struct {
shiftfsOnOverlayfsOk bool
idMapMountOk bool
overlayfsOnIDMapMountOk bool
+ idMapMountOnOvfsOk bool
noRootfsCloning bool
ignoreSysfsChown bool
allowTrustedXattr bool
@@ -242,9 +243,10 @@ func newSysboxMgr(ctx *cli.Context) (*SysboxMgr, error) {

idMapMountOk := false
ovfsOnIDMapMountOk := false
+ idMapMountOnOvfsOk := false

if !ctx.GlobalBool("disable-idmapped-mount") {
- idMapMountOk, ovfsOnIDMapMountOk, err = checkIDMapMountSupport(ctx)
+ idMapMountOk, ovfsOnIDMapMountOk, idMapMountOnOvfsOk, err = checkIDMapMountSupport(ctx)
if err != nil {
return nil, fmt.Errorf("ID-mapping check failed: %v", err)
}
@@ -252,6 +254,7 @@ func newSysboxMgr(ctx *cli.Context) (*SysboxMgr, error) {

if ctx.GlobalBool("disable-ovfs-on-idmapped-mount") {
ovfsOnIDMapMountOk = false
+ idMapMountOnOvfsOk = false
}

shiftfsModPresent := false
@@ -310,6 +313,7 @@ func newSysboxMgr(ctx *cli.Context) (*SysboxMgr, error) {
shiftfsOnOverlayfsOk: shiftfsOnOvfsOk,
idMapMountOk: idMapMountOk,
overlayfsOnIDMapMountOk: ovfsOnIDMapMountOk,
+ idMapMountOnOvfsOk: idMapMountOnOvfsOk,
noRootfsCloning: ctx.GlobalBool("disable-rootfs-cloning"),
ignoreSysfsChown: ctx.GlobalBool("ignore-sysfs-chown"),
allowTrustedXattr: ctx.GlobalBool("allow-trusted-xattr"),
@@ -346,6 +350,7 @@ func newSysboxMgr(ctx *cli.Context) (*SysboxMgr, error) {
logrus.Info("Use of overlayfs on ID-mapped mounts disabled.")
} else {
logrus.Infof("Overlayfs on ID-mapped mounts supported by kernel: %s", ifThenElse(mgrCfg.overlayfsOnIDMapMountOk, "yes", "no"))
+ logrus.Infof("ID-mapped overlayfs mounts supported by kernel: %s", ifThenElse(mgrCfg.idMapMountOnOvfsOk, "yes", "no"))
}

if mgrCfg.noRootfsCloning {
@@ -615,6 +620,7 @@ func (mgr *SysboxMgr) register(regInfo *ipcLib.RegistrationInfo) (*ipcLib.Contai
ShiftfsOnOverlayfsOk: mgr.mgrCfg.shiftfsOnOverlayfsOk,
IDMapMountOk: mgr.mgrCfg.idMapMountOk,
OverlayfsOnIDMapMountOk: mgr.mgrCfg.overlayfsOnIDMapMountOk,
+ IDMapMountOnOverlayfsOk: mgr.mgrCfg.idMapMountOnOvfsOk,
NoRootfsCloning: mgr.mgrCfg.noRootfsCloning,
IgnoreSysfsChown: mgr.mgrCfg.ignoreSysfsChown,
AllowTrustedXattr: mgr.mgrCfg.allowTrustedXattr,
@@ -980,7 +986,7 @@ func (mgr *SysboxMgr) reqMounts(id string, rootfsUidShiftType idShiftUtils.IDShi

switch rootfsUidShiftType {

- case idShiftUtils.IDMappedMount:
+ case idShiftUtils.IDMappedMount, idShiftUtils.IDMappedOverlayfs:
volChownOnSync = false
volUid = 0
volGid = 0
diff --git a/utils.go b/utils.go
index 92389f5..61a1445 100644
--- a/utils.go
+++ b/utils.go
@@ -912,7 +912,7 @@ func getInode(file string) (uint64, error) {
return st.Ino, nil
}

-func checkIDMapMountSupport(ctx *cli.Context) (bool, bool, error) {
+func checkIDMapMountSupport(ctx *cli.Context) (bool, bool, bool, error) {

// The sysbox lib dir may have restrictive permissions; loosen those up
// temporarily while we perform the ID-map check since it runs inside a
@@ -921,12 +921,12 @@ func checkIDMapMountSupport(ctx *cli.Context) (bool, bool, error) {
// write-other permissions.
fi, err := os.Stat(sysboxLibDir)
if err != nil {
- return false, false, err
+ return false, false, false, err
}
origPerm := fi.Mode()

if err := os.Chmod(sysboxLibDir, 0755); err != nil {
- return false, false, fmt.Errorf("failed to chmod %s to 0755: %s", sysboxLibDir, err)
+ return false, false, false, fmt.Errorf("failed to chmod %s to 0755: %s", sysboxLibDir, err)
}

defer func() {
@@ -935,19 +935,24 @@ func checkIDMapMountSupport(ctx *cli.Context) (bool, bool, error) {

IDMapMountOk, err := idMap.IDMapMountSupported(sysboxLibDir)
if err != nil {
- return false, false, fmt.Errorf("failed to check kernel ID-mapping support: %v", err)
+ return false, false, false, fmt.Errorf("failed to check kernel ID-mapping support: %v", err)
}

ovfsOnIDMapMountOk, err := idMap.OverlayfsOnIDMapMountSupported(sysboxLibDir)
if err != nil {
- return false, false, fmt.Errorf("failed to check kernel ID-mapping-on-overlayfs support: %v", err)
+ return false, false, false, fmt.Errorf("failed to check kernel ID-mapping-on-overlayfs support: %v", err)
+ }
+
+ idMapMountOnOvfsOk, err := idMap.IDMapMountSupportedOnOverlayfs(sysboxLibDir)
+ if err != nil {
+ return false, false, false, fmt.Errorf("failed to check kernel ID-mapped overlayfs mount support: %v", err)
}

if err := os.Chmod(sysboxLibDir, origPerm); err != nil {
- return false, false, fmt.Errorf("failed to chmod %s back to %o: %s", sysboxLibDir, origPerm, err)
+ return false, false, false, fmt.Errorf("failed to chmod %s back to %o: %s", sysboxLibDir, origPerm, err)
}

- return IDMapMountOk, ovfsOnIDMapMountOk, nil
+ return IDMapMountOk, ovfsOnIDMapMountOk, idMapMountOnOvfsOk, nil
}

func checkShiftfsSupport(ctx *cli.Context) (bool, bool, error) {
Loading
Loading