Skip to content

Commit

Permalink
feat(lib): use memfd on linux instead of dumping libddwaf.so in /tmp
Browse files Browse the repository at this point in the history
Signed-off-by: Eliott Bouhana <[email protected]>
  • Loading branch information
eliottness committed Sep 2, 2024
1 parent 48f7206 commit c840ba3
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 76 deletions.
16 changes: 8 additions & 8 deletions internal/bindings/waf_dl.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,22 +40,22 @@ type wafSymbols struct {
run uintptr
}

// newWafDl loads the libddwaf shared library and resolves all tge relevant symbols.
// NewWafDl loads the libddwaf shared library and resolves all tge relevant symbols.
// The caller is responsible for calling wafDl.Close on the returned object once they
// are done with it so that associated resources can be released.
func NewWafDl() (dl *WafDl, err error) {
file, err := lib.DumpEmbeddedWAF()
file, closer, err := lib.DumpEmbeddedWAF()
if err != nil {
return
}
defer func() {
if rmErr := os.Remove(file); rmErr != nil {
err = errors.Join(err, fmt.Errorf("error removing %s: %w", file, rmErr))
if rmErr := closer(); rmErr != nil {
err = errors.Join(err, fmt.Errorf("error removing %s: %w", file.Name(), rmErr))
}
}()

var handle uintptr
if handle, err = purego.Dlopen(file, purego.RTLD_GLOBAL|purego.RTLD_NOW); err != nil {
if handle, err = purego.Dlopen(file.Name(), purego.RTLD_GLOBAL|purego.RTLD_NOW); err != nil {
return
}

Expand Down Expand Up @@ -97,12 +97,12 @@ func (waf *WafDl) Close() error {
return purego.Dlclose(waf.handle)
}

// wafGetVersion returned string is a static string so we do not need to free it
// WafGetVersion returned string is a static string so we do not need to free it
func (waf *WafDl) WafGetVersion() string {
return unsafe.Gostring(unsafe.Cast[byte](waf.syscall(waf.getVersion)))
}

// wafInit initializes a new WAF with the provided ruleset, configuration and info objects. A
// WafInit initializes a new WAF with the provided ruleset, configuration and info objects. A
// cgoRefPool ensures that the provided input values are not moved or garbage collected by the Go
// runtime during the WAF call.
func (waf *WafDl) WafInit(ruleset *WafObject, config *WafConfig, info *WafObject) WafHandle {
Expand All @@ -125,7 +125,7 @@ func (waf *WafDl) WafDestroy(handle WafHandle) {
unsafe.KeepAlive(handle)
}

// wafKnownAddresses returns static strings so we do not need to free them
// WafKnownAddresses returns static strings so we do not need to free them
func (waf *WafDl) WafKnownAddresses(handle WafHandle) []string {
var nbAddresses uint32

Expand Down
13 changes: 6 additions & 7 deletions internal/bindings/waf_dl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"debug/elf"
"debug/macho"
"fmt"
"os"
"runtime"
"testing"

Expand All @@ -33,14 +32,14 @@ func TestVerifyHeader(t *testing.T) {
// testVerifyELFHeader is here to ease the debug cases that will likely need
// to dive in the linker to debug because the error handling is very poor
func testVerifyELFHeader(t *testing.T) {
file, err := lib.DumpEmbeddedWAF()
file, closer, err := lib.DumpEmbeddedWAF()
require.NoError(t, err)

defer func() {
_ = os.Remove(file)
_ = closer()
}()

elfFile, err := elf.Open(file)
elfFile, err := elf.Open(file.Name())
require.NoError(t, err)

switch runtime.GOARCH {
Expand All @@ -60,14 +59,14 @@ func testVerifyELFHeader(t *testing.T) {
// testVerifyMachOHeader is here to ease the debug cases that will likely need
// to dive in the linker to debug because the error handling is very poor
func testVerifyMachOHeader(t *testing.T) {
file, err := lib.DumpEmbeddedWAF()
file, closer, err := lib.DumpEmbeddedWAF()
require.NoError(t, err)

defer func() {
_ = os.Remove(file)
_ = closer()
}()

machOFile, err := macho.Open(file)
machOFile, err := macho.Open(file.Name())
require.NoError(t, err)

switch runtime.GOARCH {
Expand Down
57 changes: 57 additions & 0 deletions internal/lib/dump_waf_darwin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2016-present Datadog, Inc.

//go:build darwin && (amd64 || arm64) && !go1.24 && !datadog.no_waf && (cgo || appsec)

package lib

import (
"bytes"
"compress/gzip"
"errors"
"fmt"
"os"

_ "embed"
)

//go:embed .version
var EmbeddedWAFVersion string

func DumpEmbeddedWAF() (file *os.File, closer func() error, err error) {
file, err := os.CreateTemp("", embedNamePattern)

Check failure on line 24 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-14 go1.21

no new variables on left side of :=

Check failure on line 24 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-14 go1.22 (DD_APPSEC_WAF_LOG_LEVEL=TRACE)

no new variables on left side of :=

Check failure on line 24 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-13 go1.22 (DD_APPSEC_WAF_LOG_LEVEL=TRACE)

no new variables on left side of :=

Check failure on line 24 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-12 go1.22 (DD_APPSEC_WAF_LOG_LEVEL=TRACE)

no new variables on left side of :=

Check failure on line 24 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-12 go1.21

no new variables on left side of :=

Check failure on line 24 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-13 go1.21

no new variables on left side of :=
if err != nil {
return nil, nil, fmt.Errorf("error creating temp file: %w", err)
}
path = file.Name()

Check failure on line 28 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-14 go1.21

undefined: path

Check failure on line 28 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-14 go1.22 (DD_APPSEC_WAF_LOG_LEVEL=TRACE)

undefined: path

Check failure on line 28 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-13 go1.22 (DD_APPSEC_WAF_LOG_LEVEL=TRACE)

undefined: path

Check failure on line 28 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-12 go1.22 (DD_APPSEC_WAF_LOG_LEVEL=TRACE)

undefined: path

Check failure on line 28 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-12 go1.21

undefined: path

Check failure on line 28 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-13 go1.21

undefined: path

defer func() {
if err != nil {
if closeErr := file.Close(); closeErr != nil {
err = errors.Join(err, fmt.Errorf("error closing file: %w", closeErr))
}
if rmErr := os.Remove(path); rmErr != nil {

Check failure on line 35 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-14 go1.21

undefined: path

Check failure on line 35 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-14 go1.22 (DD_APPSEC_WAF_LOG_LEVEL=TRACE)

undefined: path

Check failure on line 35 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-13 go1.22 (DD_APPSEC_WAF_LOG_LEVEL=TRACE)

undefined: path

Check failure on line 35 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-12 go1.22 (DD_APPSEC_WAF_LOG_LEVEL=TRACE)

undefined: path

Check failure on line 35 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-12 go1.21

undefined: path

Check failure on line 35 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-13 go1.21

undefined: path
err = errors.Join(err, fmt.Errorf("error removing file: %w", rmErr))
}
}
}()

gr, err := gzip.NewReader(bytes.NewReader(libddwaf))
if err != nil {
return nil, nil, fmt.Errorf("error creating gzip reader: %w", err)
}

if _, err := io.Copy(file, gr); err != nil {

Check failure on line 46 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-14 go1.21

undefined: io

Check failure on line 46 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-14 go1.22 (DD_APPSEC_WAF_LOG_LEVEL=TRACE)

undefined: io

Check failure on line 46 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-13 go1.22 (DD_APPSEC_WAF_LOG_LEVEL=TRACE)

undefined: io

Check failure on line 46 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-12 go1.22 (DD_APPSEC_WAF_LOG_LEVEL=TRACE)

undefined: io

Check failure on line 46 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-12 go1.21

undefined: io

Check failure on line 46 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-13 go1.21

undefined: io
return nil, nil, fmt.Errorf("error copying gzip content to file: %w", err)
}

if err := gr.Close(); err != nil {
return nil, nil, fmt.Errorf("error closing gzip reader: %w", err)
}

return file, func() {

Check failure on line 54 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-14 go1.21

cannot use func() {…} (value of type func()) as func() error value in return statement

Check failure on line 54 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-14 go1.22 (DD_APPSEC_WAF_LOG_LEVEL=TRACE)

cannot use func() {…} (value of type func()) as func() error value in return statement

Check failure on line 54 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-13 go1.22 (DD_APPSEC_WAF_LOG_LEVEL=TRACE)

cannot use func() {…} (value of type func()) as func() error value in return statement

Check failure on line 54 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-12 go1.22 (DD_APPSEC_WAF_LOG_LEVEL=TRACE)

cannot use func() {…} (value of type func()) as func() error value in return statement

Check failure on line 54 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-12 go1.21

cannot use func() {…} (value of type func()) as func() error value in return statement

Check failure on line 54 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-13 go1.21

cannot use func() {…} (value of type func()) as func() error value in return statement
return errors.Join(file.Close(), os.Remove(path))

Check failure on line 55 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-14 go1.21

too many return values

Check failure on line 55 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-14 go1.21

undefined: path

Check failure on line 55 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-14 go1.22 (DD_APPSEC_WAF_LOG_LEVEL=TRACE)

too many return values

Check failure on line 55 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-13 go1.22 (DD_APPSEC_WAF_LOG_LEVEL=TRACE)

too many return values

Check failure on line 55 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-14 go1.22 (DD_APPSEC_WAF_LOG_LEVEL=TRACE)

undefined: path

Check failure on line 55 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-13 go1.22 (DD_APPSEC_WAF_LOG_LEVEL=TRACE)

undefined: path

Check failure on line 55 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-12 go1.22 (DD_APPSEC_WAF_LOG_LEVEL=TRACE)

too many return values

Check failure on line 55 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-12 go1.22 (DD_APPSEC_WAF_LOG_LEVEL=TRACE)

undefined: path

Check failure on line 55 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-12 go1.21

too many return values

Check failure on line 55 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-12 go1.21

undefined: path

Check failure on line 55 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-13 go1.21

too many return values

Check failure on line 55 in internal/lib/dump_waf_darwin.go

View workflow job for this annotation

GitHub Actions / GitHub Runner / macos-13 go1.21

undefined: path
}, nil
}
59 changes: 59 additions & 0 deletions internal/lib/dump_waf_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2016-present Datadog, Inc.

//go:build linux && (amd64 || arm64) && !go1.24 && !datadog.no_waf && (cgo || appsec)

package lib

import (
"bytes"
"compress/gzip"
"errors"
"fmt"
"golang.org/x/sys/unix"
"io"
"os"

_ "embed"
)

//go:embed .version
var EmbeddedWAFVersion string

func DumpEmbeddedWAF() (file *os.File, closer func() error, err error) {

fd, err := unix.MemfdCreate("libddwaf", 0)
if err != nil {
return nil, nil, fmt.Errorf("error creating memfd: %w", err)
}

file = os.NewFile(uintptr(fd), fmt.Sprintf("/proc/self/fd/%d", fd))
if file == nil {
return nil, nil, errors.New("error creating file from fd")
}

defer func() {
if file != nil && err != nil {
if closeErr := file.Close(); closeErr != nil {
err = errors.Join(err, fmt.Errorf("error closing file: %w", closeErr))
}
}
}()

gr, err := gzip.NewReader(bytes.NewReader(libddwaf))
if err != nil {
return nil, nil, fmt.Errorf("error creating gzip reader: %w", err)
}

if _, err := io.Copy(file, gr); err != nil {
return nil, nil, fmt.Errorf("error copying gzip content to memfd: %w", err)
}

if err := gr.Close(); err != nil {
return nil, nil, fmt.Errorf("error closing gzip reader: %w", err)
}

return file, file.Close, nil
}
61 changes: 0 additions & 61 deletions internal/lib/lib.go

This file was deleted.

0 comments on commit c840ba3

Please sign in to comment.