Skip to content

Commit

Permalink
mesh-init: fix executable copy when dynamic linker is used
Browse files Browse the repository at this point in the history
When using dynamic linking (e.g. Cgo) during compilation, the
`consul-ecs` process will be started by calling the linker to launch the
actual Go executable. This causes `os.Executable()` to return the linker
rather than the program itself.

When self-copying in the `mesh-init` command, check for dynamic linker
use. If detected, fall back to a path-based executable resolution
derived from `os.Argv[0]`, which should provide the name of the real
executable file +/- its path.
  • Loading branch information
zalimeni committed May 1, 2024
1 parent 0b3f4a2 commit 7e72f0c
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 9 deletions.
8 changes: 7 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ jobs:
needs:
- get-go-version
- get-product-version
# Warning: Updating the ubuntu version for this job may cause FIPS builds on arm64 to
# have issues running mesh-init, which copies the Cgo dynamically linked binary to a
# remote host. Compiling against a secure-but-older GLibC version (by using an older
# Ubuntu image) is the easiest way to avoid this issue.
# See https://groups.google.com/g/pat-users/c/dawmYvN4DBc
runs-on: ubuntu-20.04
strategy:
matrix:
Expand Down Expand Up @@ -93,12 +98,13 @@ jobs:
- name: Build
env:
# Env may be overridden by matrix values, e.g. CGO_ENABLED for FIPS builds.
GOOS: ${{ matrix.goos }}
GOARCH: ${{ matrix.goarch }}
LDFLAGS: ${{ needs.get-product-version.outputs.ldflags }}
CGO_ENABLED: "0"
run: |
go env
${{ matrix.env }} go env
mkdir dist out
${{ matrix.env }} go build -tags=${{ matrix.gotags }} -ldflags="$LDFLAGS" -o dist/ .
zip -r -j out/${{ env.PKG_NAME }}_${{ needs.get-product-version.outputs.product-version }}${{ matrix.fips }}_${{ matrix.goos }}_${{ matrix.goarch }}.zip dist/
Expand Down
6 changes: 1 addition & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ SHELL = /usr/bin/env bash -euo pipefail -c
# ---------- CRT ----------
BIN_NAME = consul-ecs

ARCH = $(shell A=$$(uname -m); [ $$A = x86_64 ] && A=amd64; echo $$A)
ARCH = $(shell A=$$(uname -m); [ $$A = x86_64 ] && A=amd64; [ $$A = aarch64 ] && A=arm64; echo $$A)
OS = $(shell uname | tr [[:upper:]] [[:lower:]])
PLATFORM = $(OS)/$(ARCH)
DIST = dist/$(PLATFORM)
Expand Down Expand Up @@ -33,10 +33,6 @@ dev-fips: dist
.PHONY: dev-fips

# Docker Stuff.
# TODO: Docker in CircleCI doesn't support buildkit.
# So we enable build-kit in the individual targets.
# We can set this here one time, once we're off CircleCI.
# export DOCKER_BUILDKIT=1
BUILD_ARGS = BIN_NAME=consul-ecs PRODUCT_VERSION=$(VERSION) GIT_COMMIT=$(GIT_COMMIT) GIT_DIRTY=$(GIT_DIRTY)
TAG = $(BIN_NAME)/$(TARGET):$(VERSION)
BA_FLAGS = $(addprefix --build-arg=,$(BUILD_ARGS))
Expand Down
31 changes: 28 additions & 3 deletions subcommand/mesh-init/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import (
"fmt"
"net"
"os"
"os/exec"
"path"
"path/filepath"
"regexp"
"strconv"
"strings"
"time"
Expand Down Expand Up @@ -51,12 +54,12 @@ func (c *Command) Run(args []string) int {
return 1
}

config, err := config.FromEnv()
configEnv, err := config.FromEnv()
if err != nil {
c.UI.Error(fmt.Sprintf("invalid config: %s", err))
return 1
}
c.config = config
c.config = configEnv

c.log = logging.FromConfig(c.config).Logger()

Expand Down Expand Up @@ -375,6 +378,28 @@ func (c *Command) copyECSBinaryToSharedVolume() error {
if err != nil {
return err
}

// Dynamic linking (e.g. Cgo) can interfere with reading the executable path
// due to the dynamic linker being used to launch the `consul-ecs` binary.
// If detected, fall back to searching for the current executable via os.Args and PATH.
// c.f. https://go.dev/src/os/executable_path.go
if ok, _ := regexp.MatchString("ld-[^.]+\\.so\\.[0-9]+", ex); ok {
c.log.Debug("got dynamic linker from os.Executable(), falling back to path search", "found", ex)
pathEx, err := exec.LookPath(os.Args[0])
if err != nil {
return err
}
pathEx, err = filepath.EvalSymlinks(pathEx)
if err != nil {
return err
}
pathEx, err = filepath.Abs(pathEx)
if err != nil {
return err
}
ex = pathEx
}

data, err := os.ReadFile(ex)
if err != nil {
return err
Expand All @@ -385,7 +410,7 @@ func (c *Command) copyECSBinaryToSharedVolume() error {
if err != nil {
return err
}
c.log.Info("copied binary", "file", copyConsulECSBinary)
c.log.Info("copied binary", "source", ex, "destination", copyConsulECSBinary)
return nil
}

Expand Down

0 comments on commit 7e72f0c

Please sign in to comment.