Skip to content

Commit

Permalink
Add sockaddr struct fields for unix, inet, inet6 sockets
Browse files Browse the repository at this point in the history
  • Loading branch information
yanivagman committed Jan 8, 2020
1 parent 05372ab commit aee95da
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 15 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,6 @@ Adding new events (especially system calls) to Tracee is straightforward, but on

## TODO

* Add full sockaddr struct fields to: "connect", "accept", "bind", "getsockname"
* Consider tracing commit_creds to detect potential kernel exploits
* Consider re-writing userspace side (python) in golang

Expand Down
22 changes: 20 additions & 2 deletions tracee/event_monitor_ebpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@
*/

#include <uapi/linux/ptrace.h>
#include <uapi/linux/in.h>
#include <uapi/linux/in6.h>
#include <uapi/linux/un.h>
#include <uapi/linux/utsname.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/nsproxy.h>
#include <linux/ns_common.h>
#include <linux/pid_namespace.h>
#include <linux/security.h>
#include <linux/socket.h>
#include <linux/version.h>

#define MAXARG 20
Expand Down Expand Up @@ -936,9 +940,23 @@ static __always_inline int save_args_to_submit_buf(u64 types)
save_to_submit_buf(submit_p, (void*)&(args.args[i]), sizeof(int), ACCESS_MODE_T);
break;
case SOCKADDR_T:
if (args.args[i])
if (args.args[i]) {
bpf_probe_read(&family, sizeof(short), (void*)args.args[i]);
save_to_submit_buf(submit_p, (void*)&family, sizeof(short), SOCKADDR_T);
switch (family)
{
case AF_UNIX:
save_to_submit_buf(submit_p, (void*)(args.args[i]), sizeof(struct sockaddr_un), SOCKADDR_T);
break;
case AF_INET:
save_to_submit_buf(submit_p, (void*)(args.args[i]), sizeof(struct sockaddr_in), SOCKADDR_T);
break;
case AF_INET6:
save_to_submit_buf(submit_p, (void*)(args.args[i]), sizeof(struct sockaddr_in6), SOCKADDR_T);
break;
default:
save_to_submit_buf(submit_p, (void*)&family, sizeof(short), SOCKADDR_T);
}
}
break;
}
}
Expand Down
109 changes: 97 additions & 12 deletions tracee/tracer.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,11 @@
44: "AF_XDP",
}

class SupportedAF(object):
AF_UNIX = 1
AF_INET = 2
AF_INET6 = 10

