[lxc-devel] [lxd/master] shared/idmap: Shift fscaps

stgraber on Github lxc-bot at linuxcontainers.org
Thu Aug 2 20:00:11 UTC 2018


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 370 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20180802/3275e772/attachment.bin>
-------------- next part --------------
From a2fb8e28ad2884f4922ab0673beef3755965d0b7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Thu, 2 Aug 2018 00:36:25 -0400
Subject: [PATCH] shared/idmap: Shift fscaps
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Closes #4862

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 shared/idmap/idmapset_linux.go | 30 ++++++++++++++--
 shared/idmap/shift_linux.go    | 63 +++++++++++++++++++++++++++++-----
 2 files changed, 82 insertions(+), 11 deletions(-)

diff --git a/shared/idmap/idmapset_linux.go b/shared/idmap/idmapset_linux.go
index 8c6da8120..91c5c4e9f 100644
--- a/shared/idmap/idmapset_linux.go
+++ b/shared/idmap/idmapset_linux.go
@@ -13,6 +13,7 @@ import (
 	"strings"
 
 	"github.com/lxc/lxd/shared"
+	"github.com/lxc/lxd/shared/logger"
 )
 
 type IdRange struct {
@@ -505,6 +506,7 @@ func (set *IdmapSet) doUidshiftIntoContainer(dir string, testmode bool, how stri
 
 		uid := int64(intUid)
 		gid := int64(intGid)
+		caps := []byte{}
 
 		var newuid, newgid int64
 		switch how {
@@ -517,16 +519,38 @@ func (set *IdmapSet) doUidshiftIntoContainer(dir string, testmode bool, how stri
 		if testmode {
 			fmt.Printf("I would shift %q to %d %d\n", path, newuid, newgid)
 		} else {
+			// Dump capabilities
+			if fi.Mode()&os.ModeSymlink == 0 {
+				caps, err = GetCaps(path)
+				if err != nil {
+					return err
+				}
+			}
+
+			// Shift owner
 			err = ShiftOwner(dir, path, int(newuid), int(newgid))
 			if err != nil {
 				return err
 			}
 
-			err = ShiftACL(path, func(uid int64, gid int64) (int64, int64) { return set.doShiftIntoNs(uid, gid, how) })
-			if err != nil {
-				return err
+			if fi.Mode()&os.ModeSymlink == 0 {
+				// Shift POSIX ACLs
+				err = ShiftACL(path, func(uid int64, gid int64) (int64, int64) { return set.doShiftIntoNs(uid, gid, how) })
+				if err != nil {
+					return err
+				}
+
+				// Shift capabilities
+				if len(caps) != 0 {
+					rootUid, _ := set.ShiftIntoNs(0, 0)
+					err = SetCaps(path, caps, rootUid)
+					if err != nil {
+						logger.Warnf("Unable to set file capabilities on %s", path)
+					}
+				}
 			}
 		}
+
 		return nil
 	}
 
diff --git a/shared/idmap/shift_linux.go b/shared/idmap/shift_linux.go
index d351e0116..e1864bef6 100644
--- a/shared/idmap/shift_linux.go
+++ b/shared/idmap/shift_linux.go
@@ -5,8 +5,9 @@ package idmap
 
 import (
 	"fmt"
-	"os"
 	"unsafe"
+
+	"github.com/lxc/lxd/shared"
 )
 
 // #cgo LDFLAGS: -lacl
@@ -18,11 +19,33 @@ import (
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/capability.h>
 #include <unistd.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/acl.h>
 
+// Needs to be included at the end
+#include <attr/xattr.h>
+
+int set_caps(char *path, char *caps, ssize_t len, uint32_t uid) {
+	ssize_t ret;
+	struct vfs_ns_cap_data ns_xattr;
+
+	memset(&ns_xattr, 0, sizeof(ns_xattr));
+	memcpy(&ns_xattr, caps, len);
+	ns_xattr.magic_etc &= ~(VFS_CAP_REVISION_1 | VFS_CAP_REVISION_2);
+	ns_xattr.magic_etc |= VFS_CAP_REVISION_3 | VFS_CAP_FLAGS_EFFECTIVE;
+	ns_xattr.rootid = uid;
+
+	ret = setxattr(path, "security.capability", &ns_xattr, sizeof(ns_xattr), 0);
+	if (ret < 0) {
+		return -1;
+	}
+
+	return 0;
+}
+
 int shiftowner(char *basepath, char *path, int uid, int gid) {
 	struct stat sb;
 	int fd, r;
@@ -102,20 +125,44 @@ func ShiftOwner(basepath string, path string, uid int, gid int) error {
 	if r != 0 {
 		return fmt.Errorf("Failed to change ownership of: %s", path)
 	}
+
 	return nil
 }
 
-// ShiftACL updates uid and gid for file ACLs when entering/exiting a namespace
-func ShiftACL(path string, shiftIds func(uid int64, gid int64) (int64, int64)) error {
-	finfo, err := os.Lstat(path)
+// GetCaps extracts the list of capabilities effective on the file
+func GetCaps(path string) ([]byte, error) {
+	xattrs, err := shared.GetAllXattr(path)
 	if err != nil {
-		return err
+		return nil, err
 	}
-	if finfo.Mode()&os.ModeSymlink != 0 {
-		return nil
+
+	valueStr, ok := xattrs["security.capability"]
+	if !ok {
+		return nil, nil
 	}
 
-	err = shiftAclType(path, C.ACL_TYPE_ACCESS, shiftIds)
+	return []byte(valueStr), nil
+}
+
+// SetCaps applies the caps for a particular root uid
+func SetCaps(path string, caps []byte, uid int64) error {
+	cpath := C.CString(path)
+	defer C.free(unsafe.Pointer(cpath))
+
+	ccaps := C.CString(string(caps))
+	defer C.free(unsafe.Pointer(ccaps))
+
+	r := C.set_caps(cpath, ccaps, C.ssize_t(len(caps)), C.uint32_t(uid))
+	if r != 0 {
+		return fmt.Errorf("Failed to apply capabilities to: %s", path)
+	}
+
+	return nil
+}
+
+// ShiftACL updates uid and gid for file ACLs when entering/exiting a namespace
+func ShiftACL(path string, shiftIds func(uid int64, gid int64) (int64, int64)) error {
+	err := shiftAclType(path, C.ACL_TYPE_ACCESS, shiftIds)
 	if err != nil {
 		return err
 	}


More information about the lxc-devel mailing list