xref: /linux/tools/testing/selftests/filesystems/fclog.c (revision 3a2a5b278fb8d4cdb3154b8e4a38352b945f96fd)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Author: Aleksa Sarai <cyphar@cyphar.com>
4  * Copyright (C) 2025 SUSE LLC.
5  */
6 
7 #include <assert.h>
8 #include <errno.h>
9 #include <sched.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <sys/mount.h>
15 
16 #include "../kselftest_harness.h"
17 
18 #define ASSERT_ERRNO(expected, _t, seen)				\
19 	__EXPECT(expected, #expected,					\
20 		({__typeof__(seen) _tmp_seen = (seen);			\
21 		  _tmp_seen >= 0 ? _tmp_seen : -errno; }), #seen, _t, 1)
22 
23 #define ASSERT_ERRNO_EQ(expected, seen) \
24 	ASSERT_ERRNO(expected, ==, seen)
25 
26 #define ASSERT_SUCCESS(seen) \
27 	ASSERT_ERRNO(0, <=, seen)
28 
FIXTURE(ns)29 FIXTURE(ns)
30 {
31 	int host_mntns;
32 };
33 
FIXTURE_SETUP(ns)34 FIXTURE_SETUP(ns)
35 {
36 	/* Stash the old mntns. */
37 	self->host_mntns = open("/proc/self/ns/mnt", O_RDONLY|O_CLOEXEC);
38 	ASSERT_SUCCESS(self->host_mntns);
39 
40 	/* Create a new mount namespace and make it private. */
41 	ASSERT_SUCCESS(unshare(CLONE_NEWNS));
42 	ASSERT_SUCCESS(mount(NULL, "/", NULL, MS_PRIVATE|MS_REC, NULL));
43 }
44 
FIXTURE_TEARDOWN(ns)45 FIXTURE_TEARDOWN(ns)
46 {
47 	ASSERT_SUCCESS(setns(self->host_mntns, CLONE_NEWNS));
48 	ASSERT_SUCCESS(close(self->host_mntns));
49 }
50 
TEST_F(ns,fscontext_log_enodata)51 TEST_F(ns, fscontext_log_enodata)
52 {
53 	int fsfd = fsopen("tmpfs", FSOPEN_CLOEXEC);
54 	ASSERT_SUCCESS(fsfd);
55 
56 	/* A brand new fscontext has no log entries. */
57 	char buf[128] = {};
58 	for (int i = 0; i < 16; i++)
59 		ASSERT_ERRNO_EQ(-ENODATA, read(fsfd, buf, sizeof(buf)));
60 
61 	ASSERT_SUCCESS(close(fsfd));
62 }
63 
TEST_F(ns,fscontext_log_errorfc)64 TEST_F(ns, fscontext_log_errorfc)
65 {
66 	int fsfd = fsopen("tmpfs", FSOPEN_CLOEXEC);
67 	ASSERT_SUCCESS(fsfd);
68 
69 	ASSERT_ERRNO_EQ(-EINVAL, fsconfig(fsfd, FSCONFIG_SET_STRING, "invalid-arg", "123", 0));
70 
71 	char buf[128] = {};
72 	ASSERT_SUCCESS(read(fsfd, buf, sizeof(buf)));
73 	EXPECT_STREQ("e tmpfs: Unknown parameter 'invalid-arg'\n", buf);
74 
75 	/* The message has been consumed. */
76 	ASSERT_ERRNO_EQ(-ENODATA, read(fsfd, buf, sizeof(buf)));
77 	ASSERT_SUCCESS(close(fsfd));
78 }
79 
TEST_F(ns,fscontext_log_errorfc_after_fsmount)80 TEST_F(ns, fscontext_log_errorfc_after_fsmount)
81 {
82 	int fsfd = fsopen("tmpfs", FSOPEN_CLOEXEC);
83 	ASSERT_SUCCESS(fsfd);
84 
85 	ASSERT_ERRNO_EQ(-EINVAL, fsconfig(fsfd, FSCONFIG_SET_STRING, "invalid-arg", "123", 0));
86 
87 	ASSERT_SUCCESS(fsconfig(fsfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0));
88 	int mfd = fsmount(fsfd, FSMOUNT_CLOEXEC, MOUNT_ATTR_NOEXEC | MOUNT_ATTR_NOSUID);
89 	ASSERT_SUCCESS(mfd);
90 	ASSERT_SUCCESS(move_mount(mfd, "", AT_FDCWD, "/tmp", MOVE_MOUNT_F_EMPTY_PATH));
91 
92 	/*
93 	 * The fscontext log should still contain data even after
94 	 * FSCONFIG_CMD_CREATE and fsmount().
95 	 */
96 	char buf[128] = {};
97 	ASSERT_SUCCESS(read(fsfd, buf, sizeof(buf)));
98 	EXPECT_STREQ("e tmpfs: Unknown parameter 'invalid-arg'\n", buf);
99 
100 	/* The message has been consumed. */
101 	ASSERT_ERRNO_EQ(-ENODATA, read(fsfd, buf, sizeof(buf)));
102 	ASSERT_SUCCESS(close(fsfd));
103 }
104 
TEST_F(ns,fscontext_log_emsgsize)105 TEST_F(ns, fscontext_log_emsgsize)
106 {
107 	int fsfd = fsopen("tmpfs", FSOPEN_CLOEXEC);
108 	ASSERT_SUCCESS(fsfd);
109 
110 	ASSERT_ERRNO_EQ(-EINVAL, fsconfig(fsfd, FSCONFIG_SET_STRING, "invalid-arg", "123", 0));
111 
112 	char buf[128] = {};
113 	/*
114 	 * Attempting to read a message with too small a buffer should not
115 	 * result in the message getting consumed.
116 	 */
117 	ASSERT_ERRNO_EQ(-EMSGSIZE, read(fsfd, buf, 0));
118 	ASSERT_ERRNO_EQ(-EMSGSIZE, read(fsfd, buf, 1));
119 	for (int i = 0; i < 16; i++)
120 		ASSERT_ERRNO_EQ(-EMSGSIZE, read(fsfd, buf, 16));
121 
122 	ASSERT_SUCCESS(read(fsfd, buf, sizeof(buf)));
123 	EXPECT_STREQ("e tmpfs: Unknown parameter 'invalid-arg'\n", buf);
124 
125 	/* The message has been consumed. */
126 	ASSERT_ERRNO_EQ(-ENODATA, read(fsfd, buf, sizeof(buf)));
127 	ASSERT_SUCCESS(close(fsfd));
128 }
129 
130 TEST_HARNESS_MAIN
131