From d19e998e7a99d24122da3e98d9886e3b7b4b3501 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Fri, 14 Feb 2014 14:24:37 +0100 Subject: [PATCH 1/4] Archive: Add Add Lgetxattr and Lsetxattr implementations Docker-DCO-1.1-Signed-off-by: Alexander Larsson (github: alexlarsson) --- archive/stat_linux.go | 53 +++++++++++++++++++++++++++++++++++++ archive/stat_unsupported.go | 8 ++++++ 2 files changed, 61 insertions(+) diff --git a/archive/stat_linux.go b/archive/stat_linux.go index f87a99c55a..2910ce5bab 100644 --- a/archive/stat_linux.go +++ b/archive/stat_linux.go @@ -37,3 +37,56 @@ func UtimesNano(path string, ts []syscall.Timespec) error { } return nil } + +// Returns a nil slice and nil error if the xattr is not set +func Lgetxattr(path string, attr string) ([]byte, error) { + pathBytes, err := syscall.BytePtrFromString(path) + if err != nil { + return nil, err + } + attrBytes, err := syscall.BytePtrFromString(attr) + if err != nil { + return nil, err + } + + dest := make([]byte, 128) + destBytes := unsafe.Pointer(&dest[0]) + sz, _, errno := syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0) + if errno == syscall.ENODATA { + return nil, nil + } + if errno == syscall.ERANGE { + dest = make([]byte, sz) + destBytes := unsafe.Pointer(&dest[0]) + sz, _, errno = syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0) + } + if errno != 0 { + return nil, errno + } + + return dest[:sz], nil +} + +var _zero uintptr + +func Lsetxattr(path string, attr string, data []byte, flags int) error { + pathBytes, err := syscall.BytePtrFromString(path) + if err != nil { + return err + } + attrBytes, err := syscall.BytePtrFromString(attr) + if err != nil { + return err + } + var dataBytes unsafe.Pointer + if len(data) > 0 { + dataBytes = unsafe.Pointer(&data[0]) + } else { + dataBytes = unsafe.Pointer(&_zero) + } + _, _, errno := syscall.Syscall6(syscall.SYS_LSETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(dataBytes), uintptr(len(data)), uintptr(flags), 0) + if errno != 0 { + return errno + } + return nil +} diff --git a/archive/stat_unsupported.go b/archive/stat_unsupported.go index 50ca461867..99f1fbc7da 100644 --- a/archive/stat_unsupported.go +++ b/archive/stat_unsupported.go @@ -19,3 +19,11 @@ func LUtimesNano(path string, ts []syscall.Timespec) error { func UtimesNano(path string, ts []syscall.Timespec) error { return ErrNotImplemented } + +func Lgetxattr(path string, attr string) ([]byte, error) { + return nil, ErrNotImplemented +} + +func Lsetxattr(path string, attr string, data []byte, flags int) error { + return ErrNotImplemented +} From c8428d77fdde41786aa5c0c4e64e0e762f873676 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Wed, 15 Jan 2014 15:05:30 +0100 Subject: [PATCH 2/4] archive: extract xattrs from tarfiles Docker-DCO-1.1-Signed-off-by: Alexander Larsson (github: alexlarsson) --- archive/archive.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/archive/archive.go b/archive/archive.go index 16c01993b7..206580fa08 100644 --- a/archive/archive.go +++ b/archive/archive.go @@ -251,6 +251,12 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader) e return err } + for key, value := range hdr.Xattrs { + if err := Lsetxattr(path, key, []byte(value), 0); err != nil { + return err + } + } + // There is no LChmod, so ignore mode for symlink. Also, this // must happen after chown, as that can modify the file mode if hdr.Typeflag != tar.TypeSymlink { From 87ca750cdc3114a340af1c5bc9394cc5f6242677 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Fri, 17 Jan 2014 10:51:59 +0100 Subject: [PATCH 3/4] archive: Detect file changes to capability bits Docker-DCO-1.1-Signed-off-by: Alexander Larsson (github: alexlarsson) --- archive/changes.go | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/archive/changes.go b/archive/changes.go index b46b13bbe7..a9eba8196f 100644 --- a/archive/changes.go +++ b/archive/changes.go @@ -1,6 +1,7 @@ package archive import ( + "bytes" "code.google.com/p/go/src/pkg/archive/tar" "fmt" "github.com/dotcloud/docker/utils" @@ -126,10 +127,11 @@ func Changes(layers []string, rw string) ([]Change, error) { } type FileInfo struct { - parent *FileInfo - name string - stat syscall.Stat_t - children map[string]*FileInfo + parent *FileInfo + name string + stat syscall.Stat_t + children map[string]*FileInfo + capability []byte } func (root *FileInfo) LookUp(path string) *FileInfo { @@ -200,7 +202,8 @@ func (info *FileInfo) addChanges(oldInfo *FileInfo, changes *[]Change) { oldStat.Rdev != newStat.Rdev || // Don't look at size for dirs, its not a good measure of change (oldStat.Size != newStat.Size && oldStat.Mode&syscall.S_IFDIR != syscall.S_IFDIR) || - !sameFsTimeSpec(getLastModification(oldStat), getLastModification(newStat)) { + !sameFsTimeSpec(getLastModification(oldStat), getLastModification(newStat)) || + bytes.Compare(oldChild.capability, newChild.capability) != 0 { change := Change{ Path: newChild.path(), Kind: ChangeModify, @@ -275,6 +278,8 @@ func collectFileInfo(sourceDir string) (*FileInfo, error) { return err } + info.capability, _ = Lgetxattr(path, "security.capability") + parent.children[info.name] = info return nil From 3b9953903b12eaca76655311bd44533768f6f3da Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Mon, 20 Jan 2014 12:26:08 +0100 Subject: [PATCH 4/4] archive: Handle capabilities in tar files If a file has a security.capability set, we push this to the tar file. This is important to handle in e.g. layer files or when copying files to containers, as some distros (e.g. Fedora) use capability bits as a more finegrained version of setuid bits, and thus if the capabilites are stripped (and setuid is not set) the binaries will fail to work. Docker-DCO-1.1-Signed-off-by: Alexander Larsson (github: alexlarsson) --- archive/archive.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/archive/archive.go b/archive/archive.go index 206580fa08..8bb0a8ed1c 100644 --- a/archive/archive.go +++ b/archive/archive.go @@ -165,6 +165,13 @@ func addTarFile(path, name string, tw *tar.Writer) error { hdr.Devmajor = int64(major(uint64(stat.Rdev))) hdr.Devminor = int64(minor(uint64(stat.Rdev))) } + + } + + capability, _ := Lgetxattr(path, "security.capability") + if capability != nil { + hdr.Xattrs = make(map[string]string) + hdr.Xattrs["security.capability"] = string(capability) } if err := tw.WriteHeader(hdr); err != nil {