xref: /aosp_15_r20/external/bcc/examples/cpp/KModRetExample.cc (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1*387f9dfdSAndroid Build Coastguard Worker /*
2*387f9dfdSAndroid Build Coastguard Worker  * Copyright (c) Facebook, Inc.
3*387f9dfdSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License")
4*387f9dfdSAndroid Build Coastguard Worker  *
5*387f9dfdSAndroid Build Coastguard Worker  * Usage:
6*387f9dfdSAndroid Build Coastguard Worker  *   $ ./KModRetExample
7*387f9dfdSAndroid Build Coastguard Worker  *   opened file: /bin/true
8*387f9dfdSAndroid Build Coastguard Worker  *   security_file_open() is called 1 times, expecting 1
9*387f9dfdSAndroid Build Coastguard Worker  *
10*387f9dfdSAndroid Build Coastguard Worker  * Kfunc modify_ret support is only available at kernel version 5.6 and later.
11*387f9dfdSAndroid Build Coastguard Worker  * This example only works for x64. Currently, only the kernel functions can
12*387f9dfdSAndroid Build Coastguard Worker  * be attached with BPF_MODIFY_RETURN:
13*387f9dfdSAndroid Build Coastguard Worker  *   - Whitelisted for error injection by checking within_error_injection_list.
14*387f9dfdSAndroid Build Coastguard Worker  *     Similar discussions happened for the bpf_override_return helper.
15*387f9dfdSAndroid Build Coastguard Worker  *   - The LSM security hooks (kernel global function with prefix "security_").
16*387f9dfdSAndroid Build Coastguard Worker  */
17*387f9dfdSAndroid Build Coastguard Worker 
18*387f9dfdSAndroid Build Coastguard Worker #include <fstream>
19*387f9dfdSAndroid Build Coastguard Worker #include <iostream>
20*387f9dfdSAndroid Build Coastguard Worker #include <iomanip>
21*387f9dfdSAndroid Build Coastguard Worker #include <string>
22*387f9dfdSAndroid Build Coastguard Worker 
23*387f9dfdSAndroid Build Coastguard Worker #include <error.h>
24*387f9dfdSAndroid Build Coastguard Worker #include <sys/types.h>
25*387f9dfdSAndroid Build Coastguard Worker #include <sys/stat.h>
26*387f9dfdSAndroid Build Coastguard Worker #include <fcntl.h>
27*387f9dfdSAndroid Build Coastguard Worker 
28*387f9dfdSAndroid Build Coastguard Worker #include "bcc_version.h"
29*387f9dfdSAndroid Build Coastguard Worker #include "BPF.h"
30*387f9dfdSAndroid Build Coastguard Worker 
31*387f9dfdSAndroid Build Coastguard Worker const std::string BPF_PROGRAM = R"(
32*387f9dfdSAndroid Build Coastguard Worker #include <linux/fs.h>
33*387f9dfdSAndroid Build Coastguard Worker #include <asm/errno.h>
34*387f9dfdSAndroid Build Coastguard Worker 
35*387f9dfdSAndroid Build Coastguard Worker BPF_ARRAY(target_pid, u32, 1);
36*387f9dfdSAndroid Build Coastguard Worker static bool match_target_pid()
37*387f9dfdSAndroid Build Coastguard Worker {
38*387f9dfdSAndroid Build Coastguard Worker   int key = 0, *val, tpid, cpid;
39*387f9dfdSAndroid Build Coastguard Worker 
40*387f9dfdSAndroid Build Coastguard Worker   val = target_pid.lookup(&key);
41*387f9dfdSAndroid Build Coastguard Worker   if (!val)
42*387f9dfdSAndroid Build Coastguard Worker     return false;
43*387f9dfdSAndroid Build Coastguard Worker 
44*387f9dfdSAndroid Build Coastguard Worker   tpid = *val;
45*387f9dfdSAndroid Build Coastguard Worker   cpid = bpf_get_current_pid_tgid() >> 32;
46*387f9dfdSAndroid Build Coastguard Worker   if (tpid == 0 || tpid != cpid)
47*387f9dfdSAndroid Build Coastguard Worker      return false;
48*387f9dfdSAndroid Build Coastguard Worker   return true;
49*387f9dfdSAndroid Build Coastguard Worker }
50*387f9dfdSAndroid Build Coastguard Worker 
51*387f9dfdSAndroid Build Coastguard Worker struct fname_buf {
52*387f9dfdSAndroid Build Coastguard Worker   char buf[16];
53*387f9dfdSAndroid Build Coastguard Worker };
54*387f9dfdSAndroid Build Coastguard Worker BPF_ARRAY(fname_table, struct fname_buf, 1);
55*387f9dfdSAndroid Build Coastguard Worker 
56*387f9dfdSAndroid Build Coastguard Worker KMOD_RET(__x64_sys_openat, struct pt_regs *regs, int ret)
57*387f9dfdSAndroid Build Coastguard Worker {
58*387f9dfdSAndroid Build Coastguard Worker   if (!match_target_pid())
59*387f9dfdSAndroid Build Coastguard Worker     return 0;
60*387f9dfdSAndroid Build Coastguard Worker 
61*387f9dfdSAndroid Build Coastguard Worker   // openat syscall arguments:
62*387f9dfdSAndroid Build Coastguard Worker   //   int dfd, const char __user * filename, int flags, umode_t mode
63*387f9dfdSAndroid Build Coastguard Worker   char *filename = (char *)PT_REGS_PARM2_SYSCALL(regs);
64*387f9dfdSAndroid Build Coastguard Worker 
65*387f9dfdSAndroid Build Coastguard Worker   int key = 0;
66*387f9dfdSAndroid Build Coastguard Worker   struct fname_buf *val;
67*387f9dfdSAndroid Build Coastguard Worker   val = fname_table.lookup(&key);
68*387f9dfdSAndroid Build Coastguard Worker   if (!val)
69*387f9dfdSAndroid Build Coastguard Worker     return false;
70*387f9dfdSAndroid Build Coastguard Worker 
71*387f9dfdSAndroid Build Coastguard Worker   if (bpf_copy_from_user(val, sizeof(*val), filename) < 0)
72*387f9dfdSAndroid Build Coastguard Worker     return 0;
73*387f9dfdSAndroid Build Coastguard Worker 
74*387f9dfdSAndroid Build Coastguard Worker   /* match target_pid, return -EINVAL. */
75*387f9dfdSAndroid Build Coastguard Worker   return -EINVAL;
76*387f9dfdSAndroid Build Coastguard Worker }
77*387f9dfdSAndroid Build Coastguard Worker 
78*387f9dfdSAndroid Build Coastguard Worker BPF_ARRAY(count, u32, 1);
79*387f9dfdSAndroid Build Coastguard Worker KMOD_RET(security_file_open, struct file *file, int ret)
80*387f9dfdSAndroid Build Coastguard Worker {
81*387f9dfdSAndroid Build Coastguard Worker   if (!match_target_pid())
82*387f9dfdSAndroid Build Coastguard Worker     return 0;
83*387f9dfdSAndroid Build Coastguard Worker 
84*387f9dfdSAndroid Build Coastguard Worker   int key = 0, *val;
85*387f9dfdSAndroid Build Coastguard Worker   val = count.lookup(&key);
86*387f9dfdSAndroid Build Coastguard Worker   if (!val)
87*387f9dfdSAndroid Build Coastguard Worker     return 0;
88*387f9dfdSAndroid Build Coastguard Worker 
89*387f9dfdSAndroid Build Coastguard Worker   /* no modification, kernel func continues to execute after this. */
90*387f9dfdSAndroid Build Coastguard Worker   lock_xadd(val, 1);
91*387f9dfdSAndroid Build Coastguard Worker   return 0;
92*387f9dfdSAndroid Build Coastguard Worker }
93*387f9dfdSAndroid Build Coastguard Worker )";
94*387f9dfdSAndroid Build Coastguard Worker 
95*387f9dfdSAndroid Build Coastguard Worker struct fname_buf {
96*387f9dfdSAndroid Build Coastguard Worker   char buf[16];
97*387f9dfdSAndroid Build Coastguard Worker };
98*387f9dfdSAndroid Build Coastguard Worker 
modify_return(ebpf::BPF & bpf)99*387f9dfdSAndroid Build Coastguard Worker static int modify_return(ebpf::BPF &bpf) {
100*387f9dfdSAndroid Build Coastguard Worker   int prog_fd;
101*387f9dfdSAndroid Build Coastguard Worker   auto res = bpf.load_func("kmod_ret____x64_sys_openat",
102*387f9dfdSAndroid Build Coastguard Worker                            BPF_PROG_TYPE_TRACING, prog_fd, BPF_F_SLEEPABLE);
103*387f9dfdSAndroid Build Coastguard Worker   if (!res.ok()) {
104*387f9dfdSAndroid Build Coastguard Worker     std::cerr << res.msg() << std::endl;
105*387f9dfdSAndroid Build Coastguard Worker     return 1;
106*387f9dfdSAndroid Build Coastguard Worker   }
107*387f9dfdSAndroid Build Coastguard Worker 
108*387f9dfdSAndroid Build Coastguard Worker   int attach_fd = bpf_attach_kfunc(prog_fd);
109*387f9dfdSAndroid Build Coastguard Worker   if (attach_fd < 0) {
110*387f9dfdSAndroid Build Coastguard Worker     std::cerr << "bpf_attach_kfunc failed: " << attach_fd << std::endl;
111*387f9dfdSAndroid Build Coastguard Worker     return 1;
112*387f9dfdSAndroid Build Coastguard Worker   }
113*387f9dfdSAndroid Build Coastguard Worker 
114*387f9dfdSAndroid Build Coastguard Worker   int ret = open("/bin/true", O_RDONLY);
115*387f9dfdSAndroid Build Coastguard Worker   if (ret >= 0 || errno != EINVAL) {
116*387f9dfdSAndroid Build Coastguard Worker     close(attach_fd);
117*387f9dfdSAndroid Build Coastguard Worker     std::cerr << "incorrect open result" << std::endl;
118*387f9dfdSAndroid Build Coastguard Worker     return 1;
119*387f9dfdSAndroid Build Coastguard Worker   }
120*387f9dfdSAndroid Build Coastguard Worker 
121*387f9dfdSAndroid Build Coastguard Worker   auto fname_table = bpf.get_array_table<struct fname_buf>("fname_table");
122*387f9dfdSAndroid Build Coastguard Worker   uint32_t key = 0;
123*387f9dfdSAndroid Build Coastguard Worker   struct fname_buf val;
124*387f9dfdSAndroid Build Coastguard Worker   res = fname_table.get_value(key, val);
125*387f9dfdSAndroid Build Coastguard Worker   if (!res.ok()) {
126*387f9dfdSAndroid Build Coastguard Worker     close(attach_fd);
127*387f9dfdSAndroid Build Coastguard Worker     std::cerr << res.msg() << std::endl;
128*387f9dfdSAndroid Build Coastguard Worker     return 1;
129*387f9dfdSAndroid Build Coastguard Worker   }
130*387f9dfdSAndroid Build Coastguard Worker   std::cout << "opened file: " << val.buf << std::endl;
131*387f9dfdSAndroid Build Coastguard Worker 
132*387f9dfdSAndroid Build Coastguard Worker   // detach the kfunc.
133*387f9dfdSAndroid Build Coastguard Worker   close(attach_fd);
134*387f9dfdSAndroid Build Coastguard Worker   return 0;
135*387f9dfdSAndroid Build Coastguard Worker }
136*387f9dfdSAndroid Build Coastguard Worker 
not_modify_return(ebpf::BPF & bpf)137*387f9dfdSAndroid Build Coastguard Worker static int not_modify_return(ebpf::BPF &bpf) {
138*387f9dfdSAndroid Build Coastguard Worker   int prog_fd;
139*387f9dfdSAndroid Build Coastguard Worker   auto res = bpf.load_func("kmod_ret__security_file_open",
140*387f9dfdSAndroid Build Coastguard Worker                             BPF_PROG_TYPE_TRACING, prog_fd);
141*387f9dfdSAndroid Build Coastguard Worker   if (!res.ok()) {
142*387f9dfdSAndroid Build Coastguard Worker     std::cerr << res.msg() << std::endl;
143*387f9dfdSAndroid Build Coastguard Worker     return 1;
144*387f9dfdSAndroid Build Coastguard Worker   }
145*387f9dfdSAndroid Build Coastguard Worker 
146*387f9dfdSAndroid Build Coastguard Worker   int attach_fd = bpf_attach_kfunc(prog_fd);
147*387f9dfdSAndroid Build Coastguard Worker   if (attach_fd < 0) {
148*387f9dfdSAndroid Build Coastguard Worker     std::cerr << "bpf_attach_kfunc failed: " << attach_fd << std::endl;
149*387f9dfdSAndroid Build Coastguard Worker     return 1;
150*387f9dfdSAndroid Build Coastguard Worker   }
151*387f9dfdSAndroid Build Coastguard Worker 
152*387f9dfdSAndroid Build Coastguard Worker   int ret = open("/bin/true", O_RDONLY);
153*387f9dfdSAndroid Build Coastguard Worker   if (ret < 0) {
154*387f9dfdSAndroid Build Coastguard Worker     close(attach_fd);
155*387f9dfdSAndroid Build Coastguard Worker     std::cerr << "incorrect open result" << std::endl;
156*387f9dfdSAndroid Build Coastguard Worker     return 1;
157*387f9dfdSAndroid Build Coastguard Worker   }
158*387f9dfdSAndroid Build Coastguard Worker 
159*387f9dfdSAndroid Build Coastguard Worker   auto count_table = bpf.get_array_table<uint32_t>("count");
160*387f9dfdSAndroid Build Coastguard Worker   uint32_t key = 0, val = 0;
161*387f9dfdSAndroid Build Coastguard Worker   res = count_table.get_value(key, val);
162*387f9dfdSAndroid Build Coastguard Worker   if (!res.ok()) {
163*387f9dfdSAndroid Build Coastguard Worker     close(attach_fd);
164*387f9dfdSAndroid Build Coastguard Worker     std::cerr << res.msg() << std::endl;
165*387f9dfdSAndroid Build Coastguard Worker     return 1;
166*387f9dfdSAndroid Build Coastguard Worker   }
167*387f9dfdSAndroid Build Coastguard Worker 
168*387f9dfdSAndroid Build Coastguard Worker   close(attach_fd);
169*387f9dfdSAndroid Build Coastguard Worker   std::cout << "security_file_open() is called " << val << " times, expecting 1\n";
170*387f9dfdSAndroid Build Coastguard Worker   return 0;
171*387f9dfdSAndroid Build Coastguard Worker }
172*387f9dfdSAndroid Build Coastguard Worker 
main()173*387f9dfdSAndroid Build Coastguard Worker int main() {
174*387f9dfdSAndroid Build Coastguard Worker   ebpf::BPF bpf;
175*387f9dfdSAndroid Build Coastguard Worker   auto res = bpf.init(BPF_PROGRAM);
176*387f9dfdSAndroid Build Coastguard Worker   if (!res.ok()) {
177*387f9dfdSAndroid Build Coastguard Worker     std::cerr << res.msg() << std::endl;
178*387f9dfdSAndroid Build Coastguard Worker     return 1;
179*387f9dfdSAndroid Build Coastguard Worker   }
180*387f9dfdSAndroid Build Coastguard Worker 
181*387f9dfdSAndroid Build Coastguard Worker   uint32_t key = 0, val = getpid();
182*387f9dfdSAndroid Build Coastguard Worker   auto pid_table = bpf.get_array_table<uint32_t>("target_pid");
183*387f9dfdSAndroid Build Coastguard Worker   res = pid_table.update_value(key, val);
184*387f9dfdSAndroid Build Coastguard Worker   if (!res.ok()) {
185*387f9dfdSAndroid Build Coastguard Worker     std::cerr << res.msg() << std::endl;
186*387f9dfdSAndroid Build Coastguard Worker     return 1;
187*387f9dfdSAndroid Build Coastguard Worker   }
188*387f9dfdSAndroid Build Coastguard Worker 
189*387f9dfdSAndroid Build Coastguard Worker   if (modify_return(bpf))
190*387f9dfdSAndroid Build Coastguard Worker     return 1;
191*387f9dfdSAndroid Build Coastguard Worker 
192*387f9dfdSAndroid Build Coastguard Worker   if (not_modify_return(bpf))
193*387f9dfdSAndroid Build Coastguard Worker     return 1;
194*387f9dfdSAndroid Build Coastguard Worker 
195*387f9dfdSAndroid Build Coastguard Worker   return 0;
196*387f9dfdSAndroid Build Coastguard Worker }
197