1cd324d7aSKP Singh // SPDX-License-Identifier: GPL-2.0
2cd324d7aSKP Singh
3cd324d7aSKP Singh /*
4cd324d7aSKP Singh * Copyright 2020 Google LLC.
5cd324d7aSKP Singh */
6cd324d7aSKP Singh
7a367efa7SKP Singh #include "vmlinux.h"
8cd324d7aSKP Singh #include <errno.h>
9cd324d7aSKP Singh #include <bpf/bpf_helpers.h>
10cd324d7aSKP Singh #include <bpf/bpf_tracing.h>
11cd324d7aSKP Singh
12cd324d7aSKP Singh char _license[] SEC("license") = "GPL";
13cd324d7aSKP Singh
14cd324d7aSKP Singh #define DUMMY_STORAGE_VALUE 0xdeadbeef
15cd324d7aSKP Singh
16cd324d7aSKP Singh int monitored_pid = 0;
17cd324d7aSKP Singh int inode_storage_result = -1;
18cd324d7aSKP Singh int sk_storage_result = -1;
19d8db84d7SMartin KaFai Lau int task_storage_result = -1;
20cd324d7aSKP Singh
219cde3beeSKP Singh struct local_storage {
229cde3beeSKP Singh struct inode *exec_inode;
23cd324d7aSKP Singh __u32 value;
24cd324d7aSKP Singh };
25cd324d7aSKP Singh
26cd324d7aSKP Singh struct {
27cd324d7aSKP Singh __uint(type, BPF_MAP_TYPE_INODE_STORAGE);
28cd324d7aSKP Singh __uint(map_flags, BPF_F_NO_PREALLOC);
29cd324d7aSKP Singh __type(key, int);
309cde3beeSKP Singh __type(value, struct local_storage);
31cd324d7aSKP Singh } inode_storage_map SEC(".maps");
32cd324d7aSKP Singh
33cd324d7aSKP Singh struct {
34cd324d7aSKP Singh __uint(type, BPF_MAP_TYPE_SK_STORAGE);
35cd324d7aSKP Singh __uint(map_flags, BPF_F_NO_PREALLOC | BPF_F_CLONE);
36cd324d7aSKP Singh __type(key, int);
379cde3beeSKP Singh __type(value, struct local_storage);
38cd324d7aSKP Singh } sk_storage_map SEC(".maps");
39cd324d7aSKP Singh
409cde3beeSKP Singh struct {
410e790cbbSJoanne Koong __uint(type, BPF_MAP_TYPE_SK_STORAGE);
420e790cbbSJoanne Koong __uint(map_flags, BPF_F_NO_PREALLOC | BPF_F_CLONE);
430e790cbbSJoanne Koong __type(key, int);
440e790cbbSJoanne Koong __type(value, struct local_storage);
450e790cbbSJoanne Koong } sk_storage_map2 SEC(".maps");
460e790cbbSJoanne Koong
470e790cbbSJoanne Koong struct {
489cde3beeSKP Singh __uint(type, BPF_MAP_TYPE_TASK_STORAGE);
499cde3beeSKP Singh __uint(map_flags, BPF_F_NO_PREALLOC);
509cde3beeSKP Singh __type(key, int);
519cde3beeSKP Singh __type(value, struct local_storage);
529cde3beeSKP Singh } task_storage_map SEC(".maps");
539cde3beeSKP Singh
54d8db84d7SMartin KaFai Lau struct {
55d8db84d7SMartin KaFai Lau __uint(type, BPF_MAP_TYPE_TASK_STORAGE);
56d8db84d7SMartin KaFai Lau __uint(map_flags, BPF_F_NO_PREALLOC);
57d8db84d7SMartin KaFai Lau __type(key, int);
58d8db84d7SMartin KaFai Lau __type(value, struct local_storage);
59d8db84d7SMartin KaFai Lau } task_storage_map2 SEC(".maps");
60d8db84d7SMartin KaFai Lau
61cd324d7aSKP Singh SEC("lsm/inode_unlink")
BPF_PROG(unlink_hook,struct inode * dir,struct dentry * victim)62cd324d7aSKP Singh int BPF_PROG(unlink_hook, struct inode *dir, struct dentry *victim)
63cd324d7aSKP Singh {
64cd324d7aSKP Singh __u32 pid = bpf_get_current_pid_tgid() >> 32;
65d8db84d7SMartin KaFai Lau struct bpf_local_storage *local_storage;
669cde3beeSKP Singh struct local_storage *storage;
67d8db84d7SMartin KaFai Lau struct task_struct *task;
689cde3beeSKP Singh bool is_self_unlink;
69cd324d7aSKP Singh
70cd324d7aSKP Singh if (pid != monitored_pid)
71cd324d7aSKP Singh return 0;
72cd324d7aSKP Singh
73d8db84d7SMartin KaFai Lau task = bpf_get_current_task_btf();
74d8db84d7SMartin KaFai Lau if (!task)
75d8db84d7SMartin KaFai Lau return 0;
76d8db84d7SMartin KaFai Lau
77d8db84d7SMartin KaFai Lau task_storage_result = -1;
78d8db84d7SMartin KaFai Lau
79d8db84d7SMartin KaFai Lau storage = bpf_task_storage_get(&task_storage_map, task, 0, 0);
80d8db84d7SMartin KaFai Lau if (!storage)
81d8db84d7SMartin KaFai Lau return 0;
82d8db84d7SMartin KaFai Lau
839cde3beeSKP Singh /* Don't let an executable delete itself */
849cde3beeSKP Singh is_self_unlink = storage->exec_inode == victim->d_inode;
859cde3beeSKP Singh
86d8db84d7SMartin KaFai Lau storage = bpf_task_storage_get(&task_storage_map2, task, 0,
87d8db84d7SMartin KaFai Lau BPF_LOCAL_STORAGE_GET_F_CREATE);
88d8db84d7SMartin KaFai Lau if (!storage || storage->value)
892f94ac19SKP Singh return 0;
90d8db84d7SMartin KaFai Lau
91d8db84d7SMartin KaFai Lau if (bpf_task_storage_delete(&task_storage_map, task))
92d8db84d7SMartin KaFai Lau return 0;
93d8db84d7SMartin KaFai Lau
94d8db84d7SMartin KaFai Lau /* Ensure that the task_storage_map is disconnected from the storage.
95d8db84d7SMartin KaFai Lau * The storage memory should not be freed back to the
96d8db84d7SMartin KaFai Lau * bpf_mem_alloc.
97d8db84d7SMartin KaFai Lau */
98d8db84d7SMartin KaFai Lau local_storage = task->bpf_storage;
99d8db84d7SMartin KaFai Lau if (!local_storage || local_storage->smap)
100d8db84d7SMartin KaFai Lau return 0;
101d8db84d7SMartin KaFai Lau
102d8db84d7SMartin KaFai Lau task_storage_result = 0;
103d8db84d7SMartin KaFai Lau
104d8db84d7SMartin KaFai Lau return is_self_unlink ? -EPERM : 0;
1052f94ac19SKP Singh }
1062f94ac19SKP Singh
1070ae6eff2SKP Singh SEC("lsm.s/inode_rename")
BPF_PROG(inode_rename,struct inode * old_dir,struct dentry * old_dentry,struct inode * new_dir,struct dentry * new_dentry,unsigned int flags)1082f94ac19SKP Singh int BPF_PROG(inode_rename, struct inode *old_dir, struct dentry *old_dentry,
1092f94ac19SKP Singh struct inode *new_dir, struct dentry *new_dentry,
1102f94ac19SKP Singh unsigned int flags)
1112f94ac19SKP Singh {
1122f94ac19SKP Singh struct local_storage *storage;
1132f94ac19SKP Singh int err;
1142f94ac19SKP Singh
1152f94ac19SKP Singh /* new_dentry->d_inode can be NULL when the inode is renamed to a file
1162f94ac19SKP Singh * that did not exist before. The helper should be able to handle this
1172f94ac19SKP Singh * NULL pointer.
1182f94ac19SKP Singh */
1192f94ac19SKP Singh bpf_inode_storage_get(&inode_storage_map, new_dentry->d_inode, 0,
120f0e5ba0bSKP Singh BPF_LOCAL_STORAGE_GET_F_CREATE);
1212f94ac19SKP Singh
1222f94ac19SKP Singh storage = bpf_inode_storage_get(&inode_storage_map, old_dentry->d_inode,
1232f94ac19SKP Singh 0, 0);
124cd324d7aSKP Singh if (!storage)
125cd324d7aSKP Singh return 0;
126cd324d7aSKP Singh
127f0e5ba0bSKP Singh if (storage->value != DUMMY_STORAGE_VALUE)
128cd324d7aSKP Singh inode_storage_result = -1;
129cd324d7aSKP Singh
1302f94ac19SKP Singh err = bpf_inode_storage_delete(&inode_storage_map, old_dentry->d_inode);
131f0e5ba0bSKP Singh if (!err)
132f0e5ba0bSKP Singh inode_storage_result = err;
133cd324d7aSKP Singh
134cd324d7aSKP Singh return 0;
135cd324d7aSKP Singh }
136cd324d7aSKP Singh
1370ae6eff2SKP Singh SEC("lsm.s/socket_bind")
BPF_PROG(socket_bind,struct socket * sock,struct sockaddr * address,int addrlen)138cd324d7aSKP Singh int BPF_PROG(socket_bind, struct socket *sock, struct sockaddr *address,
139cd324d7aSKP Singh int addrlen)
140cd324d7aSKP Singh {
141cd324d7aSKP Singh __u32 pid = bpf_get_current_pid_tgid() >> 32;
1429cde3beeSKP Singh struct local_storage *storage;
143*39f8a293SAlexei Starovoitov struct sock *sk = sock->sk;
144cd324d7aSKP Singh
145*39f8a293SAlexei Starovoitov if (pid != monitored_pid || !sk)
146cd324d7aSKP Singh return 0;
147cd324d7aSKP Singh
148*39f8a293SAlexei Starovoitov storage = bpf_sk_storage_get(&sk_storage_map, sk, 0, 0);
149cd324d7aSKP Singh if (!storage)
150cd324d7aSKP Singh return 0;
151cd324d7aSKP Singh
152cd324d7aSKP Singh sk_storage_result = -1;
1531f443d0fSMartin KaFai Lau if (storage->value != DUMMY_STORAGE_VALUE)
1541f443d0fSMartin KaFai Lau return 0;
155cd324d7aSKP Singh
1560e790cbbSJoanne Koong /* This tests that we can associate multiple elements
1570e790cbbSJoanne Koong * with the local storage.
1580e790cbbSJoanne Koong */
159*39f8a293SAlexei Starovoitov storage = bpf_sk_storage_get(&sk_storage_map2, sk, 0,
1600e790cbbSJoanne Koong BPF_LOCAL_STORAGE_GET_F_CREATE);
1610e790cbbSJoanne Koong if (!storage)
1620e790cbbSJoanne Koong return 0;
1630e790cbbSJoanne Koong
164*39f8a293SAlexei Starovoitov if (bpf_sk_storage_delete(&sk_storage_map2, sk))
1650e790cbbSJoanne Koong return 0;
1660e790cbbSJoanne Koong
167*39f8a293SAlexei Starovoitov storage = bpf_sk_storage_get(&sk_storage_map2, sk, 0,
1681f443d0fSMartin KaFai Lau BPF_LOCAL_STORAGE_GET_F_CREATE);
1691f443d0fSMartin KaFai Lau if (!storage)
1701f443d0fSMartin KaFai Lau return 0;
171f0e5ba0bSKP Singh
172*39f8a293SAlexei Starovoitov if (bpf_sk_storage_delete(&sk_storage_map, sk))
1731f443d0fSMartin KaFai Lau return 0;
1741f443d0fSMartin KaFai Lau
175d8db84d7SMartin KaFai Lau /* Ensure that the sk_storage_map is disconnected from the storage. */
176*39f8a293SAlexei Starovoitov if (!sk->sk_bpf_storage || sk->sk_bpf_storage->smap)
1771f443d0fSMartin KaFai Lau return 0;
1781f443d0fSMartin KaFai Lau
1791f443d0fSMartin KaFai Lau sk_storage_result = 0;
180cd324d7aSKP Singh return 0;
181cd324d7aSKP Singh }
182cd324d7aSKP Singh
1830ae6eff2SKP Singh SEC("lsm.s/socket_post_create")
BPF_PROG(socket_post_create,struct socket * sock,int family,int type,int protocol,int kern)184cd324d7aSKP Singh int BPF_PROG(socket_post_create, struct socket *sock, int family, int type,
185cd324d7aSKP Singh int protocol, int kern)
186cd324d7aSKP Singh {
187cd324d7aSKP Singh __u32 pid = bpf_get_current_pid_tgid() >> 32;
1889cde3beeSKP Singh struct local_storage *storage;
189*39f8a293SAlexei Starovoitov struct sock *sk = sock->sk;
190cd324d7aSKP Singh
191*39f8a293SAlexei Starovoitov if (pid != monitored_pid || !sk)
192cd324d7aSKP Singh return 0;
193cd324d7aSKP Singh
194*39f8a293SAlexei Starovoitov storage = bpf_sk_storage_get(&sk_storage_map, sk, 0,
195f0e5ba0bSKP Singh BPF_LOCAL_STORAGE_GET_F_CREATE);
196cd324d7aSKP Singh if (!storage)
197cd324d7aSKP Singh return 0;
198cd324d7aSKP Singh
199cd324d7aSKP Singh storage->value = DUMMY_STORAGE_VALUE;
200cd324d7aSKP Singh
201cd324d7aSKP Singh return 0;
202cd324d7aSKP Singh }
203cd324d7aSKP Singh
2049cde3beeSKP Singh /* This uses the local storage to remember the inode of the binary that a
2059cde3beeSKP Singh * process was originally executing.
2069cde3beeSKP Singh */
2070ae6eff2SKP Singh SEC("lsm.s/bprm_committed_creds")
BPF_PROG(exec,struct linux_binprm * bprm)2089cde3beeSKP Singh void BPF_PROG(exec, struct linux_binprm *bprm)
2099cde3beeSKP Singh {
2102f94ac19SKP Singh __u32 pid = bpf_get_current_pid_tgid() >> 32;
2119cde3beeSKP Singh struct local_storage *storage;
2129cde3beeSKP Singh
2132f94ac19SKP Singh if (pid != monitored_pid)
2142f94ac19SKP Singh return;
2152f94ac19SKP Singh
2169cde3beeSKP Singh storage = bpf_task_storage_get(&task_storage_map,
2179cde3beeSKP Singh bpf_get_current_task_btf(), 0,
2189cde3beeSKP Singh BPF_LOCAL_STORAGE_GET_F_CREATE);
2190ae6eff2SKP Singh if (storage)
2209cde3beeSKP Singh storage->exec_inode = bprm->file->f_inode;
2212f94ac19SKP Singh
2222f94ac19SKP Singh storage = bpf_inode_storage_get(&inode_storage_map, bprm->file->f_inode,
2232f94ac19SKP Singh 0, BPF_LOCAL_STORAGE_GET_F_CREATE);
2242f94ac19SKP Singh if (!storage)
2252f94ac19SKP Singh return;
2262f94ac19SKP Singh
2272f94ac19SKP Singh storage->value = DUMMY_STORAGE_VALUE;
2289cde3beeSKP Singh }
229