File Index
Files and directories
Sign in
FILE

fs_kfuncs.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/bpf/prog_tests/fs_kfuncs.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
  3
  4#include <stdlib.h>
  5#include <sys/types.h>
  6#include <sys/xattr.h>
  7#include <linux/fsverity.h>
  8#include <unistd.h>
  9#include <test_progs.h>
 10#include "test_get_xattr.skel.h"
 11#include "test_set_remove_xattr.skel.h"
 12#include "test_fsverity.skel.h"
 13
 14static const char testfile[] = "/tmp/test_progs_fs_kfuncs";
 15
 16static void test_get_xattr(const char *name, const char *value, bool allow_access)
 17{
 18	struct test_get_xattr *skel = NULL;
 19	int fd = -1, err;
 20	int v[32];
 21
 22	fd = open(testfile, O_CREAT | O_RDONLY, 0644);
 23	if (!ASSERT_GE(fd, 0, "create_file"))
 24		return;
 25
 26	close(fd);
 27	fd = -1;
 28
 29	err = setxattr(testfile, name, value, strlen(value) + 1, 0);
 30	if (err && errno == EOPNOTSUPP) {
 31		printf("%s:SKIP:local fs doesn't support xattr (%d)\n"
 32		       "To run this test, make sure /tmp filesystem supports xattr.\n",
 33		       __func__, errno);
 34		test__skip();
 35		goto out;
 36	}
 37
 38	if (!ASSERT_OK(err, "setxattr"))
 39		goto out;
 40
 41	skel = test_get_xattr__open_and_load();
 42	if (!ASSERT_OK_PTR(skel, "test_get_xattr__open_and_load"))
 43		goto out;
 44
 45	skel->bss->monitored_pid = getpid();
 46	err = test_get_xattr__attach(skel);
 47
 48	if (!ASSERT_OK(err, "test_get_xattr__attach"))
 49		goto out;
 50
 51	fd = open(testfile, O_RDONLY, 0644);
 52
 53	if (!ASSERT_GE(fd, 0, "open_file"))
 54		goto out;
 55
 56	/* Trigger security_inode_getxattr */
 57	err = getxattr(testfile, name, v, sizeof(v));
 58
 59	if (allow_access) {
 60		ASSERT_EQ(err, -1, "getxattr_return");
 61		ASSERT_EQ(errno, EINVAL, "getxattr_errno");
 62		ASSERT_EQ(skel->bss->found_xattr_from_file, 1, "found_xattr_from_file");
 63		ASSERT_EQ(skel->bss->found_xattr_from_dentry, 1, "found_xattr_from_dentry");
 64	} else {
 65		ASSERT_EQ(err, strlen(value) + 1, "getxattr_return");
 66		ASSERT_EQ(skel->bss->found_xattr_from_file, 0, "found_xattr_from_file");
 67		ASSERT_EQ(skel->bss->found_xattr_from_dentry, 0, "found_xattr_from_dentry");
 68	}
 69
 70out:
 71	close(fd);
 72	test_get_xattr__destroy(skel);
 73	remove(testfile);
 74}
 75
 76/* xattr value we will set to security.bpf.foo */
 77static const char value_foo[] = "hello";
 78
 79static void read_and_validate_foo(struct test_set_remove_xattr *skel)
 80{
 81	char value_out[32];
 82	int err;
 83
 84	err = getxattr(testfile, skel->rodata->xattr_foo, value_out, sizeof(value_out));
 85	ASSERT_EQ(err, sizeof(value_foo), "getxattr size foo");
 86	ASSERT_EQ(strncmp(value_out, value_foo, sizeof(value_foo)), 0, "strncmp value_foo");
 87}
 88
 89static void set_foo(struct test_set_remove_xattr *skel)
 90{
 91	ASSERT_OK(setxattr(testfile, skel->rodata->xattr_foo, value_foo, strlen(value_foo) + 1, 0),
 92		  "setxattr foo");
 93}
 94
 95static void validate_bar_match(struct test_set_remove_xattr *skel)
 96{
 97	char value_out[32];
 98	int err;
 99
100	err = getxattr(testfile, skel->rodata->xattr_bar, value_out, sizeof(value_out));
101	ASSERT_EQ(err, sizeof(skel->data->value_bar), "getxattr size bar");
102	ASSERT_EQ(strncmp(value_out, skel->data->value_bar, sizeof(skel->data->value_bar)), 0,
103		  "strncmp value_bar");
104}
105
106static void validate_bar_removed(struct test_set_remove_xattr *skel)
107{
108	char value_out[32];
109	int err;
110
111	err = getxattr(testfile, skel->rodata->xattr_bar, value_out, sizeof(value_out));
112	ASSERT_LT(err, 0, "getxattr size bar should fail");
113}
114
115static void test_set_remove_xattr(void)
116{
117	struct test_set_remove_xattr *skel = NULL;
118	int fd = -1, err;
119
120	fd = open(testfile, O_CREAT | O_RDONLY, 0644);
121	if (!ASSERT_GE(fd, 0, "create_file"))
122		return;
123
124	close(fd);
125	fd = -1;
126
127	skel = test_set_remove_xattr__open_and_load();
128	if (!ASSERT_OK_PTR(skel, "test_set_remove_xattr__open_and_load"))
129		return;
130
131	/* Set security.bpf.foo to "hello" */
132	err = setxattr(testfile, skel->rodata->xattr_foo, value_foo, strlen(value_foo) + 1, 0);
133	if (err && errno == EOPNOTSUPP) {
134		printf("%s:SKIP:local fs doesn't support xattr (%d)\n"
135		       "To run this test, make sure /tmp filesystem supports xattr.\n",
136		       __func__, errno);
137		test__skip();
138		goto out;
139	}
140
141	if (!ASSERT_OK(err, "setxattr"))
142		goto out;
143
144	skel->bss->monitored_pid = getpid();
145	err = test_set_remove_xattr__attach(skel);
146	if (!ASSERT_OK(err, "test_set_remove_xattr__attach"))
147		goto out;
148
149	/* First, test not _locked version of the kfuncs with getxattr. */
150
151	/* Read security.bpf.foo and trigger test_inode_getxattr. This
152	 * bpf program will set security.bpf.bar to "world".
153	 */
154	read_and_validate_foo(skel);
155	validate_bar_match(skel);
156
157	/* Read security.bpf.foo and trigger test_inode_getxattr again.
158	 * This will remove xattr security.bpf.bar.
159	 */
160	read_and_validate_foo(skel);
161	validate_bar_removed(skel);
162
163	ASSERT_TRUE(skel->bss->set_security_bpf_bar_success, "set_security_bpf_bar_success");
164	ASSERT_TRUE(skel->bss->remove_security_bpf_bar_success, "remove_security_bpf_bar_success");
165	ASSERT_TRUE(skel->bss->set_security_selinux_fail, "set_security_selinux_fail");
166	ASSERT_TRUE(skel->bss->remove_security_selinux_fail, "remove_security_selinux_fail");
167
168	/* Second, test _locked version of the kfuncs, with setxattr */
169
170	/* Set security.bpf.foo and trigger test_inode_setxattr. This
171	 * bpf program will set security.bpf.bar to "world".
172	 */
173	set_foo(skel);
174	validate_bar_match(skel);
175
176	/* Set security.bpf.foo and trigger test_inode_setxattr again.
177	 * This will remove xattr security.bpf.bar.
178	 */
179	set_foo(skel);
180	validate_bar_removed(skel);
181
182	ASSERT_TRUE(skel->bss->locked_set_security_bpf_bar_success,
183		    "locked_set_security_bpf_bar_success");
184	ASSERT_TRUE(skel->bss->locked_remove_security_bpf_bar_success,
185		    "locked_remove_security_bpf_bar_success");
186	ASSERT_TRUE(skel->bss->locked_set_security_selinux_fail,
187		    "locked_set_security_selinux_fail");
188	ASSERT_TRUE(skel->bss->locked_remove_security_selinux_fail,
189		    "locked_remove_security_selinux_fail");
190
191out:
192	close(fd);
193	test_set_remove_xattr__destroy(skel);
194	remove(testfile);
195}
196
197#ifndef SHA256_DIGEST_SIZE
198#define SHA256_DIGEST_SIZE      32
199#endif
200
201static void test_fsverity(void)
202{
203	struct fsverity_enable_arg arg = {0};
204	struct test_fsverity *skel = NULL;
205	struct fsverity_digest *d;
206	int fd, err;
207	char buffer[4096];
208
209	fd = open(testfile, O_CREAT | O_RDWR, 0644);
210	if (!ASSERT_GE(fd, 0, "create_file"))
211		return;
212
213	/* Write random buffer, so the file is not empty */
214	err = write(fd, buffer, 4096);
215	if (!ASSERT_EQ(err, 4096, "write_file"))
216		goto out;
217	close(fd);
218
219	/* Reopen read-only, otherwise FS_IOC_ENABLE_VERITY will fail */
220	fd = open(testfile, O_RDONLY, 0644);
221	if (!ASSERT_GE(fd, 0, "open_file1"))
222		return;
223
224	/* Enable fsverity for the file.
225	 * If the file system doesn't support verity, this will fail. Skip
226	 * the test in such case.
227	 */
228	arg.version = 1;
229	arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;
230	arg.block_size = 4096;
231	err = ioctl(fd, FS_IOC_ENABLE_VERITY, &arg);
232	if (err) {
233		printf("%s:SKIP:local fs doesn't support fsverity (%d)\n"
234		       "To run this test, try enable CONFIG_FS_VERITY and enable FSVerity for the filesystem.\n",
235		       __func__, errno);
236		test__skip();
237		goto out;
238	}
239
240	skel = test_fsverity__open_and_load();
241	if (!ASSERT_OK_PTR(skel, "test_fsverity__open_and_load"))
242		goto out;
243
244	/* Get fsverity_digest from ioctl */
245	d = (struct fsverity_digest *)skel->bss->expected_digest;
246	d->digest_algorithm = FS_VERITY_HASH_ALG_SHA256;
247	d->digest_size = SHA256_DIGEST_SIZE;
248	err = ioctl(fd, FS_IOC_MEASURE_VERITY, skel->bss->expected_digest);
249	if (!ASSERT_OK(err, "ioctl_FS_IOC_MEASURE_VERITY"))
250		goto out;
251
252	skel->bss->monitored_pid = getpid();
253	err = test_fsverity__attach(skel);
254	if (!ASSERT_OK(err, "test_fsverity__attach"))
255		goto out;
256
257	/* Reopen the file to trigger the program */
258	close(fd);
259	fd = open(testfile, O_RDONLY);
260	if (!ASSERT_GE(fd, 0, "open_file2"))
261		goto out;
262
263	ASSERT_EQ(skel->bss->got_fsverity, 1, "got_fsverity");
264	ASSERT_EQ(skel->bss->digest_matches, 1, "digest_matches");
265out:
266	close(fd);
267	test_fsverity__destroy(skel);
268	remove(testfile);
269}
270
271void test_fs_kfuncs(void)
272{
273	/* Matches xattr_names in progs/test_get_xattr.c */
274	if (test__start_subtest("user_xattr"))
275		test_get_xattr("user.kfuncs", "hello", true);
276
277	if (test__start_subtest("security_bpf_xattr"))
278		test_get_xattr("security.bpf.xxx", "hello", true);
279
280	if (test__start_subtest("security_bpf_xattr_error"))
281		test_get_xattr("security.bpf", "hello", false);
282
283	if (test__start_subtest("security_selinux_xattr_error"))
284		test_get_xattr("security.selinux", "hello", false);
285
286	if (test__start_subtest("set_remove_xattr"))
287		test_set_remove_xattr();
288
289	if (test__start_subtest("fsverity"))
290		test_fsverity();
291}
~/ Read-only file preview.