github.com/opencontainers/runc@v1.2.0-rc.1.0.20240520010911-492dc558cdd6/libcontainer/dmz/dmz_linux.go (about) 1 //go:build !runc_nodmz 2 // +build !runc_nodmz 3 4 package dmz 5 6 import ( 7 "bytes" 8 "debug/elf" 9 "embed" 10 "fmt" 11 "os" 12 "strconv" 13 "sync" 14 15 "github.com/sirupsen/logrus" 16 ) 17 18 // Try to build the runc-dmz binary on "go generate". If it fails (or 19 // libcontainer is being imported as a library), the embed.FS will not contain 20 // the file, which will then cause us to fall back to a clone of 21 // /proc/self/exe. 22 // 23 // There is an empty file called dummy-file.txt in libcontainer/dmz/binary in 24 // order to work around the restriction that go:embed requires at least one 25 // file to match the pattern. 26 // 27 //go:generate make -B binary/runc-dmz 28 //go:embed binary 29 var runcDmzFs embed.FS 30 31 // A cached copy of the contents of runc-dmz. 32 var ( 33 runcDmzBinaryOnce sync.Once 34 runcDmzBinaryIsValid bool 35 runcDmzBinary []byte 36 ) 37 38 // Binary returns a cloned copy (see CloneBinary) of a very minimal C program 39 // that just does an execve() of its arguments. This is used in the final 40 // execution step of the container execution as an intermediate process before 41 // the container process is execve'd. This allows for protection against 42 // CVE-2019-5736 without requiring a complete copy of the runc binary. Each 43 // call to Binary will return a new copy. 44 // 45 // If the runc-dmz binary is not embedded into the runc binary, Binary will 46 // return ErrNoDmzBinary as the error. 47 func Binary(tmpDir string) (*os.File, error) { 48 // Only RUNC_DMZ=true enables runc_dmz. 49 runcDmz := os.Getenv("RUNC_DMZ") 50 if runcDmz == "" { 51 logrus.Debugf("RUNC_DMZ is not set -- switching back to classic /proc/self/exe cloning") 52 return nil, ErrNoDmzBinary 53 } 54 if dmzEnabled, err := strconv.ParseBool(runcDmz); err == nil && !dmzEnabled { 55 logrus.Debugf("RUNC_DMZ is false -- switching back to classic /proc/self/exe cloning") 56 return nil, ErrNoDmzBinary 57 } else if err != nil { 58 return nil, fmt.Errorf("parsing RUNC_DMZ: %w", err) 59 } 60 61 runcDmzBinaryOnce.Do(func() { 62 runcDmzBinary, _ = runcDmzFs.ReadFile("binary/runc-dmz") 63 // Verify that our embedded binary has a standard ELF header. 64 if !bytes.HasPrefix(runcDmzBinary, []byte(elf.ELFMAG)) { 65 if len(runcDmzBinary) != 0 { 66 logrus.Infof("misconfigured build: embedded runc-dmz binary is non-empty but is missing a proper ELF header") 67 } 68 } else { 69 runcDmzBinaryIsValid = true 70 } 71 }) 72 if !runcDmzBinaryIsValid { 73 return nil, ErrNoDmzBinary 74 } 75 rdr := bytes.NewBuffer(runcDmzBinary) 76 return CloneBinary(rdr, int64(rdr.Len()), "runc-dmz", tmpDir) 77 }