mirror of
https://github.com/gravitational/teleport.git
synced 2026-10-11 22:49:54 +00:00
support disk events on Linux kernel 7.0+ by conditionally hooking do_file_open (#67650)
* support disk events on Linux kernel 7.0+ by conditionally hooking do_file_open * default to do_file_open
This commit is contained in:
@@ -114,12 +114,12 @@ int BPF_PROG(security_file_open, struct file *f)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// do_filp_open is called for all file open syscalls, but we aren't
|
// do_file_open is called for all file open syscalls, but we aren't
|
||||||
// able to get a resolved path here. If opening failed early,
|
// able to get a resolved path here. If opening failed early,
|
||||||
// security_file_open will not be called so we fall back to using the
|
// security_file_open will not be called so we fall back to using the
|
||||||
// unresolved path in the emitted event.
|
// unresolved path in the emitted event.
|
||||||
SEC("fexit/do_filp_open")
|
SEC("fexit/do_file_open")
|
||||||
int BPF_PROG(do_filp_open_exit, int dfd, struct filename *pathname, const struct open_flags *op, struct file *ret)
|
int BPF_PROG(do_file_open_exit, int dfd, struct filename *pathname, const struct open_flags *op, struct file *ret)
|
||||||
{
|
{
|
||||||
struct task_struct *task = bpf_get_current_task_btf();
|
struct task_struct *task = bpf_get_current_task_btf();
|
||||||
u32 session_id = task->sessionid;
|
u32 session_id = task->sessionid;
|
||||||
|
|||||||
+50
-3
@@ -22,10 +22,12 @@ package bpf
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/cilium/ebpf"
|
"github.com/cilium/ebpf"
|
||||||
|
"github.com/cilium/ebpf/btf"
|
||||||
"github.com/cilium/ebpf/link"
|
"github.com/cilium/ebpf/link"
|
||||||
"github.com/cilium/ebpf/ringbuf"
|
"github.com/cilium/ebpf/ringbuf"
|
||||||
"github.com/cilium/ebpf/rlimit"
|
"github.com/cilium/ebpf/rlimit"
|
||||||
@@ -36,6 +38,11 @@ import (
|
|||||||
"github.com/gravitational/teleport/lib/observability/metrics"
|
"github.com/gravitational/teleport/lib/observability/metrics"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
doFilpOpenName = "do_filp_open"
|
||||||
|
doFileOpenName = "do_file_open"
|
||||||
|
)
|
||||||
|
|
||||||
var lostDiskEvents = prometheus.NewCounter(
|
var lostDiskEvents = prometheus.NewCounter(
|
||||||
prometheus.CounterOpts{
|
prometheus.CounterOpts{
|
||||||
Name: teleport.MetricLostDiskEvents,
|
Name: teleport.MetricLostDiskEvents,
|
||||||
@@ -71,9 +78,28 @@ func startOpen(bufferSize int) (*open, error) {
|
|||||||
return nil, trace.Wrap(err)
|
return nil, trace.Wrap(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The disk eBPF program hooks do_file_open by default, which was
|
||||||
|
// renamed from do_filp_open in 7.0. Check if do_file_open is available
|
||||||
|
// and use do_filp_open otherwise; don't rely on the kernel version.
|
||||||
|
attachTarget, err := findOpenAttachTarget()
|
||||||
|
if err != nil {
|
||||||
|
return nil, trace.Wrap(err)
|
||||||
|
}
|
||||||
|
|
||||||
var objs diskObjects
|
var objs diskObjects
|
||||||
if err := loadDiskObjects(&objs, nil); err != nil {
|
spec, err := loadDisk()
|
||||||
return nil, trace.Wrap(err, "loading disk objects: %v", err)
|
if err != nil {
|
||||||
|
return nil, trace.Wrap(err, "reading disk objects")
|
||||||
|
}
|
||||||
|
|
||||||
|
p, ok := spec.Programs["do_file_open_exit"]
|
||||||
|
if !ok {
|
||||||
|
return nil, trace.NotFound("do_file_open_exit not found in disk objects")
|
||||||
|
}
|
||||||
|
p.AttachTo = attachTarget
|
||||||
|
|
||||||
|
if err := spec.LoadAndAssign(&objs, nil); err != nil {
|
||||||
|
return nil, trace.Wrap(err, "loading disk objects")
|
||||||
}
|
}
|
||||||
|
|
||||||
lostCtr, err := NewCounter(objs.LostCounter, objs.LostDoorbell, lostDiskEvents)
|
lostCtr, err := NewCounter(objs.LostCounter, objs.LostDoorbell, lostDiskEvents)
|
||||||
@@ -91,7 +117,7 @@ func startOpen(bufferSize int) (*open, error) {
|
|||||||
attachType: ebpf.AttachTraceFEntry,
|
attachType: ebpf.AttachTraceFEntry,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prog: objs.DoFilpOpenExit,
|
prog: objs.DoFileOpenExit,
|
||||||
attachType: ebpf.AttachTraceFExit,
|
attachType: ebpf.AttachTraceFExit,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -124,6 +150,27 @@ func startOpen(bufferSize int) (*open, error) {
|
|||||||
return o, nil
|
return o, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func findOpenAttachTarget() (string, error) {
|
||||||
|
kspec, err := btf.LoadKernelSpec()
|
||||||
|
if err != nil {
|
||||||
|
return "", trace.Wrap(err, "loading kernel BTF spec")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, target := range []string{doFileOpenName, doFilpOpenName} {
|
||||||
|
var fn *btf.Func
|
||||||
|
if err := kspec.TypeByName(target, &fn); err != nil {
|
||||||
|
if errors.Is(err, btf.ErrNotFound) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return "", trace.Wrap(err, "finding %s", target)
|
||||||
|
}
|
||||||
|
|
||||||
|
return target, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", trace.NotFound("do_file_open and do_filp_open not found in kernel BTF spec")
|
||||||
|
}
|
||||||
|
|
||||||
func (o *open) startSession(auditSessionID uint32) error {
|
func (o *open) startSession(auditSessionID uint32) error {
|
||||||
o.mtx.Lock()
|
o.mtx.Lock()
|
||||||
defer o.mtx.Unlock()
|
defer o.mtx.Unlock()
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ type diskSpecs struct {
|
|||||||
//
|
//
|
||||||
// It can be passed ebpf.CollectionSpec.Assign.
|
// It can be passed ebpf.CollectionSpec.Assign.
|
||||||
type diskProgramSpecs struct {
|
type diskProgramSpecs struct {
|
||||||
DoFilpOpenExit *ebpf.ProgramSpec `ebpf:"do_filp_open_exit"`
|
DoFileOpenExit *ebpf.ProgramSpec `ebpf:"do_file_open_exit"`
|
||||||
SecurityFileOpen *ebpf.ProgramSpec `ebpf:"security_file_open"`
|
SecurityFileOpen *ebpf.ProgramSpec `ebpf:"security_file_open"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,13 +137,13 @@ type diskVariables struct {
|
|||||||
//
|
//
|
||||||
// It can be passed to loadDiskObjects or ebpf.CollectionSpec.LoadAndAssign.
|
// It can be passed to loadDiskObjects or ebpf.CollectionSpec.LoadAndAssign.
|
||||||
type diskPrograms struct {
|
type diskPrograms struct {
|
||||||
DoFilpOpenExit *ebpf.Program `ebpf:"do_filp_open_exit"`
|
DoFileOpenExit *ebpf.Program `ebpf:"do_file_open_exit"`
|
||||||
SecurityFileOpen *ebpf.Program `ebpf:"security_file_open"`
|
SecurityFileOpen *ebpf.Program `ebpf:"security_file_open"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *diskPrograms) Close() error {
|
func (p *diskPrograms) Close() error {
|
||||||
return _DiskClose(
|
return _DiskClose(
|
||||||
p.DoFilpOpenExit,
|
p.DoFileOpenExit,
|
||||||
p.SecurityFileOpen,
|
p.SecurityFileOpen,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
@@ -67,7 +67,7 @@ type diskSpecs struct {
|
|||||||
//
|
//
|
||||||
// It can be passed ebpf.CollectionSpec.Assign.
|
// It can be passed ebpf.CollectionSpec.Assign.
|
||||||
type diskProgramSpecs struct {
|
type diskProgramSpecs struct {
|
||||||
DoFilpOpenExit *ebpf.ProgramSpec `ebpf:"do_filp_open_exit"`
|
DoFileOpenExit *ebpf.ProgramSpec `ebpf:"do_file_open_exit"`
|
||||||
SecurityFileOpen *ebpf.ProgramSpec `ebpf:"security_file_open"`
|
SecurityFileOpen *ebpf.ProgramSpec `ebpf:"security_file_open"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,13 +137,13 @@ type diskVariables struct {
|
|||||||
//
|
//
|
||||||
// It can be passed to loadDiskObjects or ebpf.CollectionSpec.LoadAndAssign.
|
// It can be passed to loadDiskObjects or ebpf.CollectionSpec.LoadAndAssign.
|
||||||
type diskPrograms struct {
|
type diskPrograms struct {
|
||||||
DoFilpOpenExit *ebpf.Program `ebpf:"do_filp_open_exit"`
|
DoFileOpenExit *ebpf.Program `ebpf:"do_file_open_exit"`
|
||||||
SecurityFileOpen *ebpf.Program `ebpf:"security_file_open"`
|
SecurityFileOpen *ebpf.Program `ebpf:"security_file_open"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *diskPrograms) Close() error {
|
func (p *diskPrograms) Close() error {
|
||||||
return _DiskClose(
|
return _DiskClose(
|
||||||
p.DoFilpOpenExit,
|
p.DoFileOpenExit,
|
||||||
p.SecurityFileOpen,
|
p.SecurityFileOpen,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
+1
-2
@@ -1343,7 +1343,6 @@ func runCommand(t *testing.T, srv Server, bpfSrv bpf.BPF, command string, expect
|
|||||||
scx.execRequest.SetCommand(command)
|
scx.execRequest.SetCommand(command)
|
||||||
|
|
||||||
clientChan, serverChan := newMockSSHChannel(t)
|
clientChan, serverChan := newMockSSHChannel(t)
|
||||||
clientChan.Drain()
|
|
||||||
|
|
||||||
t.Logf("running %q", command)
|
t.Logf("running %q", command)
|
||||||
|
|
||||||
@@ -1399,7 +1398,7 @@ func runCommand(t *testing.T, srv Server, bpfSrv bpf.BPF, command string, expect
|
|||||||
|
|
||||||
stdout := make([]byte, 1024)
|
stdout := make([]byte, 1024)
|
||||||
for {
|
for {
|
||||||
_, err := serverChan.Read(stdout)
|
_, err := clientChan.Read(stdout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, io.EOF) {
|
if errors.Is(err, io.EOF) {
|
||||||
return
|
return
|
||||||
|
|||||||
Reference in New Issue
Block a user