fleet/pkg/buildpkg/buildpkg.go
guangwu 33858d7301
chore: remove refs to deprecated io/ioutil (#14485)
# Checklist for submitter

If some of the following don't apply, delete the relevant line.

- [ ] Changes file added for user-visible changes in `changes/` or
`orbit/changes/`.
See [Changes
files](https://fleetdm.com/docs/contributing/committing-changes#changes-files)
for more information.
- [ ] Documented any API changes (docs/Using-Fleet/REST-API.md or
docs/Contributing/API-for-contributors.md)
- [ ] Documented any permissions changes (docs/Using
Fleet/manage-access.md)
- [ ] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements)
- [ ] Added support on fleet's osquery simulator `cmd/osquery-perf` for
new osquery data ingestion features.
- [ ] Added/updated tests
- [ ] Manual QA for all new/changed functionality
  - For Orbit and Fleet Desktop changes:
- [ ] Manual QA must be performed in the three main OSs, macOS, Windows
and Linux.
- [ ] Auto-update manual QA, from released version of component to new
version (see [tools/tuf/test](../tools/tuf/test/README.md)).

Signed-off-by: guoguangwu <guoguangwu@magic-shield.com>
2023-10-27 15:28:54 -03:00

131 lines
3.3 KiB
Go

// Package buildpkg contains utilities to build Fleet components.
package buildpkg
import (
"debug/macho"
"encoding/binary"
"errors"
"fmt"
"os"
)
// Adapted from Unlicensed https://github.com/randall77/makefat/blob/master/makefat.go
const (
magicFat64 = macho.MagicFat + 1 // TODO: add to stdlib (...when it works)
// Alignment wanted for each sub-file.
// amd64 needs 12 bits, arm64 needs 14. We choose the max of all requirements here.
alignBits = 14
align = 1 << alignBits
)
// MakeMacOSFatExecutable makes a macOS fat executable from the given binaries.
func MakeMacOSFatExecutable(outPath string, inPaths ...string) error {
// Read input files.
type input struct {
data []byte
cpu uint32
subcpu uint32
offset int64
}
var inputs []input
offset := int64(align)
for _, i := range inPaths {
data, err := os.ReadFile(i)
if err != nil {
return err
}
if len(data) < 12 {
return fmt.Errorf("file %s too small", i)
}
// All currently supported mac archs (386,amd64,arm,arm64) are little endian.
magic := binary.LittleEndian.Uint32(data[0:4])
if magic != macho.Magic32 && magic != macho.Magic64 {
return fmt.Errorf("input %s is not a macho file, magic=%x", i, magic)
}
cpu := binary.LittleEndian.Uint32(data[4:8])
subcpu := binary.LittleEndian.Uint32(data[8:12])
inputs = append(inputs, input{data: data, cpu: cpu, subcpu: subcpu, offset: offset})
offset += int64(len(data))
offset = (offset + align - 1) / align * align
}
// Decide on whether we're doing fat32 or fat64.
sixtyfour := false
if inputs[len(inputs)-1].offset >= 1<<32 || len(inputs[len(inputs)-1].data) >= 1<<32 {
// fat64 doesn't seem to work:
// - the resulting binary won't run.
// - the resulting binary is parseable by lipo, but reports that the contained files are "hidden".
// - the native OSX lipo can't make a fat64.
return errors.New("files too large to fit into a fat binary")
}
// Make output file.
out, err := os.Create(outPath)
if err != nil {
return err
}
err = out.Chmod(0o755)
if err != nil {
return err
}
// Build a fat_header.
var hdr []uint32
if sixtyfour {
hdr = append(hdr, magicFat64)
} else {
hdr = append(hdr, macho.MagicFat)
}
hdr = append(hdr, uint32(len(inputs)))
// Build a fat_arch for each input file.
for _, i := range inputs {
hdr = append(hdr, i.cpu)
hdr = append(hdr, i.subcpu)
if sixtyfour {
hdr = append(hdr, uint32(i.offset>>32)) // big endian
}
hdr = append(hdr, uint32(i.offset))
if sixtyfour {
hdr = append(hdr, uint32(len(i.data)>>32)) // big endian
}
hdr = append(hdr, uint32(len(i.data)))
hdr = append(hdr, alignBits)
if sixtyfour {
hdr = append(hdr, 0) // reserved
}
}
// Write header.
// Note that the fat binary header is big-endian, regardless of the
// endianness of the contained files.
err = binary.Write(out, binary.BigEndian, hdr)
if err != nil {
return err
}
offset = int64(4 * len(hdr))
// Write each contained file.
for _, i := range inputs {
if offset < i.offset {
_, err = out.Write(make([]byte, i.offset-offset))
if err != nil {
return err
}
offset = i.offset
}
_, err := out.Write(i.data)
if err != nil {
return err
}
offset += int64(len(i.data))
}
err = out.Close()
if err != nil {
return err
}
return nil
}