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;
14339f8a293SAlexei Starovoitov 	struct sock *sk = sock->sk;
144cd324d7aSKP Singh 
14539f8a293SAlexei Starovoitov 	if (pid != monitored_pid || !sk)
146cd324d7aSKP Singh 		return 0;
147cd324d7aSKP Singh 
14839f8a293SAlexei 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 	 */
15939f8a293SAlexei 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 
16439f8a293SAlexei Starovoitov 	if (bpf_sk_storage_delete(&sk_storage_map2, sk))
1650e790cbbSJoanne Koong 		return 0;
1660e790cbbSJoanne Koong 
16739f8a293SAlexei 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 
17239f8a293SAlexei 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. */
17639f8a293SAlexei 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;
18939f8a293SAlexei Starovoitov 	struct sock *sk = sock->sk;
190cd324d7aSKP Singh 
19139f8a293SAlexei Starovoitov 	if (pid != monitored_pid || !sk)
192cd324d7aSKP Singh 		return 0;
193cd324d7aSKP Singh 
19439f8a293SAlexei 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