xref: /aosp_15_r20/external/bcc/tools/sslsniff.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/env python
2*387f9dfdSAndroid Build Coastguard Worker#
3*387f9dfdSAndroid Build Coastguard Worker# sslsniff  Captures data on read/recv or write/send functions of OpenSSL,
4*387f9dfdSAndroid Build Coastguard Worker#           GnuTLS and NSS
5*387f9dfdSAndroid Build Coastguard Worker#           For Linux, uses BCC, eBPF.
6*387f9dfdSAndroid Build Coastguard Worker#
7*387f9dfdSAndroid Build Coastguard Worker# USAGE: sslsniff.py [-h] [-p PID] [-u UID] [-x] [-c COMM] [-o] [-g] [-n] [-d]
8*387f9dfdSAndroid Build Coastguard Worker#                    [--hexdump] [--max-buffer-size SIZE] [-l] [--handshake]
9*387f9dfdSAndroid Build Coastguard Worker#
10*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License")
11*387f9dfdSAndroid Build Coastguard Worker#
12*387f9dfdSAndroid Build Coastguard Worker# 12-Aug-2016    Adrian Lopez   Created this.
13*387f9dfdSAndroid Build Coastguard Worker# 13-Aug-2016    Mark Drayton   Fix SSL_Read
14*387f9dfdSAndroid Build Coastguard Worker# 17-Aug-2016    Adrian Lopez   Capture GnuTLS and add options
15*387f9dfdSAndroid Build Coastguard Worker#
16*387f9dfdSAndroid Build Coastguard Worker
17*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function
18*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF
19*387f9dfdSAndroid Build Coastguard Workerimport argparse
20*387f9dfdSAndroid Build Coastguard Workerimport binascii
21*387f9dfdSAndroid Build Coastguard Workerimport textwrap
22*387f9dfdSAndroid Build Coastguard Workerimport os.path
23*387f9dfdSAndroid Build Coastguard Worker
24*387f9dfdSAndroid Build Coastguard Worker# arguments
25*387f9dfdSAndroid Build Coastguard Workerexamples = """examples:
26*387f9dfdSAndroid Build Coastguard Worker    ./sslsniff              # sniff OpenSSL and GnuTLS functions
27*387f9dfdSAndroid Build Coastguard Worker    ./sslsniff -p 181       # sniff PID 181 only
28*387f9dfdSAndroid Build Coastguard Worker    ./sslsniff -u 1000      # sniff only UID 1000
29*387f9dfdSAndroid Build Coastguard Worker    ./sslsniff -c curl      # sniff curl command only
30*387f9dfdSAndroid Build Coastguard Worker    ./sslsniff --no-openssl # don't show OpenSSL calls
31*387f9dfdSAndroid Build Coastguard Worker    ./sslsniff --no-gnutls  # don't show GnuTLS calls
32*387f9dfdSAndroid Build Coastguard Worker    ./sslsniff --no-nss     # don't show NSS calls
33*387f9dfdSAndroid Build Coastguard Worker    ./sslsniff --hexdump    # show data as hex instead of trying to decode it as UTF-8
34*387f9dfdSAndroid Build Coastguard Worker    ./sslsniff -x           # show process UID and TID
35*387f9dfdSAndroid Build Coastguard Worker    ./sslsniff -l           # show function latency
36*387f9dfdSAndroid Build Coastguard Worker    ./sslsniff -l --handshake  # show SSL handshake latency
37*387f9dfdSAndroid Build Coastguard Worker    ./sslsniff --extra-lib openssl:/path/libssl.so.1.1 # sniff extra library
38*387f9dfdSAndroid Build Coastguard Worker"""
39*387f9dfdSAndroid Build Coastguard Worker
40*387f9dfdSAndroid Build Coastguard Worker
41*387f9dfdSAndroid Build Coastguard Workerdef ssllib_type(input_str):
42*387f9dfdSAndroid Build Coastguard Worker    valid_types = frozenset(['openssl', 'gnutls', 'nss'])
43*387f9dfdSAndroid Build Coastguard Worker
44*387f9dfdSAndroid Build Coastguard Worker    try:
45*387f9dfdSAndroid Build Coastguard Worker        lib_type, lib_path = input_str.split(':', 1)
46*387f9dfdSAndroid Build Coastguard Worker    except ValueError:
47*387f9dfdSAndroid Build Coastguard Worker        raise argparse.ArgumentTypeError("Invalid SSL library param: %r" % input_str)
48*387f9dfdSAndroid Build Coastguard Worker
49*387f9dfdSAndroid Build Coastguard Worker    if lib_type not in valid_types:
50*387f9dfdSAndroid Build Coastguard Worker        raise argparse.ArgumentTypeError("Invalid SSL library type: %r" % lib_type)
51*387f9dfdSAndroid Build Coastguard Worker
52*387f9dfdSAndroid Build Coastguard Worker    if not os.path.isfile(lib_path):
53*387f9dfdSAndroid Build Coastguard Worker        raise argparse.ArgumentTypeError("Invalid library path: %r" % lib_path)
54*387f9dfdSAndroid Build Coastguard Worker
55*387f9dfdSAndroid Build Coastguard Worker    return lib_type, lib_path
56*387f9dfdSAndroid Build Coastguard Worker
57*387f9dfdSAndroid Build Coastguard Worker
58*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser(
59*387f9dfdSAndroid Build Coastguard Worker    description="Sniff SSL data",
60*387f9dfdSAndroid Build Coastguard Worker    formatter_class=argparse.RawDescriptionHelpFormatter,
61*387f9dfdSAndroid Build Coastguard Worker    epilog=examples)
62*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-p", "--pid", type=int, help="sniff this PID only.")
63*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-u", "--uid", type=int, default=None,
64*387f9dfdSAndroid Build Coastguard Worker                    help="sniff this UID only.")
65*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-x", "--extra", action="store_true",
66*387f9dfdSAndroid Build Coastguard Worker                    help="show extra fields (UID, TID)")
67*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-c", "--comm",
68*387f9dfdSAndroid Build Coastguard Worker                    help="sniff only commands matching string.")
69*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-o", "--no-openssl", action="store_false", dest="openssl",
70*387f9dfdSAndroid Build Coastguard Worker                    help="do not show OpenSSL calls.")
71*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-g", "--no-gnutls", action="store_false", dest="gnutls",
72*387f9dfdSAndroid Build Coastguard Worker                    help="do not show GnuTLS calls.")
73*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-n", "--no-nss", action="store_false", dest="nss",
74*387f9dfdSAndroid Build Coastguard Worker                    help="do not show NSS calls.")
75*387f9dfdSAndroid Build Coastguard Workerparser.add_argument('-d', '--debug', dest='debug', action='count', default=0,
76*387f9dfdSAndroid Build Coastguard Worker                    help='debug mode.')
77*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--ebpf", action="store_true",
78*387f9dfdSAndroid Build Coastguard Worker                    help=argparse.SUPPRESS)
79*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--hexdump", action="store_true", dest="hexdump",
80*387f9dfdSAndroid Build Coastguard Worker                    help="show data as hexdump instead of trying to decode it as UTF-8")
81*387f9dfdSAndroid Build Coastguard Workerparser.add_argument('--max-buffer-size', type=int, default=8192,
82*387f9dfdSAndroid Build Coastguard Worker                    help='Size of captured buffer')
83*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-l", "--latency", action="store_true",
84*387f9dfdSAndroid Build Coastguard Worker                    help="show function latency")
85*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--handshake", action="store_true",
86*387f9dfdSAndroid Build Coastguard Worker                    help="show SSL handshake latency, enabled only if latency option is on.")
87*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--extra-lib", type=ssllib_type, action='append',
88*387f9dfdSAndroid Build Coastguard Worker                    help="Intercept calls from extra library (format: lib_type:lib_path)")
89*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args()
90*387f9dfdSAndroid Build Coastguard Worker
91*387f9dfdSAndroid Build Coastguard Worker
92*387f9dfdSAndroid Build Coastguard Workerprog = """
93*387f9dfdSAndroid Build Coastguard Worker#include <linux/ptrace.h>
94*387f9dfdSAndroid Build Coastguard Worker#include <linux/sched.h>        /* For TASK_COMM_LEN */
95*387f9dfdSAndroid Build Coastguard Worker
96*387f9dfdSAndroid Build Coastguard Worker#define MAX_BUF_SIZE __MAX_BUF_SIZE__
97*387f9dfdSAndroid Build Coastguard Worker
98*387f9dfdSAndroid Build Coastguard Workerstruct probe_SSL_data_t {
99*387f9dfdSAndroid Build Coastguard Worker        u64 timestamp_ns;
100*387f9dfdSAndroid Build Coastguard Worker        u64 delta_ns;
101*387f9dfdSAndroid Build Coastguard Worker        u32 pid;
102*387f9dfdSAndroid Build Coastguard Worker        u32 tid;
103*387f9dfdSAndroid Build Coastguard Worker        u32 uid;
104*387f9dfdSAndroid Build Coastguard Worker        u32 len;
105*387f9dfdSAndroid Build Coastguard Worker        int buf_filled;
106*387f9dfdSAndroid Build Coastguard Worker        int rw;
107*387f9dfdSAndroid Build Coastguard Worker        char comm[TASK_COMM_LEN];
108*387f9dfdSAndroid Build Coastguard Worker        u8 buf[MAX_BUF_SIZE];
109*387f9dfdSAndroid Build Coastguard Worker};
110*387f9dfdSAndroid Build Coastguard Worker
111*387f9dfdSAndroid Build Coastguard Worker#define BASE_EVENT_SIZE ((size_t)(&((struct probe_SSL_data_t*)0)->buf))
112*387f9dfdSAndroid Build Coastguard Worker#define EVENT_SIZE(X) (BASE_EVENT_SIZE + ((size_t)(X)))
113*387f9dfdSAndroid Build Coastguard Worker
114*387f9dfdSAndroid Build Coastguard WorkerBPF_PERCPU_ARRAY(ssl_data, struct probe_SSL_data_t, 1);
115*387f9dfdSAndroid Build Coastguard WorkerBPF_PERF_OUTPUT(perf_SSL_rw);
116*387f9dfdSAndroid Build Coastguard Worker
117*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(start_ns, u32);
118*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(bufs, u32, u64);
119*387f9dfdSAndroid Build Coastguard Worker
120*387f9dfdSAndroid Build Coastguard Workerint probe_SSL_rw_enter(struct pt_regs *ctx, void *ssl, void *buf, int num) {
121*387f9dfdSAndroid Build Coastguard Worker        int ret;
122*387f9dfdSAndroid Build Coastguard Worker        u32 zero = 0;
123*387f9dfdSAndroid Build Coastguard Worker        u64 pid_tgid = bpf_get_current_pid_tgid();
124*387f9dfdSAndroid Build Coastguard Worker        u32 pid = pid_tgid >> 32;
125*387f9dfdSAndroid Build Coastguard Worker        u32 tid = pid_tgid;
126*387f9dfdSAndroid Build Coastguard Worker        u32 uid = bpf_get_current_uid_gid();
127*387f9dfdSAndroid Build Coastguard Worker        u64 ts = bpf_ktime_get_ns();
128*387f9dfdSAndroid Build Coastguard Worker
129*387f9dfdSAndroid Build Coastguard Worker        PID_FILTER
130*387f9dfdSAndroid Build Coastguard Worker        UID_FILTER
131*387f9dfdSAndroid Build Coastguard Worker
132*387f9dfdSAndroid Build Coastguard Worker        bufs.update(&tid, (u64*)&buf);
133*387f9dfdSAndroid Build Coastguard Worker        start_ns.update(&tid, &ts);
134*387f9dfdSAndroid Build Coastguard Worker        return 0;
135*387f9dfdSAndroid Build Coastguard Worker}
136*387f9dfdSAndroid Build Coastguard Worker
137*387f9dfdSAndroid Build Coastguard Workerstatic int SSL_exit(struct pt_regs *ctx, int rw) {
138*387f9dfdSAndroid Build Coastguard Worker        int ret;
139*387f9dfdSAndroid Build Coastguard Worker        u32 zero = 0;
140*387f9dfdSAndroid Build Coastguard Worker        u64 pid_tgid = bpf_get_current_pid_tgid();
141*387f9dfdSAndroid Build Coastguard Worker        u32 pid = pid_tgid >> 32;
142*387f9dfdSAndroid Build Coastguard Worker        u32 tid = (u32)pid_tgid;
143*387f9dfdSAndroid Build Coastguard Worker        u32 uid = bpf_get_current_uid_gid();
144*387f9dfdSAndroid Build Coastguard Worker        u64 ts = bpf_ktime_get_ns();
145*387f9dfdSAndroid Build Coastguard Worker
146*387f9dfdSAndroid Build Coastguard Worker        PID_FILTER
147*387f9dfdSAndroid Build Coastguard Worker        UID_FILTER
148*387f9dfdSAndroid Build Coastguard Worker
149*387f9dfdSAndroid Build Coastguard Worker        u64 *bufp = bufs.lookup(&tid);
150*387f9dfdSAndroid Build Coastguard Worker        if (bufp == 0)
151*387f9dfdSAndroid Build Coastguard Worker                return 0;
152*387f9dfdSAndroid Build Coastguard Worker
153*387f9dfdSAndroid Build Coastguard Worker        u64 *tsp = start_ns.lookup(&tid);
154*387f9dfdSAndroid Build Coastguard Worker        if (tsp == 0)
155*387f9dfdSAndroid Build Coastguard Worker                return 0;
156*387f9dfdSAndroid Build Coastguard Worker
157*387f9dfdSAndroid Build Coastguard Worker        int len = PT_REGS_RC(ctx);
158*387f9dfdSAndroid Build Coastguard Worker        if (len <= 0) // no data
159*387f9dfdSAndroid Build Coastguard Worker                return 0;
160*387f9dfdSAndroid Build Coastguard Worker
161*387f9dfdSAndroid Build Coastguard Worker        struct probe_SSL_data_t *data = ssl_data.lookup(&zero);
162*387f9dfdSAndroid Build Coastguard Worker        if (!data)
163*387f9dfdSAndroid Build Coastguard Worker                return 0;
164*387f9dfdSAndroid Build Coastguard Worker
165*387f9dfdSAndroid Build Coastguard Worker        data->timestamp_ns = ts;
166*387f9dfdSAndroid Build Coastguard Worker        data->delta_ns = ts - *tsp;
167*387f9dfdSAndroid Build Coastguard Worker        data->pid = pid;
168*387f9dfdSAndroid Build Coastguard Worker        data->tid = tid;
169*387f9dfdSAndroid Build Coastguard Worker        data->uid = uid;
170*387f9dfdSAndroid Build Coastguard Worker        data->len = (u32)len;
171*387f9dfdSAndroid Build Coastguard Worker        data->buf_filled = 0;
172*387f9dfdSAndroid Build Coastguard Worker        data->rw = rw;
173*387f9dfdSAndroid Build Coastguard Worker        u32 buf_copy_size = min((size_t)MAX_BUF_SIZE, (size_t)len);
174*387f9dfdSAndroid Build Coastguard Worker
175*387f9dfdSAndroid Build Coastguard Worker        bpf_get_current_comm(&data->comm, sizeof(data->comm));
176*387f9dfdSAndroid Build Coastguard Worker
177*387f9dfdSAndroid Build Coastguard Worker        if (bufp != 0)
178*387f9dfdSAndroid Build Coastguard Worker                ret = bpf_probe_read_user(&data->buf, buf_copy_size, (char *)*bufp);
179*387f9dfdSAndroid Build Coastguard Worker
180*387f9dfdSAndroid Build Coastguard Worker        bufs.delete(&tid);
181*387f9dfdSAndroid Build Coastguard Worker        start_ns.delete(&tid);
182*387f9dfdSAndroid Build Coastguard Worker
183*387f9dfdSAndroid Build Coastguard Worker        if (!ret)
184*387f9dfdSAndroid Build Coastguard Worker                data->buf_filled = 1;
185*387f9dfdSAndroid Build Coastguard Worker        else
186*387f9dfdSAndroid Build Coastguard Worker                buf_copy_size = 0;
187*387f9dfdSAndroid Build Coastguard Worker
188*387f9dfdSAndroid Build Coastguard Worker        perf_SSL_rw.perf_submit(ctx, data, EVENT_SIZE(buf_copy_size));
189*387f9dfdSAndroid Build Coastguard Worker        return 0;
190*387f9dfdSAndroid Build Coastguard Worker}
191*387f9dfdSAndroid Build Coastguard Worker
192*387f9dfdSAndroid Build Coastguard Workerint probe_SSL_read_exit(struct pt_regs *ctx) {
193*387f9dfdSAndroid Build Coastguard Worker        return (SSL_exit(ctx, 0));
194*387f9dfdSAndroid Build Coastguard Worker}
195*387f9dfdSAndroid Build Coastguard Worker
196*387f9dfdSAndroid Build Coastguard Workerint probe_SSL_write_exit(struct pt_regs *ctx) {
197*387f9dfdSAndroid Build Coastguard Worker        return (SSL_exit(ctx, 1));
198*387f9dfdSAndroid Build Coastguard Worker}
199*387f9dfdSAndroid Build Coastguard Worker
200*387f9dfdSAndroid Build Coastguard WorkerBPF_PERF_OUTPUT(perf_SSL_do_handshake);
201*387f9dfdSAndroid Build Coastguard Worker
202*387f9dfdSAndroid Build Coastguard Workerint probe_SSL_do_handshake_enter(struct pt_regs *ctx, void *ssl) {
203*387f9dfdSAndroid Build Coastguard Worker        u64 pid_tgid = bpf_get_current_pid_tgid();
204*387f9dfdSAndroid Build Coastguard Worker        u32 pid = pid_tgid >> 32;
205*387f9dfdSAndroid Build Coastguard Worker        u32 tid = (u32)pid_tgid;
206*387f9dfdSAndroid Build Coastguard Worker        u64 ts = bpf_ktime_get_ns();
207*387f9dfdSAndroid Build Coastguard Worker        u32 uid = bpf_get_current_uid_gid();
208*387f9dfdSAndroid Build Coastguard Worker
209*387f9dfdSAndroid Build Coastguard Worker        PID_FILTER
210*387f9dfdSAndroid Build Coastguard Worker        UID_FILTER
211*387f9dfdSAndroid Build Coastguard Worker
212*387f9dfdSAndroid Build Coastguard Worker        start_ns.update(&tid, &ts);
213*387f9dfdSAndroid Build Coastguard Worker        return 0;
214*387f9dfdSAndroid Build Coastguard Worker}
215*387f9dfdSAndroid Build Coastguard Worker
216*387f9dfdSAndroid Build Coastguard Workerint probe_SSL_do_handshake_exit(struct pt_regs *ctx) {
217*387f9dfdSAndroid Build Coastguard Worker        u32 zero = 0;
218*387f9dfdSAndroid Build Coastguard Worker        u64 pid_tgid = bpf_get_current_pid_tgid();
219*387f9dfdSAndroid Build Coastguard Worker        u32 pid = pid_tgid >> 32;
220*387f9dfdSAndroid Build Coastguard Worker        u32 tid = (u32)pid_tgid;
221*387f9dfdSAndroid Build Coastguard Worker        u32 uid = bpf_get_current_uid_gid();
222*387f9dfdSAndroid Build Coastguard Worker        u64 ts = bpf_ktime_get_ns();
223*387f9dfdSAndroid Build Coastguard Worker        int ret;
224*387f9dfdSAndroid Build Coastguard Worker
225*387f9dfdSAndroid Build Coastguard Worker        PID_FILTER
226*387f9dfdSAndroid Build Coastguard Worker        UID_FILTER
227*387f9dfdSAndroid Build Coastguard Worker
228*387f9dfdSAndroid Build Coastguard Worker        u64 *tsp = start_ns.lookup(&tid);
229*387f9dfdSAndroid Build Coastguard Worker        if (tsp == 0)
230*387f9dfdSAndroid Build Coastguard Worker                return 0;
231*387f9dfdSAndroid Build Coastguard Worker
232*387f9dfdSAndroid Build Coastguard Worker        ret = PT_REGS_RC(ctx);
233*387f9dfdSAndroid Build Coastguard Worker        if (ret <= 0) // handshake failed
234*387f9dfdSAndroid Build Coastguard Worker                return 0;
235*387f9dfdSAndroid Build Coastguard Worker
236*387f9dfdSAndroid Build Coastguard Worker        struct probe_SSL_data_t *data = ssl_data.lookup(&zero);
237*387f9dfdSAndroid Build Coastguard Worker        if (!data)
238*387f9dfdSAndroid Build Coastguard Worker                return 0;
239*387f9dfdSAndroid Build Coastguard Worker
240*387f9dfdSAndroid Build Coastguard Worker        data->timestamp_ns = ts;
241*387f9dfdSAndroid Build Coastguard Worker        data->delta_ns = ts - *tsp;
242*387f9dfdSAndroid Build Coastguard Worker        data->pid = pid;
243*387f9dfdSAndroid Build Coastguard Worker        data->tid = tid;
244*387f9dfdSAndroid Build Coastguard Worker        data->uid = uid;
245*387f9dfdSAndroid Build Coastguard Worker        data->len = ret;
246*387f9dfdSAndroid Build Coastguard Worker        data->buf_filled = 0;
247*387f9dfdSAndroid Build Coastguard Worker        data->rw = 2;
248*387f9dfdSAndroid Build Coastguard Worker        bpf_get_current_comm(&data->comm, sizeof(data->comm));
249*387f9dfdSAndroid Build Coastguard Worker        start_ns.delete(&tid);
250*387f9dfdSAndroid Build Coastguard Worker
251*387f9dfdSAndroid Build Coastguard Worker        perf_SSL_do_handshake.perf_submit(ctx, data, EVENT_SIZE(0));
252*387f9dfdSAndroid Build Coastguard Worker        return 0;
253*387f9dfdSAndroid Build Coastguard Worker}
254*387f9dfdSAndroid Build Coastguard Worker"""
255*387f9dfdSAndroid Build Coastguard Worker
256*387f9dfdSAndroid Build Coastguard Workerif args.pid:
257*387f9dfdSAndroid Build Coastguard Worker    prog = prog.replace('PID_FILTER', 'if (pid != %d) { return 0; }' % args.pid)
258*387f9dfdSAndroid Build Coastguard Workerelse:
259*387f9dfdSAndroid Build Coastguard Worker    prog = prog.replace('PID_FILTER', '')
260*387f9dfdSAndroid Build Coastguard Worker
261*387f9dfdSAndroid Build Coastguard Workerif args.uid is not None:
262*387f9dfdSAndroid Build Coastguard Worker    prog = prog.replace('UID_FILTER', 'if (uid != %d) { return 0; }' % args.uid)
263*387f9dfdSAndroid Build Coastguard Workerelse:
264*387f9dfdSAndroid Build Coastguard Worker    prog = prog.replace('UID_FILTER', '')
265*387f9dfdSAndroid Build Coastguard Worker
266*387f9dfdSAndroid Build Coastguard Workerprog = prog.replace('__MAX_BUF_SIZE__', str(args.max_buffer_size))
267*387f9dfdSAndroid Build Coastguard Worker
268*387f9dfdSAndroid Build Coastguard Workerif args.debug or args.ebpf:
269*387f9dfdSAndroid Build Coastguard Worker    print(prog)
270*387f9dfdSAndroid Build Coastguard Worker    if args.ebpf:
271*387f9dfdSAndroid Build Coastguard Worker        exit()
272*387f9dfdSAndroid Build Coastguard Worker
273*387f9dfdSAndroid Build Coastguard Worker
274*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=prog)
275*387f9dfdSAndroid Build Coastguard Worker
276*387f9dfdSAndroid Build Coastguard Worker# It looks like SSL_read's arguments aren't available in a return probe so you
277*387f9dfdSAndroid Build Coastguard Worker# need to stash the buffer address in a map on the function entry and read it
278*387f9dfdSAndroid Build Coastguard Worker# on its exit (Mark Drayton)
279*387f9dfdSAndroid Build Coastguard Worker#
280*387f9dfdSAndroid Build Coastguard Workerdef attach_openssl(lib):
281*387f9dfdSAndroid Build Coastguard Worker    b.attach_uprobe(name=lib, sym="SSL_write",
282*387f9dfdSAndroid Build Coastguard Worker                    fn_name="probe_SSL_rw_enter", pid=args.pid or -1)
283*387f9dfdSAndroid Build Coastguard Worker    b.attach_uretprobe(name=lib, sym="SSL_write",
284*387f9dfdSAndroid Build Coastguard Worker                       fn_name="probe_SSL_write_exit", pid=args.pid or -1)
285*387f9dfdSAndroid Build Coastguard Worker    b.attach_uprobe(name=lib, sym="SSL_read",
286*387f9dfdSAndroid Build Coastguard Worker                    fn_name="probe_SSL_rw_enter", pid=args.pid or -1)
287*387f9dfdSAndroid Build Coastguard Worker    b.attach_uretprobe(name=lib, sym="SSL_read",
288*387f9dfdSAndroid Build Coastguard Worker                       fn_name="probe_SSL_read_exit", pid=args.pid or -1)
289*387f9dfdSAndroid Build Coastguard Worker    if args.latency and args.handshake:
290*387f9dfdSAndroid Build Coastguard Worker        b.attach_uprobe(name="ssl", sym="SSL_do_handshake",
291*387f9dfdSAndroid Build Coastguard Worker                        fn_name="probe_SSL_do_handshake_enter", pid=args.pid or -1)
292*387f9dfdSAndroid Build Coastguard Worker        b.attach_uretprobe(name="ssl", sym="SSL_do_handshake",
293*387f9dfdSAndroid Build Coastguard Worker                           fn_name="probe_SSL_do_handshake_exit", pid=args.pid or -1)
294*387f9dfdSAndroid Build Coastguard Worker
295*387f9dfdSAndroid Build Coastguard Workerdef attach_gnutls(lib):
296*387f9dfdSAndroid Build Coastguard Worker    b.attach_uprobe(name=lib, sym="gnutls_record_send",
297*387f9dfdSAndroid Build Coastguard Worker                    fn_name="probe_SSL_rw_enter", pid=args.pid or -1)
298*387f9dfdSAndroid Build Coastguard Worker    b.attach_uretprobe(name=lib, sym="gnutls_record_send",
299*387f9dfdSAndroid Build Coastguard Worker                       fn_name="probe_SSL_write_exit", pid=args.pid or -1)
300*387f9dfdSAndroid Build Coastguard Worker    b.attach_uprobe(name=lib, sym="gnutls_record_recv",
301*387f9dfdSAndroid Build Coastguard Worker                    fn_name="probe_SSL_rw_enter", pid=args.pid or -1)
302*387f9dfdSAndroid Build Coastguard Worker    b.attach_uretprobe(name=lib, sym="gnutls_record_recv",
303*387f9dfdSAndroid Build Coastguard Worker                       fn_name="probe_SSL_read_exit", pid=args.pid or -1)
304*387f9dfdSAndroid Build Coastguard Worker
305*387f9dfdSAndroid Build Coastguard Workerdef attach_nss(lib):
306*387f9dfdSAndroid Build Coastguard Worker    b.attach_uprobe(name=lib, sym="PR_Write",
307*387f9dfdSAndroid Build Coastguard Worker                    fn_name="probe_SSL_rw_enter", pid=args.pid or -1)
308*387f9dfdSAndroid Build Coastguard Worker    b.attach_uretprobe(name=lib, sym="PR_Write",
309*387f9dfdSAndroid Build Coastguard Worker                       fn_name="probe_SSL_write_exit", pid=args.pid or -1)
310*387f9dfdSAndroid Build Coastguard Worker    b.attach_uprobe(name=lib, sym="PR_Send",
311*387f9dfdSAndroid Build Coastguard Worker                    fn_name="probe_SSL_rw_enter", pid=args.pid or -1)
312*387f9dfdSAndroid Build Coastguard Worker    b.attach_uretprobe(name=lib, sym="PR_Send",
313*387f9dfdSAndroid Build Coastguard Worker                       fn_name="probe_SSL_write_exit", pid=args.pid or -1)
314*387f9dfdSAndroid Build Coastguard Worker    b.attach_uprobe(name=lib, sym="PR_Read",
315*387f9dfdSAndroid Build Coastguard Worker                    fn_name="probe_SSL_rw_enter", pid=args.pid or -1)
316*387f9dfdSAndroid Build Coastguard Worker    b.attach_uretprobe(name=lib, sym="PR_Read",
317*387f9dfdSAndroid Build Coastguard Worker                       fn_name="probe_SSL_read_exit", pid=args.pid or -1)
318*387f9dfdSAndroid Build Coastguard Worker    b.attach_uprobe(name=lib, sym="PR_Recv",
319*387f9dfdSAndroid Build Coastguard Worker                    fn_name="probe_SSL_rw_enter", pid=args.pid or -1)
320*387f9dfdSAndroid Build Coastguard Worker    b.attach_uretprobe(name=lib, sym="PR_Recv",
321*387f9dfdSAndroid Build Coastguard Worker                       fn_name="probe_SSL_read_exit", pid=args.pid or -1)
322*387f9dfdSAndroid Build Coastguard Worker
323*387f9dfdSAndroid Build Coastguard Worker
324*387f9dfdSAndroid Build Coastguard WorkerLIB_TRACERS = {
325*387f9dfdSAndroid Build Coastguard Worker    "openssl": attach_openssl,
326*387f9dfdSAndroid Build Coastguard Worker    "gnutls": attach_gnutls,
327*387f9dfdSAndroid Build Coastguard Worker    "nss": attach_nss,
328*387f9dfdSAndroid Build Coastguard Worker}
329*387f9dfdSAndroid Build Coastguard Worker
330*387f9dfdSAndroid Build Coastguard Worker
331*387f9dfdSAndroid Build Coastguard Workerif args.openssl:
332*387f9dfdSAndroid Build Coastguard Worker    attach_openssl("ssl")
333*387f9dfdSAndroid Build Coastguard Workerif args.gnutls:
334*387f9dfdSAndroid Build Coastguard Worker    attach_gnutls("gnutls")
335*387f9dfdSAndroid Build Coastguard Workerif args.nss:
336*387f9dfdSAndroid Build Coastguard Worker    attach_nss("nspr4")
337*387f9dfdSAndroid Build Coastguard Worker
338*387f9dfdSAndroid Build Coastguard Worker
339*387f9dfdSAndroid Build Coastguard Workerif args.extra_lib:
340*387f9dfdSAndroid Build Coastguard Worker    for lib_type, lib_path in args.extra_lib:
341*387f9dfdSAndroid Build Coastguard Worker        LIB_TRACERS[lib_type](lib_path)
342*387f9dfdSAndroid Build Coastguard Worker
343*387f9dfdSAndroid Build Coastguard Worker# define output data structure in Python
344*387f9dfdSAndroid Build Coastguard Worker
345*387f9dfdSAndroid Build Coastguard Worker
346*387f9dfdSAndroid Build Coastguard Worker# header
347*387f9dfdSAndroid Build Coastguard Workerheader = "%-12s %-18s %-16s %-7s %-7s" % ("FUNC", "TIME(s)", "COMM", "PID", "LEN")
348*387f9dfdSAndroid Build Coastguard Worker
349*387f9dfdSAndroid Build Coastguard Workerif args.extra:
350*387f9dfdSAndroid Build Coastguard Worker    header += " %-7s %-7s" % ("UID", "TID")
351*387f9dfdSAndroid Build Coastguard Worker
352*387f9dfdSAndroid Build Coastguard Workerif args.latency:
353*387f9dfdSAndroid Build Coastguard Worker    header += " %-7s" % ("LAT(ms)")
354*387f9dfdSAndroid Build Coastguard Worker
355*387f9dfdSAndroid Build Coastguard Workerprint(header)
356*387f9dfdSAndroid Build Coastguard Worker# process event
357*387f9dfdSAndroid Build Coastguard Workerstart = 0
358*387f9dfdSAndroid Build Coastguard Worker
359*387f9dfdSAndroid Build Coastguard Workerdef print_event_rw(cpu, data, size):
360*387f9dfdSAndroid Build Coastguard Worker    print_event(cpu, data, size, "perf_SSL_rw")
361*387f9dfdSAndroid Build Coastguard Worker
362*387f9dfdSAndroid Build Coastguard Workerdef print_event_handshake(cpu, data, size):
363*387f9dfdSAndroid Build Coastguard Worker    print_event(cpu, data, size, "perf_SSL_do_handshake")
364*387f9dfdSAndroid Build Coastguard Worker
365*387f9dfdSAndroid Build Coastguard Workerdef print_event(cpu, data, size, evt):
366*387f9dfdSAndroid Build Coastguard Worker    global start
367*387f9dfdSAndroid Build Coastguard Worker    event = b[evt].event(data)
368*387f9dfdSAndroid Build Coastguard Worker    if event.len <= args.max_buffer_size:
369*387f9dfdSAndroid Build Coastguard Worker        buf_size = event.len
370*387f9dfdSAndroid Build Coastguard Worker    else:
371*387f9dfdSAndroid Build Coastguard Worker        buf_size = args.max_buffer_size
372*387f9dfdSAndroid Build Coastguard Worker
373*387f9dfdSAndroid Build Coastguard Worker    if event.buf_filled == 1:
374*387f9dfdSAndroid Build Coastguard Worker        buf = bytearray(event.buf[:buf_size])
375*387f9dfdSAndroid Build Coastguard Worker    else:
376*387f9dfdSAndroid Build Coastguard Worker        buf_size = 0
377*387f9dfdSAndroid Build Coastguard Worker        buf = b""
378*387f9dfdSAndroid Build Coastguard Worker
379*387f9dfdSAndroid Build Coastguard Worker    # Filter events by command
380*387f9dfdSAndroid Build Coastguard Worker    if args.comm:
381*387f9dfdSAndroid Build Coastguard Worker        if not args.comm == event.comm.decode('utf-8', 'replace'):
382*387f9dfdSAndroid Build Coastguard Worker            return
383*387f9dfdSAndroid Build Coastguard Worker
384*387f9dfdSAndroid Build Coastguard Worker    if start == 0:
385*387f9dfdSAndroid Build Coastguard Worker        start = event.timestamp_ns
386*387f9dfdSAndroid Build Coastguard Worker    time_s = (float(event.timestamp_ns - start)) / 1000000000
387*387f9dfdSAndroid Build Coastguard Worker
388*387f9dfdSAndroid Build Coastguard Worker    lat_str = "%.3f" % (event.delta_ns / 1000000) if event.delta_ns else "N/A"
389*387f9dfdSAndroid Build Coastguard Worker
390*387f9dfdSAndroid Build Coastguard Worker    s_mark = "-" * 5 + " DATA " + "-" * 5
391*387f9dfdSAndroid Build Coastguard Worker
392*387f9dfdSAndroid Build Coastguard Worker    e_mark = "-" * 5 + " END DATA " + "-" * 5
393*387f9dfdSAndroid Build Coastguard Worker
394*387f9dfdSAndroid Build Coastguard Worker    truncated_bytes = event.len - buf_size
395*387f9dfdSAndroid Build Coastguard Worker    if truncated_bytes > 0:
396*387f9dfdSAndroid Build Coastguard Worker        e_mark = "-" * 5 + " END DATA (TRUNCATED, " + str(truncated_bytes) + \
397*387f9dfdSAndroid Build Coastguard Worker                " bytes lost) " + "-" * 5
398*387f9dfdSAndroid Build Coastguard Worker
399*387f9dfdSAndroid Build Coastguard Worker    base_fmt = "%(func)-12s %(time)-18.9f %(comm)-16s %(pid)-7d %(len)-6d"
400*387f9dfdSAndroid Build Coastguard Worker
401*387f9dfdSAndroid Build Coastguard Worker    if args.extra:
402*387f9dfdSAndroid Build Coastguard Worker        base_fmt += " %(uid)-7d %(tid)-7d"
403*387f9dfdSAndroid Build Coastguard Worker
404*387f9dfdSAndroid Build Coastguard Worker    if args.latency:
405*387f9dfdSAndroid Build Coastguard Worker        base_fmt += " %(lat)-7s"
406*387f9dfdSAndroid Build Coastguard Worker
407*387f9dfdSAndroid Build Coastguard Worker    fmt = ''.join([base_fmt, "\n%(begin)s\n%(data)s\n%(end)s\n\n"])
408*387f9dfdSAndroid Build Coastguard Worker    if args.hexdump:
409*387f9dfdSAndroid Build Coastguard Worker        unwrapped_data = binascii.hexlify(buf)
410*387f9dfdSAndroid Build Coastguard Worker        data = textwrap.fill(unwrapped_data.decode('utf-8', 'replace'), width=32)
411*387f9dfdSAndroid Build Coastguard Worker    else:
412*387f9dfdSAndroid Build Coastguard Worker        data = buf.decode('utf-8', 'replace')
413*387f9dfdSAndroid Build Coastguard Worker
414*387f9dfdSAndroid Build Coastguard Worker    rw_event = {
415*387f9dfdSAndroid Build Coastguard Worker        0: "READ/RECV",
416*387f9dfdSAndroid Build Coastguard Worker        1: "WRITE/SEND",
417*387f9dfdSAndroid Build Coastguard Worker        2: "HANDSHAKE"
418*387f9dfdSAndroid Build Coastguard Worker    }
419*387f9dfdSAndroid Build Coastguard Worker
420*387f9dfdSAndroid Build Coastguard Worker    fmt_data = {
421*387f9dfdSAndroid Build Coastguard Worker        'func': rw_event[event.rw],
422*387f9dfdSAndroid Build Coastguard Worker        'time': time_s,
423*387f9dfdSAndroid Build Coastguard Worker        'lat': lat_str,
424*387f9dfdSAndroid Build Coastguard Worker        'comm': event.comm.decode('utf-8', 'replace'),
425*387f9dfdSAndroid Build Coastguard Worker        'pid': event.pid,
426*387f9dfdSAndroid Build Coastguard Worker        'tid': event.tid,
427*387f9dfdSAndroid Build Coastguard Worker        'uid': event.uid,
428*387f9dfdSAndroid Build Coastguard Worker        'len': event.len,
429*387f9dfdSAndroid Build Coastguard Worker        'begin': s_mark,
430*387f9dfdSAndroid Build Coastguard Worker        'end': e_mark,
431*387f9dfdSAndroid Build Coastguard Worker        'data': data
432*387f9dfdSAndroid Build Coastguard Worker    }
433*387f9dfdSAndroid Build Coastguard Worker
434*387f9dfdSAndroid Build Coastguard Worker    # use base_fmt if no buf filled
435*387f9dfdSAndroid Build Coastguard Worker    if buf_size == 0:
436*387f9dfdSAndroid Build Coastguard Worker        print(base_fmt % fmt_data)
437*387f9dfdSAndroid Build Coastguard Worker    else:
438*387f9dfdSAndroid Build Coastguard Worker        print(fmt % fmt_data)
439*387f9dfdSAndroid Build Coastguard Worker
440*387f9dfdSAndroid Build Coastguard Workerb["perf_SSL_rw"].open_perf_buffer(print_event_rw)
441*387f9dfdSAndroid Build Coastguard Workerb["perf_SSL_do_handshake"].open_perf_buffer(print_event_handshake)
442*387f9dfdSAndroid Build Coastguard Workerwhile 1:
443*387f9dfdSAndroid Build Coastguard Worker    try:
444*387f9dfdSAndroid Build Coastguard Worker        b.perf_buffer_poll()
445*387f9dfdSAndroid Build Coastguard Worker    except KeyboardInterrupt:
446*387f9dfdSAndroid Build Coastguard Worker        exit()
447