Skip to content

Commit

Permalink
Add logic to detect TTYs in containers
Browse files Browse the repository at this point in the history
Opening TTYs is in most cases something that one might want to
investigate. There is now new logic in place, that hooks the `tty_open`
function of the `tty` device drivers and reports an event to userspace,
that is handled by a newly added signature called `tty_detected`. As of
right now we always alert on any `tty_open` events, but this might
change in the future.
  • Loading branch information
patrickpichler committed Mar 29, 2024
1 parent c97c511 commit d0e50c5
Show file tree
Hide file tree
Showing 21 changed files with 21,781 additions and 21,609 deletions.
15 changes: 10 additions & 5 deletions api/v1/runtime/common.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 3 additions & 4 deletions api/v1/runtime/common.proto
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ message DNS {
message DNSAnswers {
uint32 type = 1;
uint32 class = 2;
uint32 ttl= 3;
uint32 ttl = 3;
string name = 4;
bytes ip = 5;
string cname = 6;
Expand All @@ -72,7 +72,6 @@ message LogEvent {
string msg = 2;
}


message SignatureEvent {
SignatureMetadata metadata = 1;
SignatureFinding finding = 2;
Expand All @@ -81,12 +80,12 @@ message SignatureEvent {
enum SignatureEventID {
SIGNATURE_UNKNOWN = 0;
SIGNATURE_STDIO_VIA_SOCKET = 1;
SIGNATURE_TTY_DETECTED = 2;
}

message SignatureMetadata {
SignatureEventID id = 1;
string version = 2;
}

message SignatureFinding {
}
message SignatureFinding {}
1 change: 1 addition & 0 deletions charts/kvisor/values-local.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ agent:
container-stats-scrape-interval: 10s
pyroscope-addr: http://kvisord-pyroscope:4040
file-hash-enricher-enabled: true
signature-tty-detection-enabled: true

containerSecurityContext:
readOnlyRootFilesystem: false
Expand Down
2 changes: 1 addition & 1 deletion cmd/agent/daemon/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ func (a *App) Run(ctx context.Context) error {
}
defer ct.Close()

activeSignatures := signature.DefaultSignatures(log)
activeSignatures := signature.DefaultSignatures(log, a.cfg.SignatureEngineConfig.DefaultSignatureConfig)

signatureEngine := signature.NewEngine(activeSignatures, log, a.cfg.SignatureEngineConfig)

Expand Down
6 changes: 5 additions & 1 deletion cmd/agent/daemon/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ var (

mutedNamespaces = pflag.StringArray("mute-namespace", []string{"kube-system", "calico"}, "List of namespaces to ignore tracing events for. To mute multiple namespaces, provide this flag multiple times.")

fileHashEnrichedEnabled = pflag.Bool("file-hash-enricher-enabled", false, "Enables the file has event enricher for exec events")
fileHashEnrichedEnabled = pflag.Bool("file-hash-enricher-enabled", false, "Enables the file has event enricher for exec events")
ttyDetectionSignatureEnabled = pflag.Bool("signature-tty-detection-enabled", false, "Enables the tty detection signature")

castaiServerInsecure = pflag.Bool("castai-server-insecure", false, "Use insecure connection to castai grpc server. Used for e2e.")

Expand Down Expand Up @@ -104,6 +105,9 @@ func NewCommand(version string) *cobra.Command {
SignatureEngineConfig: signature.SignatureEngineConfig{
InputChanSize: *signatureEngineInputEventChanSize,
OutputChanSize: *signatureEngineOutputEventChanSize,
DefaultSignatureConfig: signature.DefaultSignatureConfig{
TTYDetectedSignatureEnabled: *ttyDetectionSignatureEnabled,
},
},
CastaiEnv: castaiClientCfg,
EnricherConfig: app.EnricherConfig{
Expand Down
1 change: 1 addition & 0 deletions pkg/ebpftracer/c/headers/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ enum event_id_e {
SOCK_SET_STATE,
MAX_EVENT_ID,
PROCESS_OOM_KILLED,
TTY_OPEN,
};

enum signal_event_id_e
Expand Down
1 change: 1 addition & 0 deletions pkg/ebpftracer/c/headers/vmlinux.h
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,7 @@ struct inode {
struct timespec64 __i_ctime;
loff_t i_size;
struct file_operations *i_fop;
dev_t i_rdev;
};

struct super_block {
Expand Down
124 changes: 77 additions & 47 deletions pkg/ebpftracer/c/tracee.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
#include <common/debug.h>
#include <common/stats.h>

#include "bpf/bpf_helpers.h"

char LICENSE[] SEC("license") = "GPL";

extern _Bool LINUX_HAS_SYSCALL_WRAPPER __kconfig;
Expand Down Expand Up @@ -4261,64 +4263,64 @@ int BPF_KPROBE(trace_load_elf_phdrs)
return 0;
}

//SEC("kprobe/security_file_permission")
//int BPF_KPROBE(trace_security_file_permission)
// SEC("kprobe/security_file_permission")
// int BPF_KPROBE(trace_security_file_permission)
//{
// struct file *file = (struct file *) PT_REGS_PARM1(ctx);
// if (file == NULL)
// return 0;
// struct inode *f_inode = get_inode_from_file(file);
// struct super_block *i_sb = get_super_block_from_inode(f_inode);
// unsigned long s_magic = get_s_magic_from_super_block(i_sb);
// struct file *file = (struct file *) PT_REGS_PARM1(ctx);
// if (file == NULL)
// return 0;
// struct inode *f_inode = get_inode_from_file(file);
// struct super_block *i_sb = get_super_block_from_inode(f_inode);
// unsigned long s_magic = get_s_magic_from_super_block(i_sb);
//
// // Only check procfs entries
// if (s_magic != PROC_SUPER_MAGIC) {
// return 0;
// }
// // Only check procfs entries
// if (s_magic != PROC_SUPER_MAGIC) {
// return 0;
// }
//
// program_data_t p = {};
// if (!init_program_data(&p, ctx))
// return 0;
// program_data_t p = {};
// if (!init_program_data(&p, ctx))
// return 0;
//
// if (!should_trace(&p))
// return 0;
// if (!should_trace(&p))
// return 0;
//
// if (!should_submit(HOOKED_PROC_FOPS, p.event))
// return 0;
// if (!should_submit(HOOKED_PROC_FOPS, p.event))
// return 0;
//
// struct file_operations *fops = (struct file_operations *) BPF_CORE_READ(f_inode, i_fop);
// if (fops == NULL)
// return 0;
// struct file_operations *fops = (struct file_operations *) BPF_CORE_READ(f_inode, i_fop);
// if (fops == NULL)
// return 0;
//
// unsigned long iterate_shared_addr = (unsigned long) BPF_CORE_READ(fops, iterate_shared);
// unsigned long iterate_addr = (unsigned long) BPF_CORE_READ(fops, iterate);
// if (iterate_addr == 0 && iterate_shared_addr == 0)
// return 0;
// unsigned long iterate_shared_addr = (unsigned long) BPF_CORE_READ(fops, iterate_shared);
// unsigned long iterate_addr = (unsigned long) BPF_CORE_READ(fops, iterate);
// if (iterate_addr == 0 && iterate_shared_addr == 0)
// return 0;
//
// // get text segment bounds
// void *stext_addr = get_stext_addr();
// if (unlikely(stext_addr == NULL))
// return 0;
// void *etext_addr = get_etext_addr();
// if (unlikely(etext_addr == NULL))
// return 0;
// // get text segment bounds
// void *stext_addr = get_stext_addr();
// if (unlikely(stext_addr == NULL))
// return 0;
// void *etext_addr = get_etext_addr();
// if (unlikely(etext_addr == NULL))
// return 0;
//
// // mark as 0 if in bounds
// if (iterate_shared_addr >= (u64) stext_addr && iterate_shared_addr < (u64) etext_addr)
// iterate_shared_addr = 0;
// if (iterate_addr >= (u64) stext_addr && iterate_addr < (u64) etext_addr)
// iterate_addr = 0;
// // mark as 0 if in bounds
// if (iterate_shared_addr >= (u64) stext_addr && iterate_shared_addr < (u64) etext_addr)
// iterate_shared_addr = 0;
// if (iterate_addr >= (u64) stext_addr && iterate_addr < (u64) etext_addr)
// iterate_addr = 0;
//
// // now check again, if both are in text bounds, return
// if (iterate_addr == 0 && iterate_shared_addr == 0)
// return 0;
// // now check again, if both are in text bounds, return
// if (iterate_addr == 0 && iterate_shared_addr == 0)
// return 0;
//
// unsigned long fops_addresses[2] = {iterate_shared_addr, iterate_addr};
// unsigned long fops_addresses[2] = {iterate_shared_addr, iterate_addr};
//
// save_u64_arr_to_buf(&p.event->args_buf, (const u64 *) fops_addresses, 2, 0);
// events_perf_submit(&p, HOOKED_PROC_FOPS, 0);
// return 0;
//}
// save_u64_arr_to_buf(&p.event->args_buf, (const u64 *) fops_addresses, 2, 0);
// events_perf_submit(&p, HOOKED_PROC_FOPS, 0);
// return 0;
// }

SEC("raw_tracepoint/task_rename")
int tracepoint__task__task_rename(struct bpf_raw_tracepoint_args *ctx)
Expand Down Expand Up @@ -6198,6 +6200,7 @@ int trace_inet_sock_set_state(struct bpf_raw_tracepoint_args *ctx)

return 0;
}
// clang-format on

SEC("raw_tracepoint/oom/mark_victim")
int oom_mark_victim(struct bpf_raw_tracepoint_args *ctx)
Expand All @@ -6209,4 +6212,31 @@ int oom_mark_victim(struct bpf_raw_tracepoint_args *ctx)
return 0;
}

// clang-format on
SEC("kprobe/tty_open")
int BPF_KPROBE(tty_open, struct inode *inode, struct file *filep)
{
program_data_t p = {};
if (!init_program_data(&p, ctx)) {
return 0;
}

if (!should_trace((&p))) {
return 0;
}

if (!should_submit(TTY_OPEN, p.event)) {
return 0;
}

void *file_path = get_path_str(__builtin_preserve_access_index(&filep->f_path));
unsigned long ino = BPF_CORE_READ(inode, i_ino);
dev_t dev = BPF_CORE_READ(inode, i_rdev);
umode_t inode_mode = get_inode_mode_from_file(filep);

save_str_to_buf(&p.event->args_buf, file_path, 0);
save_to_submit_buf(&p.event->args_buf, &ino, sizeof(ino), 1);
save_to_submit_buf(&p.event->args_buf, &inode_mode, sizeof(inode_mode), 2);
save_to_submit_buf(&p.event->args_buf, &dev, sizeof(dev), 3);

return events_perf_submit(&p, TTY_OPEN, 0);
}
Loading

0 comments on commit d0e50c5

Please sign in to comment.