1 /*
2 * RandomRead Monitor random number read events.
3 * For Linux, uses BCC, eBPF. Embedded C.
4 *
5 * Basic example of BCC Tracepoint and perf buffer.
6 *
7 * USAGE: RandomRead
8 *
9 * Copyright (c) Facebook, Inc.
10 * Licensed under the Apache License, Version 2.0 (the "License")
11 */
12
13 #include <signal.h>
14 #include <iostream>
15
16 #include "BPF.h"
17
18 const std::string BPF_PROGRAM = R"(
19 #include <linux/sched.h>
20 #include <uapi/linux/ptrace.h>
21
22 #ifndef CGROUP_FILTER
23 #define CGROUP_FILTER 0
24 #endif
25
26 struct urandom_read_args {
27 // See /sys/kernel/debug/tracing/events/random/urandom_read/format
28 uint64_t common__unused;
29 int got_bits;
30 int pool_left;
31 int input_left;
32 };
33
34 struct event_t {
35 int pid;
36 char comm[16];
37 int cpu;
38 int got_bits;
39 };
40
41 BPF_PERF_OUTPUT(events);
42 BPF_CGROUP_ARRAY(cgroup, 1);
43
44 int on_urandom_read(struct urandom_read_args* attr) {
45 if (CGROUP_FILTER && (cgroup.check_current_task(0) != 1))
46 return 0;
47
48 struct event_t event = {};
49 event.pid = bpf_get_current_pid_tgid();
50 bpf_get_current_comm(&event.comm, sizeof(event.comm));
51 event.cpu = bpf_get_smp_processor_id();
52 event.got_bits = attr->got_bits;
53
54 events.perf_submit(attr, &event, sizeof(event));
55 return 0;
56 }
57 )";
58
59 // Define the same struct to use in user space.
60 struct event_t {
61 int pid;
62 char comm[16];
63 int cpu;
64 int got_bits;
65 };
66
handle_output(void * cb_cookie,void * data,int data_size)67 void handle_output(void* cb_cookie, void* data, int data_size) {
68 auto event = static_cast<event_t*>(data);
69 std::cout << "PID: " << event->pid << " (" << event->comm << ") on CPU "
70 << event->cpu << " read " << event->got_bits << " bits"
71 << std::endl;
72 }
73
74 ebpf::BPF* bpf;
75
signal_handler(int s)76 void signal_handler(int s) {
77 std::cerr << "Terminating..." << std::endl;
78 delete bpf;
79 exit(0);
80 }
81
main(int argc,char ** argv)82 int main(int argc, char** argv) {
83 if (argc != 1 && argc != 2) {
84 std::cerr << "USAGE: RandomRead [cgroup2_path]" << std::endl;
85 return 1;
86 }
87
88 std::vector<std::string> cflags = {};
89 if (argc == 2)
90 cflags.emplace_back("-DCGROUP_FILTER=1");
91
92 bpf = new ebpf::BPF();
93 auto init_res = bpf->init(BPF_PROGRAM, cflags, {});
94 if (init_res.code() != 0) {
95 std::cerr << init_res.msg() << std::endl;
96 return 1;
97 }
98 if (argc == 2) {
99 auto cgroup_array = bpf->get_cgroup_array("cgroup");
100 auto update_res = cgroup_array.update_value(0, argv[1]);
101 if (update_res.code() != 0) {
102 std::cerr << update_res.msg() << std::endl;
103 return 1;
104 }
105 }
106
107 auto attach_res =
108 bpf->attach_tracepoint("random:urandom_read", "on_urandom_read");
109 if (attach_res.code() != 0) {
110 std::cerr << attach_res.msg() << std::endl;
111 return 1;
112 }
113
114 auto open_res = bpf->open_perf_buffer("events", &handle_output);
115 if (open_res.code() != 0) {
116 std::cerr << open_res.msg() << std::endl;
117 return 1;
118 }
119
120 signal(SIGINT, signal_handler);
121 std::cout << "Started tracing, hit Ctrl-C to terminate." << std::endl;
122 while (true)
123 bpf->poll_perf_buffer("events");
124
125 return 0;
126 }
127