ldd: run in native sandbox
Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
parent
f41fd94628
commit
4bb5d9780f
@ -140,7 +140,6 @@
|
|||||||
gcc
|
gcc
|
||||||
pkg-config
|
pkg-config
|
||||||
wayland-scanner
|
wayland-scanner
|
||||||
bubblewrap
|
|
||||||
]
|
]
|
||||||
++ (
|
++ (
|
||||||
with pkgs.pkgsStatic;
|
with pkgs.pkgsStatic;
|
||||||
|
@ -69,10 +69,7 @@ func TestContainer(t *testing.T) {
|
|||||||
container.Uid = 1000
|
container.Uid = 1000
|
||||||
container.Gid = 100
|
container.Gid = 100
|
||||||
container.Hostname = tc.host
|
container.Hostname = tc.host
|
||||||
container.CommandContext = func(ctx context.Context) *exec.Cmd {
|
container.CommandContext = commandContext
|
||||||
return exec.CommandContext(ctx, os.Args[0], "-test.v",
|
|
||||||
"-test.run=TestHelperInit", "--", "init")
|
|
||||||
}
|
|
||||||
container.Flags |= tc.flags
|
container.Flags |= tc.flags
|
||||||
container.Stdout, container.Stderr = os.Stdout, os.Stderr
|
container.Stdout, container.Stderr = os.Stdout, os.Stderr
|
||||||
container.Ops = tc.ops
|
container.Ops = tc.ops
|
||||||
@ -89,7 +86,11 @@ func TestContainer(t *testing.T) {
|
|||||||
Bind(os.Args[0], os.Args[0], 0)
|
Bind(os.Args[0], os.Args[0], 0)
|
||||||
// in case test has cgo enabled
|
// in case test has cgo enabled
|
||||||
var libPaths []string
|
var libPaths []string
|
||||||
if entries, err := ldd.Exec(ctx, os.Args[0]); err != nil {
|
if entries, err := ldd.ExecFilter(ctx,
|
||||||
|
commandContext,
|
||||||
|
func(v []byte) []byte {
|
||||||
|
return bytes.SplitN(v, []byte("TestHelperInit\n"), 2)[1]
|
||||||
|
}, os.Args[0]); err != nil {
|
||||||
log.Fatalf("ldd: %v", err)
|
log.Fatalf("ldd: %v", err)
|
||||||
} else {
|
} else {
|
||||||
libPathsM := make(map[string]struct{}, len(entries))
|
libPathsM := make(map[string]struct{}, len(entries))
|
||||||
@ -175,3 +176,8 @@ func TestHelperCheckContainer(t *testing.T) {
|
|||||||
t.Run("seccomp", func(t *testing.T) { check.MustAssertSeccomp() })
|
t.Run("seccomp", func(t *testing.T) { check.MustAssertSeccomp() })
|
||||||
t.Run("mntent", func(t *testing.T) { check.MustAssertMounts("", "/proc/mounts", "/proc/self/fd/0") })
|
t.Run("mntent", func(t *testing.T) { check.MustAssertMounts("", "/proc/mounts", "/proc/self/fd/0") })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func commandContext(ctx context.Context) *exec.Cmd {
|
||||||
|
return exec.CommandContext(ctx, os.Args[0], "-test.v",
|
||||||
|
"-test.run=TestHelperInit", "--", "init")
|
||||||
|
}
|
||||||
|
52
ldd/exec.go
52
ldd/exec.go
@ -7,8 +7,7 @@ import (
|
|||||||
"os/exec"
|
"os/exec"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/helper"
|
"git.gensokyo.uk/security/fortify/internal/sandbox"
|
||||||
"git.gensokyo.uk/security/fortify/helper/bwrap"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const lddTimeout = 2 * time.Second
|
const lddTimeout = 2 * time.Second
|
||||||
@ -18,34 +17,31 @@ var (
|
|||||||
msgStaticGlibc = []byte("not a dynamic executable")
|
msgStaticGlibc = []byte("not a dynamic executable")
|
||||||
)
|
)
|
||||||
|
|
||||||
func Exec(ctx context.Context, p string) ([]*Entry, error) {
|
func Exec(ctx context.Context, p string) ([]*Entry, error) { return ExecFilter(ctx, nil, nil, p) }
|
||||||
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 ExecFilter(ctx context.Context,
|
||||||
|
commandContext func(context.Context) *exec.Cmd,
|
||||||
|
f func([]byte) []byte,
|
||||||
|
p string) ([]*Entry, error) {
|
||||||
c, cancel := context.WithTimeout(ctx, lddTimeout)
|
c, cancel := context.WithTimeout(ctx, lddTimeout)
|
||||||
defer cancel()
|
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
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := h.Wait(); err != nil {
|
if err := container.Wait(); err != nil {
|
||||||
m := stderr.Bytes()
|
m := stderr.Bytes()
|
||||||
if bytes.Contains(m, append([]byte(p+": "), msgStatic...)) ||
|
if bytes.Contains(m, append([]byte(p+": "), msgStatic...)) ||
|
||||||
bytes.Contains(m, msgStaticGlibc) {
|
bytes.Contains(m, msgStaticGlibc) {
|
||||||
@ -56,5 +52,9 @@ func Exec(ctx context.Context, p string) ([]*Entry, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return Parse(stdout)
|
v := stdout.Bytes()
|
||||||
|
if f != nil {
|
||||||
|
v = f(v)
|
||||||
|
}
|
||||||
|
return Parse(v)
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
package ldd
|
package ldd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"math"
|
"math"
|
||||||
"path"
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -15,8 +14,8 @@ type Entry struct {
|
|||||||
Location uint64 `json:"location"`
|
Location uint64 `json:"location"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func Parse(stdout fmt.Stringer) ([]*Entry, error) {
|
func Parse(p []byte) ([]*Entry, error) {
|
||||||
payload := strings.Split(strings.TrimSpace(stdout.String()), "\n")
|
payload := strings.Split(strings.TrimSpace(string(p)), "\n")
|
||||||
result := make([]*Entry, len(payload))
|
result := make([]*Entry, len(payload))
|
||||||
|
|
||||||
for i, ent := range payload {
|
for i, ent := range payload {
|
||||||
|
@ -3,7 +3,6 @@ package ldd_test
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/ldd"
|
"git.gensokyo.uk/security/fortify/ldd"
|
||||||
@ -34,10 +33,7 @@ libzstd.so.1 => /usr/lib/libzstd.so.1 7ff71bfd2000
|
|||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
stdout := new(strings.Builder)
|
if _, err := ldd.Parse([]byte(tc.out)); !errors.Is(err, tc.wantErr) {
|
||||||
stdout.WriteString(tc.out)
|
|
||||||
|
|
||||||
if _, err := ldd.Parse(stdout); !errors.Is(err, tc.wantErr) {
|
|
||||||
t.Errorf("Parse() error = %v, wantErr %v", 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 {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.file, func(t *testing.T) {
|
t.Run(tc.file, func(t *testing.T) {
|
||||||
stdout := new(strings.Builder)
|
if got, err := ldd.Parse([]byte(tc.out)); err != nil {
|
||||||
stdout.WriteString(tc.out)
|
|
||||||
|
|
||||||
if got, err := ldd.Parse(stdout); err != nil {
|
|
||||||
t.Errorf("Parse() error = %v", err)
|
t.Errorf("Parse() error = %v", err)
|
||||||
} else if !reflect.DeepEqual(got, tc.want) {
|
} else if !reflect.DeepEqual(got, tc.want) {
|
||||||
t.Errorf("Parse() got = %#v, want %#v", got, tc.want)
|
t.Errorf("Parse() got = %#v, want %#v", got, tc.want)
|
||||||
|
@ -73,7 +73,6 @@ buildGoModule rec {
|
|||||||
pkg-config
|
pkg-config
|
||||||
wayland-scanner
|
wayland-scanner
|
||||||
makeBinaryWrapper
|
makeBinaryWrapper
|
||||||
bubblewrap
|
|
||||||
];
|
];
|
||||||
|
|
||||||
preBuild = ''
|
preBuild = ''
|
||||||
|
Loading…
Reference in New Issue
Block a user