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 <sys/resource.h>
15 #include <iostream>
16
17 #include "BPF.h"
18
19 const std::string BPF_PROGRAM = R"(
20 #include <linux/sched.h>
21 #include <uapi/linux/ptrace.h>
22
23 #ifndef CGROUP_FILTER
24 #define CGROUP_FILTER 0
25 #endif
26
27 struct event_t {
28 int pid;
29 char comm[16];
30 int cpu;
31 int got_bits;
32 };
33
34 BPF_PERF_OUTPUT(events);
35 BPF_CGROUP_ARRAY(cgroup, 1);
36
37 int on_urandom_read(struct bpf_raw_tracepoint_args *ctx) {
38 if (CGROUP_FILTER && (cgroup.check_current_task(0) != 1))
39 return 0;
40
41 struct event_t event = {};
42 event.pid = bpf_get_current_pid_tgid();
43 bpf_get_current_comm(&event.comm, sizeof(event.comm));
44 event.cpu = bpf_get_smp_processor_id();
45 // from include/trace/events/random.h:
46 // TP_PROTO(int got_bits, int pool_left, int input_left)
47 event.got_bits = ctx->args[0];
48
49 events.perf_submit(ctx, &event, sizeof(event));
50 return 0;
51 }
52 )";
53
54 // Define the same struct to use in user space.
55 struct event_t {
56 int pid;
57 char comm[16];
58 int cpu;
59 int got_bits;
60 };
61
handle_output(void * cb_cookie,void * data,int data_size)62 void handle_output(void* cb_cookie, void* data, int data_size) {
63 auto event = static_cast<event_t*>(data);
64 std::cout << "PID: " << event->pid << " (" << event->comm << ") on CPU "
65 << event->cpu << " read " << event->got_bits << " bits"
66 << std::endl;
67 }
68
69 ebpf::BPF* bpf;
70
signal_handler(int s)71 void signal_handler(int s) {
72 std::cerr << "Terminating..." << std::endl;
73 delete bpf;
74 exit(0);
75 }
76
usage(void)77 void usage(void) {
78 std::cerr << "USAGE: RandomRead [{-r|-u} [cgroup2_path]]" << std::endl;
79 }
80
main(int argc,char ** argv)81 int main(int argc, char** argv) {
82 if (argc > 3) {
83 usage();
84 return 1;
85 }
86
87 bool allow_rlimit = true;
88 if (argc >= 2) {
89 // Set a small rlimit for MEMLOCK
90 struct rlimit rlim_new = {4096, 4096};
91 setrlimit(RLIMIT_MEMLOCK, &rlim_new);
92
93 if (strcmp(argv[1], "-r") == 0) {
94 allow_rlimit = false;
95 } else if (strcmp(argv[1], "-u") == 0) {
96 allow_rlimit = true;
97 } else {
98 usage();
99 return 1;
100 }
101 }
102
103 std::vector<std::string> cflags = {};
104 if (argc == 3)
105 cflags.emplace_back("-DCGROUP_FILTER=1");
106
107 bpf = new ebpf::BPF(0, nullptr, true, "", allow_rlimit);
108 auto init_res = bpf->init(BPF_PROGRAM, cflags, {});
109 if (!init_res.ok()) {
110 std::cerr << init_res.msg() << std::endl;
111 return 1;
112 }
113 if (argc == 3) {
114 auto cgroup_array = bpf->get_cgroup_array("cgroup");
115 auto update_res = cgroup_array.update_value(0, argv[2]);
116 if (!update_res.ok()) {
117 std::cerr << update_res.msg() << std::endl;
118 return 1;
119 }
120 }
121
122 auto attach_res =
123 bpf->attach_raw_tracepoint("urandom_read", "on_urandom_read");
124 if (!attach_res.ok()) {
125 std::cerr << attach_res.msg() << std::endl;
126 return 1;
127 }
128
129 auto open_res = bpf->open_perf_buffer("events", &handle_output);
130 if (!open_res.ok()) {
131 std::cerr << open_res.msg() << std::endl;
132 return 1;
133 }
134
135 // done with all initial work, free bcc memory
136 if (bpf->free_bcc_memory()) {
137 std::cerr << "Failed to free llvm/clang memory" << std::endl;
138 return 1;
139 }
140
141 signal(SIGINT, signal_handler);
142 std::cout << "Started tracing, hit Ctrl-C to terminate." << std::endl;
143 while (true)
144 bpf->poll_perf_buffer("events");
145
146 return 0;
147 }
148