Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Osquerybeat: Strip osqueryd binary for linux #38952

Merged
merged 10 commits into from
Apr 22, 2024
13 changes: 13 additions & 0 deletions dev-tools/mage/crossbuild.go
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,19 @@ func (b GolangCrossBuilder) Build() error {
"--env", fmt.Sprintf("SNAPSHOT=%v", Snapshot),
"-v", repoInfo.RootDir+":"+mountPoint,
"-w", workDir,
)

// Ensure the proper platform is passed
// This fixes an issue where during arm64 linux build for the currently used docker image
// docker.elastic.co/beats-dev/golang-crossbuild:1.21.9-arm the image for amd64 arch is pulled
// and causes problems when using native arch tools on the binaries that are built for arm64 arch.
if strings.HasPrefix(b.Platform, "linux/") {
args = append(args,
"--platform", b.Platform,
)
}

args = append(args,
image,

// Arguments for docker crossbuild entrypoint. For details see
Expand Down
146 changes: 146 additions & 0 deletions x-pack/osquerybeat/magefile.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,24 @@
package main

import (
"context"
"errors"
"fmt"
"os"
"path/filepath"
"runtime"
"strings"
"time"

"github.com/magefile/mage/mg"

devtools "github.com/elastic/beats/v7/dev-tools/mage"
"github.com/elastic/beats/v7/dev-tools/mage/target/build"

"github.com/elastic/beats/v7/x-pack/osquerybeat/internal/command"
"github.com/elastic/beats/v7/x-pack/osquerybeat/internal/distro"
"github.com/elastic/beats/v7/x-pack/osquerybeat/internal/fileutil"

osquerybeat "github.com/elastic/beats/v7/x-pack/osquerybeat/scripts/mage"

// mage:import
Expand Down Expand Up @@ -87,9 +95,147 @@ func Clean() error {
return devtools.Clean(paths)
}

func execCommand(ctx context.Context, name string, args ...string) error {
ps := strings.Join(append([]string{name}, args...), " ")
fmt.Println(ps)
output, err := command.Execute(ctx, name, args...)
if err != nil {
fmt.Println(ps, ", failed: ", err)
return err
}
fmt.Print(output)
return err
}

func extractFromMSI() error {
if os.Getenv("GOOS") != "windows" {
return nil
}

ctx := context.Background()

osArchs := osquerybeat.OSArchs(devtools.Platforms)

for _, osarch := range osArchs {
if osarch.OS != "windows" {
continue
}
spec, err := distro.GetSpec(osarch)
if err != nil {
if errors.Is(err, distro.ErrUnsupportedOS) {
continue
} else {
return err
}
}
dip := distro.GetDataInstallDir(osarch)
msiFile := spec.DistroFilepath(dip)

// MSI extract
err = execCommand(ctx, "msiextract", "--directory", dip, msiFile)
if err != nil {
return err
}

fmt.Println("copy certs.pem from MSI")
err = devtools.Copy(filepath.Join(dip, distro.OsquerydCertsWindowsDistroPath()), distro.OsquerydCertsPath(dip))
if err != nil {
return err
}

fmt.Println("copy osqueryd.exe from MSI")
dp := distro.OsquerydPathForOS(osarch.OS, dip)
err = devtools.Copy(filepath.Join(dip, "osquery", "osqueryd", "osqueryd.exe"), dp)
if err != nil {
fmt.Println("copy osqueryd.exe from MSI failed: ", err)
return err
}
// Chmod set to the same as other executables in the final package
if err = os.Chmod(dp, 0755); err != nil {
return err
}
}

return nil
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this still here? The code has changed to not need this specifically in osquerybeat.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This a mistake on conflict resolution (context switching), the function is not used. Removed.


// stripLinuxOsqueryd Strips osqueryd binary, that is not stripped in linux tar.gz distro
func stripLinuxOsqueryd() error {
if os.Getenv("GOOS") != "linux" {
return nil
}

// Check that this step is called during x-pack/osquerybeat/ext/osquery-extension build
cwd, err := os.Getwd()
if err != nil {
return err
}

// Strip osqueryd only once when osquery-extension is built
// There are two build paths at the moment both through GolangCrossBuild
// 1. Standlone osquerybeat package (this function is called twice: for osquerybeat and osquery-extension)
// 2. Agentbeat package, this function is only called once for osquery-extension
if !strings.HasSuffix(cwd, "/osquery-extension") {
return nil
}

ctx := context.Background()

osArchs := osquerybeat.OSArchs(devtools.Platforms)

strip := func(oquerydPath string) error {
ok, err := fileutil.FileExists(oquerydPath)
if err != nil {
return err
}
if ok {
if err := execCommand(ctx, "strip", oquerydPath); err != nil {
return err
}
}
return nil
}

for _, osarch := range osArchs {
// Skip everything but matching linux arch
if osarch.OS != os.Getenv("GOOS") || osarch.Arch != os.Getenv("GOARCH") {
continue
}

// Strip osqueryd
// There are two scenarios where the build path is created depending on the type of build
// 1. Standlone osquerybeat build: the osqueryd binaries are downloaded into osquerybeat/build/data/install/[GOOS]/[GOARCH]
// 2. Agentbeat build: the osqueryd binaries are downloaded agentbeat/build/data/install/[GOOS]/[GOARCH]

// This returns something like build/data/install/linux/amd64/osqueryd
querydRelativePath := distro.OsquerydPath(distro.GetDataInstallDir(osarch))

// Checking and stripping osqueryd binary and both paths osquerybeat/build and agentbeat/build
// because at the moment it's unclear if this step was initiated from osquerybeat or agentbeat build
osquerybeatPath := filepath.Clean(filepath.Join(cwd, "../..", querydRelativePath))
err = strip(osquerybeatPath)
if err != nil {
return err
}

agentbeatPath := filepath.Clean(filepath.Join(cwd, "../../../agentbeat", querydRelativePath))
err = strip(agentbeatPath)
if err != nil {
return err
}
}

return nil
}

// GolangCrossBuild build the Beat binary inside of the golang-builder.
// Do not use directly, use crossBuild instead.
func GolangCrossBuild() error {
// Strip linux osqueryd binary
if err := stripLinuxOsqueryd(); err != nil {
return err
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this work for agentbeat? Agentbeat doesn't import the magefile from osquerybeat.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works because agent beat calls out to osquerybeat to build the extension

return callForBeat("crossBuildExt", "osquerybeat")

This path is also followed for stanalone osquerybeat crossbuild.

return devtools.GolangCrossBuild(devtools.DefaultGolangCrossBuildArgs())
}

Expand Down
Loading