Files
runc/libcontainer/dmz/dmz_linux.go
T
Aleksa Sarai 9d8fa6d695 libcontainer: dmz: fix "go get" builds
Because runc-dmz is not checked into Git, go get will end up creating a
copy of libcontainer/dmz with no runc-dmz binary, which causes external
libcontainer users to have compilation errors.

Unfortunately, we cannot get go:embed to just ignore that there are no
files matching the provided pattern, so instead we need to create a
dummy file that matches the go:embed (which we check into Git and so go
get _will_ copy) and switch to embed.FS.

This is a little bit uglier, but at least it will fix external
libcontainer users.

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2023-11-03 08:23:14 +11:00

68 lines
2.1 KiB
Go

//go:build !runc_nodmz
// +build !runc_nodmz
package dmz
import (
"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")
}
} else {
runcDmzBinaryIsValid = true
}
})
if !runcDmzBinaryIsValid {
return nil, ErrNoDmzBinary
}
rdr := bytes.NewBuffer(runcDmzBinary)
return CloneBinary(rdr, int64(rdr.Len()), "runc-dmz", tmpDir)
}