Usage of Kprobe
KProbes is a debugging mechanism for the Linux kernel which can also be used for monitoring events inside a production system.
Fetch layout
FETCHARGS : Arguments. Each probe can have up to 128 args.%REG : Fetch register REG@ADDR : Fetch memory at ADDR (ADDR should be in kernel)@SYM[+|-offs] : Fetch memory at SYM +|- offs (SYM should be a data symbol)$stackN : Fetch Nth entry of stack (N >= 0)$stack : Fetch stack address.$retval : Fetch return value.(*)$comm : Fetch current task comm.+|-offs(FETCHARG) : Fetch memory at FETCHARG +|- offs address.(**) -> access ptr type varNAME=FETCHARG : Set NAME as the argument name of FETCHARG.FETCHARG:TYPE : Set TYPE as the type of FETCHARG. Currently, basic types(u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal types(x8/x16/x32/x64), "string" and bitfield are supported.
Enable an event of kprobe
sys_connect as the example
# pwd -> /sys/kernel/debug/tracing# sys_connect(int, struct sockaddr *, int)# how to find params store in which register -> check the macro of the linux source# PT_REGS_PARM1_CORE, PT_REGS_PARM2_CORE, PT_REGS_PARM3_CORE# second param storing in %si or %edx depends on the arch# The string array type is a bit different from other types. For other base types, <base-type>[1] is equal to <base-type> (e.g. +0(%di):x32[1] is same as +0(%di):x32.) But string[1] is not equal to string. The string type itself represents “char array”, but string array type represents “char * array”
sockaddr <-> sockaddr_in
# first 2 bytes are type# bytes 0-1 of sockaddr.sa_data are sockaddr_in.sin_port# bytes 2-5 are sockaddr_in.sin_addr# bytes 6-13 are sockaddr_in.sin_zero
Definition of the structs in kernel
struct sockaddr { sa_family_t sa_family; char sa_data[14];};struct sockaddr_in { short sin_family; // e.g. AF_INET 2 unsigned short sin_port; // e.g. htons(3490) struct in_addr sin_addr; // see struct in_addr, below char sin_zero[8]; // zero this if you want to};struct in_addr {
uint32_t s_addr; /* address in network byte order */
};
Define Kprobe event
# use byte memory offset and type definition to define kprobe event
# type is u16 which is short in the offset 0 of %si register (second param)
# port is in offset 2 of %si register with unsigned short type
# addr is in offset 4 which is 4 bytes long sudo echo "p:mysocket_event sys_connect type=+0(%si):u16 port=+2(%si):u16 addr=+4(%si):u32" >> kprobe_events
Enable kprobe event mysocket_event
echo "1" > events/kprobes/mysocket_event/enable
Cleanup the event
# cleanup# echo "0" > events/kprobes/mysocket_event/enable && echo > kprobe_eventsecho "0" > events/kprobes/mysocket_event/enableecho > /sys/kernel/debug/tracing/kprobe_events
Ways to track events
cat /sys/kernel/debug/tracing/trace# read from trace_pipe
cat trace_pipe
Real example data
# netcat -zv 127.0.0.1 25# netcat-1048 [001] .... 1272634.456626: mysocket_event: (SyS_connect+0x0/0x10) type=2 port=6400 addr=16777343# port=6400 is network byte order
# do the ntohs transformation -> 25# socket.ntohl(16777343) # long net byte order to host byte order
# 2130706433# bit operation to convert host byte order to IpV4# 2130706433 % 256 -> 1
# (2130706433 >> 8) % 256 -> 0
# (2130706433 >> 16) % 256 -> 0
# (2130706433 >> 24) % 256 -> 127# 127.0.0.1
Transformation of network byte order and host byte order
# using python as the example
import socketsocket.ntohs(6400) # 25socket.nthhl(16777343) # 2130706433socket.inet_aton("127.0.0.1") # b'\x7f\x00\x00\x01'int.from_bytes(b'\x7f\x00\x00\x01', "little") #16777343
References
- http://web.mit.edu/macdev/Development/MITSupportLib/SocketsLib/Documentation/structures.html
- https://www.geek-share.com/detail/2727807280.html
- https://www.kernel.org/doc/Documentation/trace/kprobetrace.txt
- https://www.tutorialspoint.com/assembly_programming/assembly_registers.htm
- https://github.com/torvalds/linux/blob/9ff9b0d392ea08090cd1780fb196f36dbb586529/samples/bpf/test_probe_write_user_kern.c
- https://stackoverflow.com/questions/9312113/why-can-we-cast-sockaddr-to-sockaddr-in/9312174
- https://www.gta.ufrj.br/ensino/eel878/sockets/sockaddr_inman.html