Skip to content

Commit

Permalink
Merge pull request #4101 from cyphar/runc-dmz-go-get-build
Browse files Browse the repository at this point in the history
libcontainer: dmz: fix "go get" builds
  • Loading branch information
AkihiroSuda authored Nov 7, 2023
2 parents 2705c9c + 9d8fa6d commit 5bcffdf
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 17 deletions.
2 changes: 1 addition & 1 deletion libcontainer/dmz/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ else
CFLAGS += -DRUNC_USE_STDLIB
endif

runc-dmz: _dmz.c
binary/runc-dmz: _dmz.c
$(CC) $(CFLAGS) -static -o $@ $^
$(STRIP) -gs $@
File renamed without changes.
Empty file.
51 changes: 35 additions & 16 deletions libcontainer/dmz/dmz_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,32 @@ package dmz
import (
"bytes"
"debug/elf"
_ "embed"
"embed"
"os"
"sync"

"github.com/sirupsen/logrus"
)

// Try to build the runc-dmz binary. If it fails, replace it with an empty file
// (this will trigger us to fall back to a clone of /proc/self/exe). Yeah, this
// is a bit ugly but it makes sure that weird cross-compilation setups don't
// break because of runc-dmz.
// Try to build the runc-dmz binary on "go generate". If it fails (or
// libcontainer is being imported as a library), the embed.FS will not contain
// the file, which will then cause us to fall back to a clone of
// /proc/self/exe.
//
//go:generate sh -c "make -B runc-dmz || echo -n >runc-dmz"
//go:embed runc-dmz
var runcDmzBinary []byte
// There is an empty file called dummy-file.txt in libcontainer/dmz/binary in
// order to work around the restriction that go:embed requires at least one
// file to match the pattern.
//
//go:generate make -B binary/runc-dmz
//go:embed binary
var runcDmzFs embed.FS

// A cached copy of the contents of runc-dmz.
var (
runcDmzBinaryOnce sync.Once
runcDmzBinaryIsValid bool
runcDmzBinary []byte
)

// Binary returns a cloned copy (see CloneBinary) of a very minimal C program
// that just does an execve() of its arguments. This is used in the final
Expand All @@ -31,18 +43,25 @@ var runcDmzBinary []byte
// If the runc-dmz binary is not embedded into the runc binary, Binary will
// return ErrNoDmzBinary as the error.
func Binary(tmpDir string) (*os.File, error) {
rdr := bytes.NewBuffer(runcDmzBinary)
// Verify that our embedded binary has a standard ELF header.
if !bytes.HasPrefix(rdr.Bytes(), []byte(elf.ELFMAG)) {
if rdr.Len() != 0 {
logrus.Infof("misconfigured build: embedded runc-dmz binary is non-empty but is missing a proper ELF header")
}
return nil, ErrNoDmzBinary
}
// Setting RUNC_DMZ=legacy disables this dmz method.
if os.Getenv("RUNC_DMZ") == "legacy" {
logrus.Debugf("RUNC_DMZ=legacy set -- switching back to classic /proc/self/exe cloning")
return nil, ErrNoDmzBinary
}
runcDmzBinaryOnce.Do(func() {
runcDmzBinary, _ = runcDmzFs.ReadFile("binary/runc-dmz")
// Verify that our embedded binary has a standard ELF header.
if !bytes.HasPrefix(runcDmzBinary, []byte(elf.ELFMAG)) {
if len(runcDmzBinary) != 0 {
logrus.Infof("misconfigured build: embedded runc-dmz binary is non-empty but is missing a proper ELF header")
}
} else {
runcDmzBinaryIsValid = true
}
})
if !runcDmzBinaryIsValid {
return nil, ErrNoDmzBinary
}
rdr := bytes.NewBuffer(runcDmzBinary)
return CloneBinary(rdr, int64(rdr.Len()), "runc-dmz", tmpDir)
}

0 comments on commit 5bcffdf

Please sign in to comment.