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