1341f06fdSSong Liu // SPDX-License-Identifier: GPL-2.0
2341f06fdSSong Liu /* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
3341f06fdSSong Liu
4341f06fdSSong Liu #include <stdlib.h>
5341f06fdSSong Liu #include <sys/types.h>
6341f06fdSSong Liu #include <sys/xattr.h>
7341f06fdSSong Liu #include <linux/fsverity.h>
8341f06fdSSong Liu #include <unistd.h>
9341f06fdSSong Liu #include <test_progs.h>
10341f06fdSSong Liu #include "test_get_xattr.skel.h"
11341f06fdSSong Liu #include "test_fsverity.skel.h"
12341f06fdSSong Liu
13341f06fdSSong Liu static const char testfile[] = "/tmp/test_progs_fs_kfuncs";
14341f06fdSSong Liu
test_xattr(void)15341f06fdSSong Liu static void test_xattr(void)
16341f06fdSSong Liu {
17341f06fdSSong Liu struct test_get_xattr *skel = NULL;
18341f06fdSSong Liu int fd = -1, err;
19*8681156cSSong Liu int v[32];
20341f06fdSSong Liu
21341f06fdSSong Liu fd = open(testfile, O_CREAT | O_RDONLY, 0644);
22341f06fdSSong Liu if (!ASSERT_GE(fd, 0, "create_file"))
23341f06fdSSong Liu return;
24341f06fdSSong Liu
25341f06fdSSong Liu close(fd);
26341f06fdSSong Liu fd = -1;
27341f06fdSSong Liu
28341f06fdSSong Liu err = setxattr(testfile, "user.kfuncs", "hello", sizeof("hello"), 0);
29f77d7956SManu Bretelle if (err && errno == EOPNOTSUPP) {
30f77d7956SManu Bretelle printf("%s:SKIP:local fs doesn't support xattr (%d)\n"
31f77d7956SManu Bretelle "To run this test, make sure /tmp filesystem supports xattr.\n",
32f77d7956SManu Bretelle __func__, errno);
33f77d7956SManu Bretelle test__skip();
34f77d7956SManu Bretelle goto out;
35f77d7956SManu Bretelle }
36f77d7956SManu Bretelle
37341f06fdSSong Liu if (!ASSERT_OK(err, "setxattr"))
38341f06fdSSong Liu goto out;
39341f06fdSSong Liu
40341f06fdSSong Liu skel = test_get_xattr__open_and_load();
41341f06fdSSong Liu if (!ASSERT_OK_PTR(skel, "test_get_xattr__open_and_load"))
42341f06fdSSong Liu goto out;
43341f06fdSSong Liu
44341f06fdSSong Liu skel->bss->monitored_pid = getpid();
45341f06fdSSong Liu err = test_get_xattr__attach(skel);
46341f06fdSSong Liu
47341f06fdSSong Liu if (!ASSERT_OK(err, "test_get_xattr__attach"))
48341f06fdSSong Liu goto out;
49341f06fdSSong Liu
50341f06fdSSong Liu fd = open(testfile, O_RDONLY, 0644);
51341f06fdSSong Liu if (!ASSERT_GE(fd, 0, "open_file"))
52341f06fdSSong Liu goto out;
53341f06fdSSong Liu
54*8681156cSSong Liu ASSERT_EQ(skel->bss->found_xattr_from_file, 1, "found_xattr_from_file");
55*8681156cSSong Liu
56*8681156cSSong Liu /* Trigger security_inode_getxattr */
57*8681156cSSong Liu err = getxattr(testfile, "user.kfuncs", v, sizeof(v));
58*8681156cSSong Liu ASSERT_EQ(err, -1, "getxattr_return");
59*8681156cSSong Liu ASSERT_EQ(errno, EINVAL, "getxattr_errno");
60*8681156cSSong Liu ASSERT_EQ(skel->bss->found_xattr_from_dentry, 1, "found_xattr_from_dentry");
61341f06fdSSong Liu
62341f06fdSSong Liu out:
63341f06fdSSong Liu close(fd);
64341f06fdSSong Liu test_get_xattr__destroy(skel);
65341f06fdSSong Liu remove(testfile);
66341f06fdSSong Liu }
67341f06fdSSong Liu
68341f06fdSSong Liu #ifndef SHA256_DIGEST_SIZE
69341f06fdSSong Liu #define SHA256_DIGEST_SIZE 32
70341f06fdSSong Liu #endif
71341f06fdSSong Liu
test_fsverity(void)72341f06fdSSong Liu static void test_fsverity(void)
73341f06fdSSong Liu {
74341f06fdSSong Liu struct fsverity_enable_arg arg = {0};
75341f06fdSSong Liu struct test_fsverity *skel = NULL;
76341f06fdSSong Liu struct fsverity_digest *d;
77341f06fdSSong Liu int fd, err;
78341f06fdSSong Liu char buffer[4096];
79341f06fdSSong Liu
80341f06fdSSong Liu fd = open(testfile, O_CREAT | O_RDWR, 0644);
81341f06fdSSong Liu if (!ASSERT_GE(fd, 0, "create_file"))
82341f06fdSSong Liu return;
83341f06fdSSong Liu
84341f06fdSSong Liu /* Write random buffer, so the file is not empty */
85341f06fdSSong Liu err = write(fd, buffer, 4096);
86341f06fdSSong Liu if (!ASSERT_EQ(err, 4096, "write_file"))
87341f06fdSSong Liu goto out;
88341f06fdSSong Liu close(fd);
89341f06fdSSong Liu
90341f06fdSSong Liu /* Reopen read-only, otherwise FS_IOC_ENABLE_VERITY will fail */
91341f06fdSSong Liu fd = open(testfile, O_RDONLY, 0644);
92341f06fdSSong Liu if (!ASSERT_GE(fd, 0, "open_file1"))
93341f06fdSSong Liu return;
94341f06fdSSong Liu
95341f06fdSSong Liu /* Enable fsverity for the file.
96341f06fdSSong Liu * If the file system doesn't support verity, this will fail. Skip
97341f06fdSSong Liu * the test in such case.
98341f06fdSSong Liu */
99341f06fdSSong Liu arg.version = 1;
100341f06fdSSong Liu arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;
101341f06fdSSong Liu arg.block_size = 4096;
102341f06fdSSong Liu err = ioctl(fd, FS_IOC_ENABLE_VERITY, &arg);
103341f06fdSSong Liu if (err) {
104341f06fdSSong Liu printf("%s:SKIP:local fs doesn't support fsverity (%d)\n"
105341f06fdSSong Liu "To run this test, try enable CONFIG_FS_VERITY and enable FSVerity for the filesystem.\n",
106341f06fdSSong Liu __func__, errno);
107341f06fdSSong Liu test__skip();
108341f06fdSSong Liu goto out;
109341f06fdSSong Liu }
110341f06fdSSong Liu
111341f06fdSSong Liu skel = test_fsverity__open_and_load();
112341f06fdSSong Liu if (!ASSERT_OK_PTR(skel, "test_fsverity__open_and_load"))
113341f06fdSSong Liu goto out;
114341f06fdSSong Liu
115341f06fdSSong Liu /* Get fsverity_digest from ioctl */
116341f06fdSSong Liu d = (struct fsverity_digest *)skel->bss->expected_digest;
117341f06fdSSong Liu d->digest_algorithm = FS_VERITY_HASH_ALG_SHA256;
118341f06fdSSong Liu d->digest_size = SHA256_DIGEST_SIZE;
119341f06fdSSong Liu err = ioctl(fd, FS_IOC_MEASURE_VERITY, skel->bss->expected_digest);
120341f06fdSSong Liu if (!ASSERT_OK(err, "ioctl_FS_IOC_MEASURE_VERITY"))
121341f06fdSSong Liu goto out;
122341f06fdSSong Liu
123341f06fdSSong Liu skel->bss->monitored_pid = getpid();
124341f06fdSSong Liu err = test_fsverity__attach(skel);
125341f06fdSSong Liu if (!ASSERT_OK(err, "test_fsverity__attach"))
126341f06fdSSong Liu goto out;
127341f06fdSSong Liu
128341f06fdSSong Liu /* Reopen the file to trigger the program */
129341f06fdSSong Liu close(fd);
130341f06fdSSong Liu fd = open(testfile, O_RDONLY);
131341f06fdSSong Liu if (!ASSERT_GE(fd, 0, "open_file2"))
132341f06fdSSong Liu goto out;
133341f06fdSSong Liu
134341f06fdSSong Liu ASSERT_EQ(skel->bss->got_fsverity, 1, "got_fsverity");
135341f06fdSSong Liu ASSERT_EQ(skel->bss->digest_matches, 1, "digest_matches");
136341f06fdSSong Liu out:
137341f06fdSSong Liu close(fd);
138341f06fdSSong Liu test_fsverity__destroy(skel);
139341f06fdSSong Liu remove(testfile);
140341f06fdSSong Liu }
141341f06fdSSong Liu
test_fs_kfuncs(void)142341f06fdSSong Liu void test_fs_kfuncs(void)
143341f06fdSSong Liu {
144341f06fdSSong Liu if (test__start_subtest("xattr"))
145341f06fdSSong Liu test_xattr();
146341f06fdSSong Liu
147341f06fdSSong Liu if (test__start_subtest("fsverity"))
148341f06fdSSong Liu test_fsverity();
149341f06fdSSong Liu }
150