Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve uid shifting via chown. #44

Merged
merged 1 commit into from
Nov 29, 2021
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
47 changes: 12 additions & 35 deletions idShiftUtils/idShiftUtils.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,6 @@ import (
mapset "github.com/deckarep/golang-set"
)

type OffsetType int

const (
OffsetAdd OffsetType = iota
OffsetSub
)

type aclType int

const (
Expand All @@ -48,7 +41,7 @@ const (
)

// Shifts the ACL type user and group IDs by the given offset
func shiftAclType(aclT aclType, path string, uidOffset, gidOffset uint32, offsetDir OffsetType) error {
func shiftAclType(aclT aclType, path string, uidOffset, gidOffset int32) error {
var facl aclLib.ACL
var err error

Expand Down Expand Up @@ -77,13 +70,8 @@ func shiftAclType(aclT aclType, path string, uidOffset, gidOffset uint32, offset
continue
}

if offsetDir == OffsetAdd {
uid = uid + uint64(uidOffset)
} else {
uid = uid - uint64(uidOffset)
}

e.Qualifier = strconv.FormatUint(uid, 10)
targetUid := uint64(int32(uid) + uidOffset)
e.Qualifier = strconv.FormatUint(targetUid, 10)
aclShifted = true
}

Expand All @@ -95,13 +83,8 @@ func shiftAclType(aclT aclType, path string, uidOffset, gidOffset uint32, offset
continue
}

if offsetDir == OffsetAdd {
gid = gid + uint64(gidOffset)
} else {
gid = gid - uint64(gidOffset)
}

e.Qualifier = strconv.FormatUint(gid, 10)
targetGid := uint64(int32(gid) + gidOffset)
e.Qualifier = strconv.FormatUint(targetGid, 10)
aclShifted = true
}

Expand Down Expand Up @@ -129,17 +112,17 @@ func shiftAclType(aclT aclType, path string, uidOffset, gidOffset uint32, offset
}

// Shifts the ACL user and group IDs by the given offset, both for access and default ACLs
func shiftAclIds(path string, isDir bool, uidOffset, gidOffset uint32, offsetDir OffsetType) error {
func shiftAclIds(path string, isDir bool, uidOffset, gidOffset int32) error {

// Access list
err := shiftAclType(aclTypeAccess, path, uidOffset, gidOffset, offsetDir)
err := shiftAclType(aclTypeAccess, path, uidOffset, gidOffset)
if err != nil {
return err
}

// Default list (for directories only)
if isDir {
err = shiftAclType(aclTypeDefault, path, uidOffset, gidOffset, offsetDir)
err = shiftAclType(aclTypeDefault, path, uidOffset, gidOffset)
if err != nil {
return err
}
Expand All @@ -150,13 +133,12 @@ func shiftAclIds(path string, isDir bool, uidOffset, gidOffset uint32, offsetDir

// "Shifts" ownership of user and group IDs on the given directory and files and directories
// below it by the given offset, using chown.
func ShiftIdsWithChown(baseDir string, uidOffset, gidOffset uint32, offsetDir OffsetType) error {
func ShiftIdsWithChown(baseDir string, uidOffset, gidOffset int32) error {

hardLinks := []uint64{}

err := godirwalk.Walk(baseDir, &godirwalk.Options{
Callback: func(path string, de *godirwalk.Dirent) error {
var targetUid, targetGid uint32

// When doing the chown, we don't follow symlinks as we want to change
// the ownership of the symlinks themselves. We will chown the
Expand Down Expand Up @@ -184,13 +166,8 @@ func ShiftIdsWithChown(baseDir string, uidOffset, gidOffset uint32, offsetDir Of
hardLinks = append(hardLinks, st.Ino)
}

if offsetDir == OffsetAdd {
targetUid = st.Uid + uidOffset
targetGid = st.Gid + gidOffset
} else {
targetUid = st.Uid - uidOffset
targetGid = st.Gid - gidOffset
}
targetUid := int32(st.Uid) + uidOffset
targetGid := int32(st.Gid) + gidOffset

logrus.Debugf("chown %s from %d:%d to %d:%d", path, st.Uid, st.Gid, targetUid, targetGid)

Expand All @@ -203,7 +180,7 @@ func ShiftIdsWithChown(baseDir string, uidOffset, gidOffset uint32, offsetDir Of
// the Linux access control list (ACL) for the file

if fi.Mode()&os.ModeSymlink == 0 {
if err := shiftAclIds(path, fi.IsDir(), uidOffset, gidOffset, offsetDir); err != nil {
if err := shiftAclIds(path, fi.IsDir(), uidOffset, gidOffset); err != nil {
return fmt.Errorf("failed to shift ACL for %s: %s", path, err)
}
}
Expand Down
22 changes: 10 additions & 12 deletions mgr.go
Original file line number Diff line number Diff line change
Expand Up @@ -476,15 +476,13 @@ func (mgr *SysboxMgr) unregister(id string) error {
// revert mount prep actions
for _, revInfo := range info.mntPrepRev {
if revInfo.uidShifted {
logrus.Infof("reverting uid-shift on %s for %s", revInfo.path, formatter.ContainerID{id})

// revInfo.targetUid is guaranteed to be higher than revInfo.origUid
// (we checked in prepMounts())
uidOffset := int32(revInfo.origUid) - int32(revInfo.targetUid)
gidOffset := int32(revInfo.origGid) - int32(revInfo.targetGid)

uidOffset := revInfo.targetUid - revInfo.origUid
gidOffset := revInfo.targetGid - revInfo.origGid
logrus.Infof("reverting uid-shift on %s for %s (%d -> %d)", revInfo.path, formatter.ContainerID{id}, revInfo.targetUid, revInfo.origUid)

if err = idShiftUtils.ShiftIdsWithChown(revInfo.path, uidOffset, gidOffset, idShiftUtils.OffsetSub); err != nil {
if err = idShiftUtils.ShiftIdsWithChown(revInfo.path, uidOffset, gidOffset); err != nil {
logrus.Warnf("failed to revert uid-shift of mount source at %s: %s", revInfo.path, err)
}

Expand Down Expand Up @@ -837,15 +835,15 @@ func (mgr *SysboxMgr) prepMounts(id string, uid, gid uint32, prepList []ipcLib.M
}

if needUidShift {
logrus.Infof("shifting uids at %s for %s", src, formatter.ContainerID{id})

// uid is guaranteed to be higher than origUid (we checked in
// mntSrcUidShiftNeeded())
// Offset may be positive or negative
uidOffset := int32(uid) - int32(origUid)
gidOffset := int32(gid) - int32(origGid)

uidOffset := uid - origUid
gidOffset := gid - origGid
logrus.Infof("shifting uids at %s for %s (%d -> %d)", src, formatter.ContainerID{id}, origUid, uid)

if err = idShiftUtils.ShiftIdsWithChown(src, uidOffset, gidOffset, idShiftUtils.OffsetAdd); err != nil {
// TODO: for kernel >= 5.12, we need to do this using the new ID-mapped mount feature (faster, more reliable).
if err = idShiftUtils.ShiftIdsWithChown(src, uidOffset, gidOffset); err != nil {
return fmt.Errorf("failed to shift uids via chown for mount source at %s: %s", src, err)
}

Expand Down
36 changes: 8 additions & 28 deletions utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -723,28 +723,13 @@ func mntSrcUidShiftNeeded(mntSrc string, uid, gid uint32) (bool, uint32, uint32,
mntSrcUid = st.Uid
mntSrcGid = st.Gid

// If the host uid assigned to the container is higher than the uid
// of the dir being mounted into the container, then we perform uid
// If the host uid assigned to the container's root user differs from the
// uid of the dir being mounted into the container, then we perform uid
// shifting. Same for gid.
if uid > mntSrcUid && gid > mntSrcGid {
if uid != mntSrcUid && gid != mntSrcGid {
return true, mntSrcUid, mntSrcGid, nil
}

// If the host uid assigned to the container is lower than the uid of the dir
// being mounted, we skip the uid shift. This is in fact an anomalous case
// because in general the host dir being mounted into the container should
// have host range uids (e.g., 0->65535) and these are usually lower than the
// uids assigned to the container (which come from the subuid ranges in
// /etc/subuid).
if uid < mntSrcUid || gid < mntSrcGid {

logrus.Infof("skipping uid shift on %s because its uid:gid (%d:%d) is "+
"> the container's assigned uid:gid (%d:%d)",
mntSrc, mntSrcUid, mntSrcGid, uid, gid)

return false, mntSrcUid, mntSrcGid, nil
}

// If the mount dir has same ownership as the container, check the subdirs
// before we make a determination on whether ownership shifting will be
// required.
Expand All @@ -755,21 +740,16 @@ func mntSrcUidShiftNeeded(mntSrc string, uid, gid uint32) (bool, uint32, uint32,
return false, 0, 0, err
}

needChown := true
numNeedChown := 0
for _, fi := range dirFis {
st, _ := fi.Sys().(*syscall.Stat_t)

if uid <= st.Uid && gid <= st.Gid {

logrus.Infof("skipping uid shift on %s because subdir %s has uid:gid (%d:%d) which is "+
">= the container's assigned uid:gid (%d:%d)",
mntSrc, fi.Name(), st.Uid, st.Gid, uid, gid)

needChown = false
break
if uid != st.Uid || gid != st.Gid {
numNeedChown += 1
}
}

needChown := (numNeedChown == len(dirFis))

return needChown, mntSrcUid, mntSrcGid, nil
}

Expand Down