ldd: run in native sandbox
All checks were successful
Test / Create distribution (push) Successful in 25s
Test / Fortify (push) Successful in 2m27s
Test / Fpkg (push) Successful in 3m22s
Test / Data race detector (push) Successful in 3m43s
Test / Flake checks (push) Successful in 48s

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
2025-03-14 17:51:29 +09:00
parent f41fd94628
commit 4bb5d9780f
6 changed files with 41 additions and 45 deletions

View File

@@ -7,8 +7,7 @@ import (
"os/exec"
"time"
"git.gensokyo.uk/security/fortify/helper"
"git.gensokyo.uk/security/fortify/helper/bwrap"
"git.gensokyo.uk/security/fortify/internal/sandbox"
)
const lddTimeout = 2 * time.Second
@@ -18,34 +17,31 @@ var (
msgStaticGlibc = []byte("not a dynamic executable")
)
func Exec(ctx context.Context, p string) ([]*Entry, error) {
var h helper.Helper
if toolPath, err := exec.LookPath("ldd"); err != nil {
return nil, err
} else if h, err = helper.NewBwrap(
(&bwrap.Config{
Hostname: "fortify-ldd",
Chdir: "/",
Syscall: &bwrap.SyscallPolicy{DenyDevel: true, Multiarch: true},
NewSession: true,
DieWithParent: true,
}).Bind("/", "/").DevTmpfs("/dev"), toolPath, false,
nil, func(_, _ int) []string { return []string{p} },
nil, nil,
); err != nil {
return nil, err
}
stdout, stderr := new(bytes.Buffer), new(bytes.Buffer)
h.Stdout(stdout).Stderr(stderr)
func Exec(ctx context.Context, p string) ([]*Entry, error) { return ExecFilter(ctx, nil, nil, p) }
func ExecFilter(ctx context.Context,
commandContext func(context.Context) *exec.Cmd,
f func([]byte) []byte,
p string) ([]*Entry, error) {
c, cancel := context.WithTimeout(ctx, lddTimeout)
defer cancel()
if err := h.Start(c, false); err != nil {
container := sandbox.New(c, "ldd", p)
container.Hostname = "fortify-ldd"
stdout, stderr := new(bytes.Buffer), new(bytes.Buffer)
container.Stdout = stdout
container.Stderr = stderr
container.Bind("/", "/", 0).Dev("/dev")
if commandContext != nil {
container.CommandContext = commandContext
}
if err := container.Start(); err != nil {
return nil, err
} else if err = container.Serve(); err != nil {
return nil, err
}
if err := h.Wait(); err != nil {
if err := container.Wait(); err != nil {
m := stderr.Bytes()
if bytes.Contains(m, append([]byte(p+": "), msgStatic...)) ||
bytes.Contains(m, msgStaticGlibc) {
@@ -56,5 +52,9 @@ func Exec(ctx context.Context, p string) ([]*Entry, error) {
return nil, err
}
return Parse(stdout)
v := stdout.Bytes()
if f != nil {
v = f(v)
}
return Parse(v)
}

View File

@@ -2,7 +2,6 @@
package ldd
import (
"fmt"
"math"
"path"
"strconv"
@@ -15,8 +14,8 @@ type Entry struct {
Location uint64 `json:"location"`
}
func Parse(stdout fmt.Stringer) ([]*Entry, error) {
payload := strings.Split(strings.TrimSpace(stdout.String()), "\n")
func Parse(p []byte) ([]*Entry, error) {
payload := strings.Split(strings.TrimSpace(string(p)), "\n")
result := make([]*Entry, len(payload))
for i, ent := range payload {

View File

@@ -3,7 +3,6 @@ package ldd_test
import (
"errors"
"reflect"
"strings"
"testing"
"git.gensokyo.uk/security/fortify/ldd"
@@ -34,10 +33,7 @@ libzstd.so.1 => /usr/lib/libzstd.so.1 7ff71bfd2000
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
stdout := new(strings.Builder)
stdout.WriteString(tc.out)
if _, err := ldd.Parse(stdout); !errors.Is(err, tc.wantErr) {
if _, err := ldd.Parse([]byte(tc.out)); !errors.Is(err, tc.wantErr) {
t.Errorf("Parse() error = %v, wantErr %v", err, tc.wantErr)
}
})
@@ -111,10 +107,7 @@ libc.musl-x86_64.so.1 => /lib/ld-musl-x86_64.so.1 (0x7ff71c0a4000)`,
}
for _, tc := range testCases {
t.Run(tc.file, func(t *testing.T) {
stdout := new(strings.Builder)
stdout.WriteString(tc.out)
if got, err := ldd.Parse(stdout); err != nil {
if got, err := ldd.Parse([]byte(tc.out)); err != nil {
t.Errorf("Parse() error = %v", err)
} else if !reflect.DeepEqual(got, tc.want) {
t.Errorf("Parse() got = %#v, want %#v", got, tc.want)