1#!/usr/bin/python 2# 3# bashreadline Print entered bash commands from all running shells. 4# For Linux, uses BCC, eBPF. Embedded C. 5# 6# USAGE: bashreadline [-s SHARED] 7# This works by tracing the readline() function using a uretprobe (uprobes). 8# When you failed to run the script directly with error: 9# `Exception: could not determine address of symbol b'readline'`, 10# you may need specify the location of libreadline.so library 11# with `-s` option. 12# 13# Copyright 2016 Netflix, Inc. 14# Licensed under the Apache License, Version 2.0 (the "License") 15# 16# 28-Jan-2016 Brendan Gregg Created this. 17# 12-Feb-2016 Allan McAleavy migrated to BPF_PERF_OUTPUT 18 19from __future__ import print_function 20from bcc import BPF 21from time import strftime 22import argparse 23 24parser = argparse.ArgumentParser( 25 description="Print entered bash commands from all running shells", 26 formatter_class=argparse.RawDescriptionHelpFormatter) 27parser.add_argument("-s", "--shared", nargs="?", 28 const="/lib/libreadline.so", type=str, 29 help="specify the location of libreadline.so library.\ 30 Default is /lib/libreadline.so") 31args = parser.parse_args() 32 33name = args.shared if args.shared else "/bin/bash" 34 35# load BPF program 36bpf_text = """ 37#include <uapi/linux/ptrace.h> 38#include <linux/sched.h> 39 40struct str_t { 41 u64 pid; 42 char str[80]; 43}; 44 45BPF_PERF_OUTPUT(events); 46 47int printret(struct pt_regs *ctx) { 48 struct str_t data = {}; 49 char comm[TASK_COMM_LEN] = {}; 50 u32 pid; 51 if (!PT_REGS_RC(ctx)) 52 return 0; 53 pid = bpf_get_current_pid_tgid() >> 32; 54 data.pid = pid; 55 bpf_probe_read_user(&data.str, sizeof(data.str), (void *)PT_REGS_RC(ctx)); 56 57 bpf_get_current_comm(&comm, sizeof(comm)); 58 if (comm[0] == 'b' && comm[1] == 'a' && comm[2] == 's' && comm[3] == 'h' && comm[4] == 0 ) { 59 events.perf_submit(ctx,&data,sizeof(data)); 60 } 61 62 63 return 0; 64}; 65""" 66 67b = BPF(text=bpf_text) 68b.attach_uretprobe(name=name, sym="readline", fn_name="printret") 69 70# header 71print("%-9s %-7s %s" % ("TIME", "PID", "COMMAND")) 72 73def print_event(cpu, data, size): 74 event = b["events"].event(data) 75 print("%-9s %-7d %s" % (strftime("%H:%M:%S"), event.pid, 76 event.str.decode('utf-8', 'replace'))) 77 78b["events"].open_perf_buffer(print_event) 79while 1: 80 try: 81 b.perf_buffer_poll() 82 except KeyboardInterrupt: 83 exit() 84