aboutsummaryrefslogtreecommitdiffhomepage
path: root/ldd
diff options
context:
space:
mode:
authorOphestra Umiker <cat@ophivana.moe>2024-10-09 20:39:27 +0900
committerOphestra Umiker <cat@ophivana.moe>2024-10-09 20:39:27 +0900
commit6232291caebc2dc1365cdb422ed16c09c06b3f28 (patch)
tree80dbff46d90453ca9082963c66043d95c23eb9b8 /ldd
parentb99ed943865cd3e8b3ab0cbcb8e04720b158799c (diff)
ldd: implement strict ldd output parser
Fortify needs to internally resolve helper program sandbox config. They are considered trusted and runs under the privileged UID so ldd output is used to determine libraries they need inside the sandbox environment. Signed-off-by: Ophestra Umiker <cat@ophivana.moe>
Diffstat (limited to 'ldd')
-rw-r--r--ldd/error.go11
-rw-r--r--ldd/ldd.go84
2 files changed, 95 insertions, 0 deletions
diff --git a/ldd/error.go b/ldd/error.go
new file mode 100644
index 00000000..51aef948
--- /dev/null
+++ b/ldd/error.go
@@ -0,0 +1,11 @@
+package ldd
+
+import "fmt"
+
+type EntryUnexpectedSegmentsError struct {
+ Entry string
+}
+
+func (e *EntryUnexpectedSegmentsError) Error() string {
+ return fmt.Sprintf("unexpected segments in entry %q", e.Entry)
+}
diff --git a/ldd/ldd.go b/ldd/ldd.go
new file mode 100644
index 00000000..989aeca5
--- /dev/null
+++ b/ldd/ldd.go
@@ -0,0 +1,84 @@
+package ldd
+
+import (
+ "errors"
+ "fmt"
+ "math"
+ "os"
+ "os/exec"
+ "path"
+ "strconv"
+ "strings"
+)
+
+var (
+ ErrUnexpectedSeparator = errors.New("unexpected separator")
+ ErrPathNotAbsolute = errors.New("path not absolute")
+ ErrBadLocationFormat = errors.New("bad location format")
+)
+
+type Entry struct {
+ Name string `json:"name,omitempty"`
+ Path string `json:"path,omitempty"`
+ Location uint64 `json:"location"`
+}
+
+func Exec(p string) ([]*Entry, error) {
+ t := exec.Command("ldd", p)
+ t.Stdout = new(strings.Builder)
+ t.Stderr = os.Stderr
+
+ if err := t.Run(); err != nil {
+ return nil, err
+ }
+
+ out := t.Stdout.(fmt.Stringer).String()
+ payload := strings.Split(out, "\n")
+
+ result := make([]*Entry, len(payload))
+
+ for i, ent := range payload {
+ if len(ent) == 0 {
+ continue
+ }
+
+ segment := strings.SplitN(ent, " ", 5)
+
+ var iL int
+
+ switch len(segment) {
+ case 2: // /lib/ld-musl-x86_64.so.1 (0x7f04d14ef000)
+ iL = 1
+ result[i] = &Entry{Name: segment[0]}
+ case 4: // libc.musl-x86_64.so.1 => /lib/ld-musl-x86_64.so.1 (0x7f04d14ef000)
+ iL = 3
+ if segment[1] != "=>" {
+ return nil, ErrUnexpectedSeparator
+ }
+ if !path.IsAbs(segment[2]) {
+ return nil, ErrPathNotAbsolute
+ }
+ result[i] = &Entry{
+ Name: segment[0],
+ Path: segment[2],
+ }
+ default:
+ return nil, &EntryUnexpectedSegmentsError{ent}
+ }
+
+ if loc, err := parseLocation(segment[iL]); err != nil {
+ return nil, err
+ } else {
+ result[i].Location = loc
+ }
+ }
+
+ return result, nil
+}
+
+func parseLocation(s string) (uint64, error) {
+ if len(s) < 4 || s[len(s)-1] != ')' || s[:3] != "(0x" {
+ return math.MaxUint64, ErrBadLocationFormat
+ }
+ return strconv.ParseUint(s[3:len(s)-1], 16, 64)
+}