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_fsverity.skel.h"
12
13static const char testfile[] = "/tmp/test_progs_fs_kfuncs";
14
15static void test_xattr(void)
16{
17	struct test_get_xattr *skel = NULL;
18	int fd = -1, err;
19
20	fd = open(testfile, O_CREAT | O_RDONLY, 0644);
21	if (!ASSERT_GE(fd, 0, "create_file"))
22		return;
23
24	close(fd);
25	fd = -1;
26
27	err = setxattr(testfile, "user.kfuncs", "hello", sizeof("hello"), 0);
28	if (err && errno == EOPNOTSUPP) {
29		printf("%s:SKIP:local fs doesn't support xattr (%d)\n"
30		       "To run this test, make sure /tmp filesystem supports xattr.\n",
31		       __func__, errno);
32		test__skip();
33		goto out;
34	}
35
36	if (!ASSERT_OK(err, "setxattr"))
37		goto out;
38
39	skel = test_get_xattr__open_and_load();
40	if (!ASSERT_OK_PTR(skel, "test_get_xattr__open_and_load"))
41		goto out;
42
43	skel->bss->monitored_pid = getpid();
44	err = test_get_xattr__attach(skel);
45
46	if (!ASSERT_OK(err, "test_get_xattr__attach"))
47		goto out;
48
49	fd = open(testfile, O_RDONLY, 0644);
50	if (!ASSERT_GE(fd, 0, "open_file"))
51		goto out;
52
53	ASSERT_EQ(skel->bss->found_xattr, 1, "found_xattr");
54
55out:
56	close(fd);
57	test_get_xattr__destroy(skel);
58	remove(testfile);
59}
60
61#ifndef SHA256_DIGEST_SIZE
62#define SHA256_DIGEST_SIZE      32
63#endif
64
65static void test_fsverity(void)
66{
67	struct fsverity_enable_arg arg = {0};
68	struct test_fsverity *skel = NULL;
69	struct fsverity_digest *d;
70	int fd, err;
71	char buffer[4096];
72
73	fd = open(testfile, O_CREAT | O_RDWR, 0644);
74	if (!ASSERT_GE(fd, 0, "create_file"))
75		return;
76
77	/* Write random buffer, so the file is not empty */
78	err = write(fd, buffer, 4096);
79	if (!ASSERT_EQ(err, 4096, "write_file"))
80		goto out;
81	close(fd);
82
83	/* Reopen read-only, otherwise FS_IOC_ENABLE_VERITY will fail */
84	fd = open(testfile, O_RDONLY, 0644);
85	if (!ASSERT_GE(fd, 0, "open_file1"))
86		return;
87
88	/* Enable fsverity for the file.
89	 * If the file system doesn't support verity, this will fail. Skip
90	 * the test in such case.
91	 */
92	arg.version = 1;
93	arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;
94	arg.block_size = 4096;
95	err = ioctl(fd, FS_IOC_ENABLE_VERITY, &arg);
96	if (err) {
97		printf("%s:SKIP:local fs doesn't support fsverity (%d)\n"
98		       "To run this test, try enable CONFIG_FS_VERITY and enable FSVerity for the filesystem.\n",
99		       __func__, errno);
100		test__skip();
101		goto out;
102	}
103
104	skel = test_fsverity__open_and_load();
105	if (!ASSERT_OK_PTR(skel, "test_fsverity__open_and_load"))
106		goto out;
107
108	/* Get fsverity_digest from ioctl */
109	d = (struct fsverity_digest *)skel->bss->expected_digest;
110	d->digest_algorithm = FS_VERITY_HASH_ALG_SHA256;
111	d->digest_size = SHA256_DIGEST_SIZE;
112	err = ioctl(fd, FS_IOC_MEASURE_VERITY, skel->bss->expected_digest);
113	if (!ASSERT_OK(err, "ioctl_FS_IOC_MEASURE_VERITY"))
114		goto out;
115
116	skel->bss->monitored_pid = getpid();
117	err = test_fsverity__attach(skel);
118	if (!ASSERT_OK(err, "test_fsverity__attach"))
119		goto out;
120
121	/* Reopen the file to trigger the program */
122	close(fd);
123	fd = open(testfile, O_RDONLY);
124	if (!ASSERT_GE(fd, 0, "open_file2"))
125		goto out;
126
127	ASSERT_EQ(skel->bss->got_fsverity, 1, "got_fsverity");
128	ASSERT_EQ(skel->bss->digest_matches, 1, "digest_matches");
129out:
130	close(fd);
131	test_fsverity__destroy(skel);
132	remove(testfile);
133}
134
135void test_fs_kfuncs(void)
136{
137	if (test__start_subtest("xattr"))
138		test_xattr();
139
140	if (test__start_subtest("fsverity"))
141		test_fsverity();
142}
143