sock_type = {
1: "SOCK_STREAM",
2: "SOCK_DGRAM",
Expand Down Expand Up @@ -809,21 +814,103 @@ def init_bpf(self):
log.info("%-14s %-16s %-12s %-12s %-6s %-16s %-16s %-6s %-6s %-6s %-12s %s" % (
"TIME(s)", "UTS_NAME", "MNT_NS", "PID_NS", "UID", "EVENT", "COMM", "PID", "TID", "PPID", "RET", "ARGS"))

def swap_4_bytes(self, num):
return (((num << 24) & 0xFF000000) |
((num << 8) & 0x00FF0000) |
((num >> 8) & 0x0000FF00) |
((num >> 24) & 0x000000FF))

def get_sockaddr_from_buf(self, buf):
# todo: parse all fields
c_val = ctypes.cast(ctypes.byref(buf, self.cur_off), ctypes.POINTER(ctypes.c_short)).contents
self.cur_off = self.cur_off + 2
domain = c_val.value
sockaddr = dict()
domain = self.get_uint16_from_buf(buf)
if domain in sock_domain:
return sock_domain[domain]
sockaddr["sa_family"] = sock_domain[domain]
if domain == SupportedAF.AF_UNIX:
"""
struct sockaddr_un {
sa_family_t sun_family; /* AF_UNIX */
char sun_path[108]; /* Pathname */
};
"""
sun_path = buf[self.cur_off:self.cur_off + 108]
self.cur_off += 108
try:
sun_path_str = str(array.array('B', sun_path).tostring().decode("utf-8"))
sockaddr["sun_path"] = sun_path_str.strip('\x00')
except:
sockaddr["sun_path"] = ""
if domain == SupportedAF.AF_INET:
"""
struct sockaddr_in {
sa_family_t sin_family; /* address family: AF_INET */
in_port_t sin_port; /* port in network byte order */
struct in_addr sin_addr; /* internet address */
};
struct in_addr {
uint32_t s_addr; /* address in network byte order */
};
"""
sin_port = self.get_uint16_from_buf(buf)
# convert big endian (network byte order) to little endian (x86)
sin_port = ((sin_port << 8) & 0xFF00) | ((sin_port >> 8) & 0x00FF)
sockaddr["sin_port"] = str(sin_port)

sin_addr = str(self.get_uint8_from_buf(buf))
for i in range(3):
sin_addr = sin_addr + "." + str(self.get_uint8_from_buf(buf))
sockaddr["sin_addr"] = sin_addr
if domain == SupportedAF.AF_INET6:
"""
struct sockaddr_in6 {
sa_family_t sin6_family; /* AF_INET6 */
in_port_t sin6_port; /* port number */
uint32_t sin6_flowinfo; /* IPv6 flow information */
struct in6_addr sin6_addr; /* IPv6 address */
uint32_t sin6_scope_id; /* Scope ID (new in 2.4) */
};
struct in6_addr {
unsigned char s6_addr[16]; /* IPv6 address */
};
"""
sin6_port = self.get_uint16_from_buf(buf)
# convert big endian (network byte order) to little endian (x86)
sin6_port = ((sin6_port << 8) & 0xFF00) | ((sin6_port >> 8) & 0x00FF)
sockaddr["sin6_port"] = str(sin6_port)
sin6_flowinfo = self.get_uint_from_buf(buf)
# convert big endian (network byte order) to little endian (x86)
sin6_flowinfo = self.swap_4_bytes(sin6_flowinfo)
sockaddr["sin6_flowinfo"] = str(sin6_flowinfo)
sin6_addr = str("%0.2X" % self.get_uint8_from_buf(buf))
sin6_addr = sin6_addr + str("%0.2X" % self.get_uint8_from_buf(buf))
for i in range(7):
sin6_addr = sin6_addr + ":" + str("%0.2X" % self.get_uint8_from_buf(buf))
sin6_addr = sin6_addr + str("%0.2X" % self.get_uint8_from_buf(buf))
sockaddr["sin6_addr"] = sin6_addr
sin6_scope_id = self.get_uint_from_buf(buf)
# convert big endian (network byte order) to little endian (x86)
sin6_scope_id = self.swap_4_bytes(sin6_scope_id)
sockaddr["sin6_scope_id"] = str(sin6_scope_id)
else:
return str(domain)
sockaddr["sa_family"] = str(domain)

return sockaddr

def get_type_from_buf(self, buf):
c_val = ctypes.cast(ctypes.byref(buf, self.cur_off), ctypes.POINTER(ctypes.c_byte)).contents
self.cur_off = self.cur_off + 1
return c_val.value

def get_uint8_from_buf(self, buf):
c_val = ctypes.cast(ctypes.byref(buf, self.cur_off), ctypes.POINTER(ctypes.c_uint8)).contents
self.cur_off = self.cur_off + 1
return c_val.value

def get_uint16_from_buf(self, buf):
c_val = ctypes.cast(ctypes.byref(buf, self.cur_off), ctypes.POINTER(ctypes.c_uint16)).contents
self.cur_off = self.cur_off + 2
return c_val.value

def get_int_from_buf(self, buf):
c_val = ctypes.cast(ctypes.byref(buf, self.cur_off), ctypes.POINTER(ctypes.c_int)).contents
self.cur_off = self.cur_off + 4
Expand Down Expand Up @@ -860,15 +947,14 @@ def get_string_from_buf(self, buf):
except:
return ""

def get_str_arr_from_buf(self, buf, args):
def get_str_arr_from_buf(self, buf):
str_list = list()
while self.cur_off < ctypes.sizeof(buf):
argtype = self.get_type_from_buf(buf)
if argtype == ArgType.STR_T:
str_list.append(self.get_string_from_buf(buf).rstrip('\x00'))
else:
args.append('[%s]' % ', '.join(map(str, str_list)))
return
return '[%s]' % ', '.join(map(str, str_list))

def print_event(self, eventname, context, args):
# There are some syscalls which doesn't have the same name as their function
Expand Down Expand Up @@ -950,10 +1036,9 @@ def parse_event(self, event_buf):
elif argtype == ArgType.STR_T:
args.append(self.get_string_from_buf(event_buf))
elif argtype == ArgType.STR_ARR_T:
self.get_str_arr_from_buf(event_buf, args)
args.append(self.get_str_arr_from_buf(event_buf))
elif argtype == ArgType.SOCKADDR_T:
# sockaddr (partialy parsed to family)
args.append(self.get_sockaddr_from_buf(event_buf))
args.append(str(self.get_sockaddr_from_buf(event_buf)))
elif argtype == ArgType.OPEN_FLAGS_T:
args.append(open_flags_to_str(self.get_int_from_buf(event_buf)))
elif argtype == ArgType.PROT_FLAGS_T:
Expand Down

0 comments on commit aee95da

Please sign in to comment.