mirror of
https://github.com/safedep/pmg.git
synced 2026-08-03 07:24:09 +02:00
visibility setup with ebpf
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
// Code generated by bpf2go; DO NOT EDIT.
|
||||
//go:build mips || mips64 || ppc64 || s390x
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"io"
|
||||
"structs"
|
||||
|
||||
"github.com/cilium/ebpf"
|
||||
)
|
||||
|
||||
type bpfEvent struct {
|
||||
_ structs.HostLayout
|
||||
Pid uint32
|
||||
Uid uint32
|
||||
Daddr uint32
|
||||
Dport uint16
|
||||
Comm [16]uint8
|
||||
_ [2]byte
|
||||
}
|
||||
|
||||
// Names of all BPF objects in the ELF.
|
||||
//
|
||||
// Used for safe lookups in a Collection or CollectionSpec.
|
||||
const (
|
||||
bpfMapEvents = "events"
|
||||
bpfProgConnect4 = "connect4"
|
||||
bpfVarUnusedEvent = "unused_event"
|
||||
)
|
||||
|
||||
// loadBpf returns the embedded CollectionSpec for bpf.
|
||||
func loadBpf() (*ebpf.CollectionSpec, error) {
|
||||
reader := bytes.NewReader(_BpfBytes)
|
||||
spec, err := ebpf.LoadCollectionSpecFromReader(reader)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't load bpf: %w", err)
|
||||
}
|
||||
|
||||
return spec, err
|
||||
}
|
||||
|
||||
// loadBpfObjects loads bpf and converts it into a struct.
|
||||
//
|
||||
// The following types are suitable as obj argument:
|
||||
//
|
||||
// *bpfObjects
|
||||
// *bpfPrograms
|
||||
// *bpfMaps
|
||||
//
|
||||
// See ebpf.CollectionSpec.LoadAndAssign documentation for details.
|
||||
func loadBpfObjects(obj any, opts *ebpf.CollectionOptions) error {
|
||||
spec, err := loadBpf()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return spec.LoadAndAssign(obj, opts)
|
||||
}
|
||||
|
||||
// bpfSpecs contains maps and programs before they are loaded into the kernel.
|
||||
//
|
||||
// It can be passed ebpf.CollectionSpec.Assign.
|
||||
type bpfSpecs struct {
|
||||
bpfProgramSpecs
|
||||
bpfMapSpecs
|
||||
bpfVariableSpecs
|
||||
}
|
||||
|
||||
// bpfProgramSpecs contains programs before they are loaded into the kernel.
|
||||
//
|
||||
// It can be passed ebpf.CollectionSpec.Assign.
|
||||
type bpfProgramSpecs struct {
|
||||
Connect4 *ebpf.ProgramSpec `ebpf:"connect4"`
|
||||
}
|
||||
|
||||
// bpfMapSpecs contains maps before they are loaded into the kernel.
|
||||
//
|
||||
// It can be passed ebpf.CollectionSpec.Assign.
|
||||
type bpfMapSpecs struct {
|
||||
Events *ebpf.MapSpec `ebpf:"events"`
|
||||
}
|
||||
|
||||
// bpfVariableSpecs contains global variables before they are loaded into the kernel.
|
||||
//
|
||||
// It can be passed ebpf.CollectionSpec.Assign.
|
||||
type bpfVariableSpecs struct {
|
||||
UnusedEvent *ebpf.VariableSpec `ebpf:"unused_event"`
|
||||
}
|
||||
|
||||
// bpfObjects contains all objects after they have been loaded into the kernel.
|
||||
//
|
||||
// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign.
|
||||
type bpfObjects struct {
|
||||
bpfPrograms
|
||||
bpfMaps
|
||||
bpfVariables
|
||||
}
|
||||
|
||||
func (o *bpfObjects) Close() error {
|
||||
return _BpfClose(
|
||||
&o.bpfPrograms,
|
||||
&o.bpfMaps,
|
||||
)
|
||||
}
|
||||
|
||||
// bpfMaps contains all maps after they have been loaded into the kernel.
|
||||
//
|
||||
// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign.
|
||||
type bpfMaps struct {
|
||||
Events *ebpf.Map `ebpf:"events"`
|
||||
}
|
||||
|
||||
func (m *bpfMaps) Close() error {
|
||||
return _BpfClose(
|
||||
m.Events,
|
||||
)
|
||||
}
|
||||
|
||||
// bpfVariables contains all global variables after they have been loaded into the kernel.
|
||||
//
|
||||
// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign.
|
||||
type bpfVariables struct {
|
||||
UnusedEvent *ebpf.Variable `ebpf:"unused_event"`
|
||||
}
|
||||
|
||||
// bpfPrograms contains all programs after they have been loaded into the kernel.
|
||||
//
|
||||
// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign.
|
||||
type bpfPrograms struct {
|
||||
Connect4 *ebpf.Program `ebpf:"connect4"`
|
||||
}
|
||||
|
||||
func (p *bpfPrograms) Close() error {
|
||||
return _BpfClose(
|
||||
p.Connect4,
|
||||
)
|
||||
}
|
||||
|
||||
func _BpfClose(closers ...io.Closer) error {
|
||||
for _, closer := range closers {
|
||||
if err := closer.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Do not access this directly.
|
||||
//
|
||||
//go:embed bpf_bpfeb.o
|
||||
var _BpfBytes []byte
|
||||
Binary file not shown.
@@ -0,0 +1,155 @@
|
||||
// Code generated by bpf2go; DO NOT EDIT.
|
||||
//go:build 386 || amd64 || arm || arm64 || loong64 || mips64le || mipsle || ppc64le || riscv64 || wasm
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"io"
|
||||
"structs"
|
||||
|
||||
"github.com/cilium/ebpf"
|
||||
)
|
||||
|
||||
type bpfEvent struct {
|
||||
_ structs.HostLayout
|
||||
Pid uint32
|
||||
Uid uint32
|
||||
Daddr uint32
|
||||
Dport uint16
|
||||
Comm [16]uint8
|
||||
_ [2]byte
|
||||
}
|
||||
|
||||
// Names of all BPF objects in the ELF.
|
||||
//
|
||||
// Used for safe lookups in a Collection or CollectionSpec.
|
||||
const (
|
||||
bpfMapEvents = "events"
|
||||
bpfProgConnect4 = "connect4"
|
||||
bpfVarUnusedEvent = "unused_event"
|
||||
)
|
||||
|
||||
// loadBpf returns the embedded CollectionSpec for bpf.
|
||||
func loadBpf() (*ebpf.CollectionSpec, error) {
|
||||
reader := bytes.NewReader(_BpfBytes)
|
||||
spec, err := ebpf.LoadCollectionSpecFromReader(reader)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't load bpf: %w", err)
|
||||
}
|
||||
|
||||
return spec, err
|
||||
}
|
||||
|
||||
// loadBpfObjects loads bpf and converts it into a struct.
|
||||
//
|
||||
// The following types are suitable as obj argument:
|
||||
//
|
||||
// *bpfObjects
|
||||
// *bpfPrograms
|
||||
// *bpfMaps
|
||||
//
|
||||
// See ebpf.CollectionSpec.LoadAndAssign documentation for details.
|
||||
func loadBpfObjects(obj any, opts *ebpf.CollectionOptions) error {
|
||||
spec, err := loadBpf()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return spec.LoadAndAssign(obj, opts)
|
||||
}
|
||||
|
||||
// bpfSpecs contains maps and programs before they are loaded into the kernel.
|
||||
//
|
||||
// It can be passed ebpf.CollectionSpec.Assign.
|
||||
type bpfSpecs struct {
|
||||
bpfProgramSpecs
|
||||
bpfMapSpecs
|
||||
bpfVariableSpecs
|
||||
}
|
||||
|
||||
// bpfProgramSpecs contains programs before they are loaded into the kernel.
|
||||
//
|
||||
// It can be passed ebpf.CollectionSpec.Assign.
|
||||
type bpfProgramSpecs struct {
|
||||
Connect4 *ebpf.ProgramSpec `ebpf:"connect4"`
|
||||
}
|
||||
|
||||
// bpfMapSpecs contains maps before they are loaded into the kernel.
|
||||
//
|
||||
// It can be passed ebpf.CollectionSpec.Assign.
|
||||
type bpfMapSpecs struct {
|
||||
Events *ebpf.MapSpec `ebpf:"events"`
|
||||
}
|
||||
|
||||
// bpfVariableSpecs contains global variables before they are loaded into the kernel.
|
||||
//
|
||||
// It can be passed ebpf.CollectionSpec.Assign.
|
||||
type bpfVariableSpecs struct {
|
||||
UnusedEvent *ebpf.VariableSpec `ebpf:"unused_event"`
|
||||
}
|
||||
|
||||
// bpfObjects contains all objects after they have been loaded into the kernel.
|
||||
//
|
||||
// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign.
|
||||
type bpfObjects struct {
|
||||
bpfPrograms
|
||||
bpfMaps
|
||||
bpfVariables
|
||||
}
|
||||
|
||||
func (o *bpfObjects) Close() error {
|
||||
return _BpfClose(
|
||||
&o.bpfPrograms,
|
||||
&o.bpfMaps,
|
||||
)
|
||||
}
|
||||
|
||||
// bpfMaps contains all maps after they have been loaded into the kernel.
|
||||
//
|
||||
// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign.
|
||||
type bpfMaps struct {
|
||||
Events *ebpf.Map `ebpf:"events"`
|
||||
}
|
||||
|
||||
func (m *bpfMaps) Close() error {
|
||||
return _BpfClose(
|
||||
m.Events,
|
||||
)
|
||||
}
|
||||
|
||||
// bpfVariables contains all global variables after they have been loaded into the kernel.
|
||||
//
|
||||
// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign.
|
||||
type bpfVariables struct {
|
||||
UnusedEvent *ebpf.Variable `ebpf:"unused_event"`
|
||||
}
|
||||
|
||||
// bpfPrograms contains all programs after they have been loaded into the kernel.
|
||||
//
|
||||
// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign.
|
||||
type bpfPrograms struct {
|
||||
Connect4 *ebpf.Program `ebpf:"connect4"`
|
||||
}
|
||||
|
||||
func (p *bpfPrograms) Close() error {
|
||||
return _BpfClose(
|
||||
p.Connect4,
|
||||
)
|
||||
}
|
||||
|
||||
func _BpfClose(closers ...io.Closer) error {
|
||||
for _, closer := range closers {
|
||||
if err := closer.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Do not access this directly.
|
||||
//
|
||||
//go:embed bpf_bpfel.o
|
||||
var _BpfBytes []byte
|
||||
Binary file not shown.
@@ -0,0 +1,37 @@
|
||||
//go:build ignore
|
||||
#include <linux/bpf.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_endian.h>
|
||||
|
||||
char __license[] SEC("license") = "Dual MIT/GPL";
|
||||
|
||||
struct event {
|
||||
__u32 pid;
|
||||
__u32 uid;
|
||||
__u32 daddr;
|
||||
__u16 dport;
|
||||
__u8 comm[16]; // command
|
||||
};
|
||||
|
||||
struct event *unused_event __attribute__((unused));
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_RINGBUF);
|
||||
__uint(max_entries, 1 << 24);
|
||||
} events SEC(".maps");
|
||||
|
||||
SEC("cgroup/connect4")
|
||||
int connect4(struct bpf_sock_addr *ctx) {
|
||||
struct event *e = bpf_ringbuf_reserve(&events, sizeof(*e), 0);
|
||||
if (!e)
|
||||
return 1;
|
||||
|
||||
e->pid = bpf_get_current_pid_tgid() >> 32;
|
||||
e->uid = bpf_get_current_uid_gid();
|
||||
e->daddr = ctx->user_ip4;
|
||||
e->dport = bpf_ntohs(ctx->user_port);
|
||||
bpf_get_current_comm(&e->comm, sizeof(e->comm));
|
||||
|
||||
bpf_ringbuf_submit(e, 0);
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
module ebpf-poc
|
||||
|
||||
go 1.25.0
|
||||
|
||||
require (
|
||||
github.com/cilium/ebpf v0.22.0 // indirect
|
||||
golang.org/x/sys v0.43.0 // indirect
|
||||
)
|
||||
@@ -0,0 +1,4 @@
|
||||
github.com/cilium/ebpf v0.22.0 h1:v2ktp0roffpMOj2MMf3idtCQZOsAoC4BJbAJN+ke2bY=
|
||||
github.com/cilium/ebpf v0.22.0/go.mod h1:CDzZbe2hC5JjlDC+CY3KFCzlYwN4gbxppYM+Z10bQt4=
|
||||
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
|
||||
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
@@ -0,0 +1,98 @@
|
||||
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -type event bpf connect.c -- -I/usr/include/aarch64-linux-gnu
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"github.com/cilium/ebpf"
|
||||
"github.com/cilium/ebpf/link"
|
||||
"github.com/cilium/ebpf/ringbuf"
|
||||
"github.com/cilium/ebpf/rlimit"
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := rlimit.RemoveMemlock()
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to remove mem lock: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
var objs bpfObjects
|
||||
err = loadBpfObjects(&objs, nil)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to load bpf objects: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
defer objs.Close()
|
||||
|
||||
rootCgroup := "/sys/fs/cgroup"
|
||||
|
||||
l, err := link.AttachCgroup(link.CgroupOptions{
|
||||
Path: rootCgroup,
|
||||
Attach: ebpf.AttachCGroupInet4Connect,
|
||||
Program: objs.Connect4,
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to attach cgroup: %v\n", err)
|
||||
return
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
rd, err := ringbuf.NewReader(objs.Events)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to create ringbuf reader: %v\n", err)
|
||||
return
|
||||
}
|
||||
defer rd.Close()
|
||||
|
||||
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||||
defer stop() // Cleans up resources allocated by the signal package
|
||||
|
||||
fmt.Println("Application started. Press Ctrl+C to exit.")
|
||||
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
fmt.Println("\nSignal received, detaching and cleaning up...")
|
||||
rd.Close()
|
||||
}()
|
||||
|
||||
var e bpfEvent
|
||||
for {
|
||||
rec, err := rd.Read()
|
||||
if err != nil {
|
||||
if errors.Is(err, ringbuf.ErrClosed) {
|
||||
return
|
||||
}
|
||||
fmt.Printf("failed to read raw event: %v\n", err)
|
||||
continue
|
||||
}
|
||||
|
||||
err = binary.Read(bytes.NewReader(rec.RawSample), binary.LittleEndian, &e)
|
||||
if err != nil {
|
||||
fmt.Printf("failed to read event: %v\n", err)
|
||||
continue
|
||||
}
|
||||
|
||||
ip := make(net.IP, 4)
|
||||
binary.LittleEndian.PutUint32(ip, e.Daddr)
|
||||
|
||||
name := e.Comm[:]
|
||||
if i := bytes.IndexByte(name, 0); i != -1 {
|
||||
name = name[:i] // keep bytes before the first NUL
|
||||
}
|
||||
comm := string(name)
|
||||
|
||||
fmt.Println()
|
||||
fmt.Printf("PID: %v\nUID: %v\ndAddr: %v\ndPort: %v\nCommand: %v\n", e.Pid, e.Uid, ip, e.Dport, comm)
|
||||
}
|
||||
}
|
||||
Executable
BIN
Binary file not shown.
Reference in New Issue
Block a user