Skip to content

Commit

Permalink
add creat syscall and fix open incorrect flags bug
Browse files Browse the repository at this point in the history
  • Loading branch information
yanivagman committed Oct 2, 2019
1 parent 220d5ed commit 9871c7a
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 27 deletions.
23 changes: 18 additions & 5 deletions container_event_monitor_ebpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@

// todo: execve: handle envp, put argv and envp in a list instead being different param for each arg
// todo: when a new file is written - copy it offline
// todo: add syscalls: "getdirents", "uname", "symlink", "symlinkat"
// todo: add syscalls: "getdirents", "uname"
// todo: add full sockaddr struct to: "connect", "accept", "bind", "getsockname"
// todo: add commit_creds tracing to detect kernel exploits
// todo: macro of function which includes entry and exit
// todo: fix problem with execveat - can't see pathname
// todo: save argv_loc array in a map instead of submitting it (to avoid race condition). we can't remove entrance as after execve memory is wiped
// todo: add check for head and tail to avoid overflow!
// todo: have modification of a new syscall happen in one consolidated struct, that will be used in relevant macro (to avoid updating in several places in file)
// todo: add a "do extra" function inside the macro, so we can also include special cases (e.g. is_capable)
// todo: add support for kernel versions 4.19 onward (see kernel version dependant section below)

Expand Down Expand Up @@ -400,6 +399,12 @@ typedef struct execve_info {
int argv_loc[MAXARG+1]; // argv location in str_buf
} execve_info_t;

typedef struct creat_info {
context_t context;
int pathname_loc;
int flags;
} creat_info_t;

typedef struct execveat_info {
context_t context;
enum event_type type;
Expand Down Expand Up @@ -648,6 +653,8 @@ static __always_inline int is_container()
return lookup_pid_ns(task);
}

// Note: this function is not nested!
// if inner kernel functions are called in syscall this may be a problem! - fix
static __always_inline int save_args(struct pt_regs *ctx)
{
u64 id;
Expand All @@ -669,6 +676,8 @@ static __always_inline int save_args(struct pt_regs *ctx)
return 0;
}

// Note: this function is not nested!
// if inner kernel functions are called in syscall this may be a problem! - fix
static __always_inline int load_args(args_t *args)
{
args_t *saved_args;
Expand Down Expand Up @@ -785,8 +794,12 @@ int trace_ret_##name(struct pt_regs *ctx) \

// Note: race condition may occur if a malicious user changes the arguments concurrently
// consider using security_file_open instead
TRACE_ENT_FUNC(open);
TRACE_RET_FUNC(open, SYS_OPEN, ARG_TYPE0(INT_T)|ARG_TYPE1(STR_T)|ARG_TYPE2(INT_T));
TRACE_ENT_FUNC(sys_open);
TRACE_RET_FUNC(sys_open, SYS_OPEN, ARG_TYPE0(STR_T)|ARG_TYPE1(INT_T));
TRACE_ENT_FUNC(sys_openat);
TRACE_RET_FUNC(sys_openat, SYS_OPENAT, ARG_TYPE0(INT_T)|ARG_TYPE1(STR_T)|ARG_TYPE2(INT_T));
TRACE_ENT_FUNC(sys_creat);
TRACE_RET_FUNC(sys_creat, SYS_CREAT, ARG_TYPE0(STR_T)|ARG_TYPE1(INT_T));
TRACE_ENT_FUNC(sys_mmap);
TRACE_RET_FUNC(sys_mmap, SYS_MMAP, ARG_TYPE0(POINTER_T)|ARG_TYPE1(SIZE_T_T)|ARG_TYPE2(INT_T)|ARG_TYPE3(INT_T)|ARG_TYPE4(INT_T)|ARG_TYPE5(OFF_T_T));
TRACE_ENT_FUNC(sys_mprotect);
Expand Down Expand Up @@ -992,7 +1005,7 @@ int trace_do_exit(struct pt_regs *ctx, long code)
return 0;
}

int kprobe__cap_capable(struct pt_regs *ctx, const struct cred *cred,
int trace_cap_capable(struct pt_regs *ctx, const struct cred *cred,
struct user_namespace *targ_ns, int cap, int cap_opt)
{
int audit;
Expand Down
65 changes: 43 additions & 22 deletions container_tracer.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@
"memfd_create", "socket", "close", "ioctl", "access", "faccessat", "kill", "listen",
"connect", "accept", "accept4", "bind", "getsockname", "prctl", "ptrace",
"process_vm_writev", "process_vm_readv", "init_module", "finit_module", "delete_module",
"symlink", "symlinkat", "getdents", "getdents64"]
"symlink", "symlinkat", "getdents", "getdents64", "creat", "open", "openat"]

class EventType(object):
EVENT_ARG = 0
Expand Down Expand Up @@ -516,11 +516,23 @@ class execveat_info_t(ctypes.Structure):

class open_info_t(ctypes.Structure):
_pack_ = 1 # for all events passed with buffer (in eBPF code), we use packed structs
_fields_ = [("context", context_t),
("filename_loc", ctypes.c_uint),
("flags", ctypes.c_int),]

class openat_info_t(ctypes.Structure):
_pack_ = 1
_fields_ = [("context", context_t),
("dirfd", ctypes.c_int),
("filename_loc", ctypes.c_uint),
("flags", ctypes.c_int),]

class creat_info_t(ctypes.Structure):
#_pack_ = 1
_fields_ = [("context", context_t),
("pathname_loc", ctypes.c_uint),
("mode", ctypes.c_uint),]

class memfd_create_info_t(ctypes.Structure):
_pack_ = 1
_fields_ = [("context", context_t),
Expand Down Expand Up @@ -750,10 +762,8 @@ def init_bpf(self):
self.bpf.attach_kprobe(event=syscall_fnname, fn_name="trace_sys_" + syscall)
self.bpf.attach_kretprobe(event=syscall_fnname, fn_name="trace_ret_sys_" + syscall)

self.bpf.attach_kprobe(event="do_sys_open", fn_name="trace_open")
self.bpf.attach_kretprobe(event="do_sys_open", fn_name="trace_ret_open")
self.bpf.attach_kprobe(event="do_exit", fn_name="trace_do_exit")
#self.bpf.attach_kprobe(event="cap_capable", fn_name="trace_cap_capable")
self.bpf.attach_kprobe(event="cap_capable", fn_name="trace_cap_capable")

if self.verbose:
log.info("%-14s %-12s %-12s %-6s %-16s %-16s %-6s %-6s %-6s %-16s %s" % ("TIME(s)", "MNT_NS", "PID_NS", "UID", "EVENT", "COMM", "PID", "TID", "PPID", "RET", "ARGS"))
Expand Down Expand Up @@ -914,60 +924,60 @@ def access_mode_to_str(self, flags):
def open_flags_to_str(self, flags):
f_str = ""

if flags&0x1:
if flags&0o1:
f_str += "O_WRONLY"
elif flags&0x2:
elif flags&0o2:
f_str += "O_RDWR"
else:
f_str += "O_RDONLY"


if flags&0x100:
if flags&0o100:
f_str += "|O_CREAT"

if flags&0x200:
if flags&0o200:
f_str += "|O_EXCL"

if flags&0x400:
if flags&0o400:
f_str += "|O_NOCTTY"

if flags&0x1000:
if flags&0o1000:
f_str += "|O_TRUNC"

if flags&0x2000:
if flags&0o2000:
f_str += "|O_APPEND"

if flags&0x4000:
if flags&0o4000:
f_str += "|O_NONBLOCK"

if flags&0x4010000:
if flags&0o4010000:
f_str += "|O_SYNC"

if flags&0x20000:
if flags&0o20000:
f_str += "|O_ASYNC"

if flags&0x100000:
if flags&0o100000:
f_str += "|O_LARGEFILE"

if flags&0x200000:
if flags&0o200000:
f_str += "|O_DIRECTORY"

if flags&0x400000:
if flags&0o400000:
f_str += "|O_NOFOLLOW"

if flags&0x2000000:
if flags&0o2000000:
f_str += "|O_CLOEXEC"

if flags&0x40000:
if flags&0o40000:
f_str += "|O_DIRECT"

if flags&0x1000000:
if flags&0o1000000:
f_str += "|O_NOATIME"

if flags&0x10000000:
if flags&0o10000000:
f_str += "|O_PATH"

if flags&0x20000000:
if flags&0o20000000:
f_str += "|O_TMPFILE"

return f_str
Expand Down Expand Up @@ -1033,6 +1043,17 @@ def print_event(self, cpu, data, size):
event = ctypes.cast(data, ctypes.POINTER(open_info_t)).contents
args.append(self.get_string_from_buf(cpu, int(event.filename_loc)))
args.append(self.open_flags_to_str(event.flags))
elif context.eventid == EventId.SYS_OPENAT:
eventname = "openat"
event = ctypes.cast(data, ctypes.POINTER(openat_info_t)).contents
args.append(str(event.dirfd))
args.append(self.get_string_from_buf(cpu, int(event.filename_loc)))
args.append(self.open_flags_to_str(event.flags))
elif context.eventid == EventId.SYS_CREAT:
eventname = "creat"
event = ctypes.cast(data, ctypes.POINTER(creat_info_t)).contents
args.append(self.get_string_from_buf(cpu, int(event.pathname_loc)))
args.append(str(event.mode))
elif context.eventid == EventId.SYS_MEMFD_CREATE:
eventname = "memfd_create"
event = ctypes.cast(data, ctypes.POINTER(memfd_create_info_t)).contents
Expand Down

0 comments on commit 9871c7a

Please sign in to comment.