Use v2 capabilities in layer archives
When building images in a user-namespaced container, v3 capabilities are stored including the root UID of the creator of the user-namespace. This UID does not make sense outside the build environment however. If the image is run in a non-user-namespaced runtime, or if a user-namespaced runtime uses a different UID, the capabilities requested by the effective bit will not be honoured by `execve(2)` due to this mismatch. Instead, we convert v3 capabilities to v2, dropping the root UID on the fly. Signed-off-by: Eric Mountain <eric.mountain@datadoghq.com>
This commit is contained in:
parent
4d6bc59f81
commit
95eb490780
|
@ -126,15 +126,6 @@ func TestBuildUserNamespaceValidateCapabilitiesAreV2(t *testing.T) {
|
||||||
_, err = stdcopy.StdCopy(actualStdout, actualStderr, logReader)
|
_, err = stdcopy.StdCopy(actualStdout, actualStderr, logReader)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
if strings.TrimSpace(actualStdout.String()) != "/bin/sleep cap_net_bind_service=eip" {
|
if strings.TrimSpace(actualStdout.String()) != "/bin/sleep cap_net_bind_service=eip" {
|
||||||
// Activate when fix is merged: https://github.com/moby/moby/pull/41724
|
t.Fatalf("run produced invalid output: %q, expected %q", actualStdout.String(), "/bin/sleep cap_net_bind_service=eip")
|
||||||
//t.Fatalf("run produced invalid output: %q, expected %q", actualStdout.String(), "/bin/sleep cap_net_bind_service=eip")
|
|
||||||
// t.Logf("run produced invalid output (expected until #41724 merges): %q, expected %q",
|
|
||||||
// actualStdout.String(),
|
|
||||||
// "/bin/sleep cap_net_bind_service=eip")
|
|
||||||
} else {
|
|
||||||
// Shouldn't happen until fix is merged: https://github.com/moby/moby/pull/41724
|
|
||||||
t.Fatalf("run produced valid output (unexpected until #41724 merges): %q, expected %q",
|
|
||||||
actualStdout.String(),
|
|
||||||
"/bin/sleep cap_net_bind_service=eip")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -402,10 +402,24 @@ func fillGo18FileTypeBits(mode int64, fi os.FileInfo) int64 {
|
||||||
// ReadSecurityXattrToTarHeader reads security.capability xattr from filesystem
|
// ReadSecurityXattrToTarHeader reads security.capability xattr from filesystem
|
||||||
// to a tar header
|
// to a tar header
|
||||||
func ReadSecurityXattrToTarHeader(path string, hdr *tar.Header) error {
|
func ReadSecurityXattrToTarHeader(path string, hdr *tar.Header) error {
|
||||||
|
const (
|
||||||
|
// Values based on linux/include/uapi/linux/capability.h
|
||||||
|
xattrCapsSz2 = 20
|
||||||
|
versionOffset = 3
|
||||||
|
vfsCapRevision2 = 2
|
||||||
|
vfsCapRevision3 = 3
|
||||||
|
)
|
||||||
capability, _ := system.Lgetxattr(path, "security.capability")
|
capability, _ := system.Lgetxattr(path, "security.capability")
|
||||||
if capability != nil {
|
if capability != nil {
|
||||||
|
length := len(capability)
|
||||||
|
if capability[versionOffset] == vfsCapRevision3 {
|
||||||
|
// Convert VFS_CAP_REVISION_3 to VFS_CAP_REVISION_2 as root UID makes no
|
||||||
|
// sense outside the user namespace the archive is built in.
|
||||||
|
capability[versionOffset] = vfsCapRevision2
|
||||||
|
length = xattrCapsSz2
|
||||||
|
}
|
||||||
hdr.Xattrs = make(map[string]string)
|
hdr.Xattrs = make(map[string]string)
|
||||||
hdr.Xattrs["security.capability"] = string(capability)
|
hdr.Xattrs["security.capability"] = string(capability[:length])
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue