xref: /linux/tools/testing/selftests/bpf/progs/local_storage.c (revision 02680c23d7b3febe45ea3d4f9818c2b2dc89020a)
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")
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")
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")
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")
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")
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