Repository: opencontainers/runc
File: libcontainer/dmz/dmz_linux.go (Go)

Code before:
	"bytes"
	"debug/elf"
	"embed"
	"os"

	"github.com/sirupsen/logrus"
)

// 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.
//
// There is an empty file called runc-dmz-dummy-file.txt in libcontainer/dmz in
// order to work around the restriction that go:embed requires at least one
// file to match the pattern.
//
//go:generate sh -c "make -B runc-dmz"
//go:embed runc-dmz*
var runcDmzFs embed.FS

// The contents of runc-dmz.
var runcDmzBinary []byte

func init() {
	runcDmzBinary, _ = runcDmzFs.ReadFile("runc-dmz")
}

// 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
// execution step of the container execution as an intermediate process before
// the container process is execve'd. This allows for protection against
// CVE-2019-5736 without requiring a complete copy of the runc binary. Each
// call to Binary will return a new copy.
//
// 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
	}

Review comment (suggestion):
I'm thinking, since we only need dmz binary for runc start/run/exec, maybe instead of adding `init()` it is better to integrate this code into the `Binary` function below?

We may even get rid of using `bytes.NewBuffer` since it might be sufficient to do `runDmzFs.Open` and return the resulting file.


Code after:
	"bytes"
	"debug/elf"
	"embed"
	"os"
	"sync"

	"github.com/sirupsen/logrus"
)

// 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.
//
// 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
// execution step of the container execution as an intermediate process before
// the container process is execve'd. This allows for protection against
// CVE-2019-5736 without requiring a complete copy of the runc binary. Each
// call to Binary will return a new copy.
//
// 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) {
	// 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")
			}