1 // SPDX-License-Identifier: GPL-2.0
2
3 /*
4 * Copyright 2020 Google LLC.
5 */
6
7 #include "vmlinux.h"
8 #include <errno.h>
9 #include <bpf/bpf_helpers.h>
10 #include <bpf/bpf_tracing.h>
11
12 char _license[] SEC("license") = "GPL";
13
14 #define DUMMY_STORAGE_VALUE 0xdeadbeef
15
16 int monitored_pid = 0;
17 int inode_storage_result = -1;
18 int sk_storage_result = -1;
19
20 struct local_storage {
21 struct inode *exec_inode;
22 __u32 value;
23 struct bpf_spin_lock lock;
24 };
25
26 struct {
27 __uint(type, BPF_MAP_TYPE_INODE_STORAGE);
28 __uint(map_flags, BPF_F_NO_PREALLOC);
29 __type(key, int);
30 __type(value, struct local_storage);
31 } inode_storage_map SEC(".maps");
32
33 struct {
34 __uint(type, BPF_MAP_TYPE_SK_STORAGE);
35 __uint(map_flags, BPF_F_NO_PREALLOC | BPF_F_CLONE);
36 __type(key, int);
37 __type(value, struct local_storage);
38 } sk_storage_map SEC(".maps");
39
40 struct {
41 __uint(type, BPF_MAP_TYPE_TASK_STORAGE);
42 __uint(map_flags, BPF_F_NO_PREALLOC);
43 __type(key, int);
44 __type(value, struct local_storage);
45 } task_storage_map SEC(".maps");
46
47 SEC("lsm/inode_unlink")
BPF_PROG(unlink_hook,struct inode * dir,struct dentry * victim)48 int BPF_PROG(unlink_hook, struct inode *dir, struct dentry *victim)
49 {
50 __u32 pid = bpf_get_current_pid_tgid() >> 32;
51 struct local_storage *storage;
52 bool is_self_unlink;
53
54 if (pid != monitored_pid)
55 return 0;
56
57 storage = bpf_task_storage_get(&task_storage_map,
58 bpf_get_current_task_btf(), 0, 0);
59 if (storage) {
60 /* Don't let an executable delete itself */
61 bpf_spin_lock(&storage->lock);
62 is_self_unlink = storage->exec_inode == victim->d_inode;
63 bpf_spin_unlock(&storage->lock);
64 if (is_self_unlink)
65 return -EPERM;
66 }
67
68 return 0;
69 }
70
71 SEC("lsm/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)72 int BPF_PROG(inode_rename, struct inode *old_dir, struct dentry *old_dentry,
73 struct inode *new_dir, struct dentry *new_dentry,
74 unsigned int flags)
75 {
76 __u32 pid = bpf_get_current_pid_tgid() >> 32;
77 struct local_storage *storage;
78 int err;
79
80 /* new_dentry->d_inode can be NULL when the inode is renamed to a file
81 * that did not exist before. The helper should be able to handle this
82 * NULL pointer.
83 */
84 bpf_inode_storage_get(&inode_storage_map, new_dentry->d_inode, 0,
85 BPF_LOCAL_STORAGE_GET_F_CREATE);
86
87 storage = bpf_inode_storage_get(&inode_storage_map, old_dentry->d_inode,
88 0, 0);
89 if (!storage)
90 return 0;
91
92 bpf_spin_lock(&storage->lock);
93 if (storage->value != DUMMY_STORAGE_VALUE)
94 inode_storage_result = -1;
95 bpf_spin_unlock(&storage->lock);
96
97 err = bpf_inode_storage_delete(&inode_storage_map, old_dentry->d_inode);
98 if (!err)
99 inode_storage_result = err;
100
101 return 0;
102 }
103
104 SEC("lsm/socket_bind")
BPF_PROG(socket_bind,struct socket * sock,struct sockaddr * address,int addrlen)105 int BPF_PROG(socket_bind, struct socket *sock, struct sockaddr *address,
106 int addrlen)
107 {
108 __u32 pid = bpf_get_current_pid_tgid() >> 32;
109 struct local_storage *storage;
110 int err;
111
112 if (pid != monitored_pid)
113 return 0;
114
115 storage = bpf_sk_storage_get(&sk_storage_map, sock->sk, 0,
116 BPF_LOCAL_STORAGE_GET_F_CREATE);
117 if (!storage)
118 return 0;
119
120 bpf_spin_lock(&storage->lock);
121 if (storage->value != DUMMY_STORAGE_VALUE)
122 sk_storage_result = -1;
123 bpf_spin_unlock(&storage->lock);
124
125 err = bpf_sk_storage_delete(&sk_storage_map, sock->sk);
126 if (!err)
127 sk_storage_result = err;
128
129 return 0;
130 }
131
132 SEC("lsm/socket_post_create")
BPF_PROG(socket_post_create,struct socket * sock,int family,int type,int protocol,int kern)133 int BPF_PROG(socket_post_create, struct socket *sock, int family, int type,
134 int protocol, int kern)
135 {
136 __u32 pid = bpf_get_current_pid_tgid() >> 32;
137 struct local_storage *storage;
138
139 if (pid != monitored_pid)
140 return 0;
141
142 storage = bpf_sk_storage_get(&sk_storage_map, sock->sk, 0,
143 BPF_LOCAL_STORAGE_GET_F_CREATE);
144 if (!storage)
145 return 0;
146
147 bpf_spin_lock(&storage->lock);
148 storage->value = DUMMY_STORAGE_VALUE;
149 bpf_spin_unlock(&storage->lock);
150
151 return 0;
152 }
153
154 /* This uses the local storage to remember the inode of the binary that a
155 * process was originally executing.
156 */
157 SEC("lsm/bprm_committed_creds")
BPF_PROG(exec,struct linux_binprm * bprm)158 void BPF_PROG(exec, struct linux_binprm *bprm)
159 {
160 __u32 pid = bpf_get_current_pid_tgid() >> 32;
161 struct local_storage *storage;
162
163 if (pid != monitored_pid)
164 return;
165
166 storage = bpf_task_storage_get(&task_storage_map,
167 bpf_get_current_task_btf(), 0,
168 BPF_LOCAL_STORAGE_GET_F_CREATE);
169 if (storage) {
170 bpf_spin_lock(&storage->lock);
171 storage->exec_inode = bprm->file->f_inode;
172 bpf_spin_unlock(&storage->lock);
173 }
174
175 storage = bpf_inode_storage_get(&inode_storage_map, bprm->file->f_inode,
176 0, BPF_LOCAL_STORAGE_GET_F_CREATE);
177 if (!storage)
178 return;
179
180 bpf_spin_lock(&storage->lock);
181 storage->value = DUMMY_STORAGE_VALUE;
182 bpf_spin_unlock(&storage->lock);
183 }
184