xref: /linux/tools/testing/selftests/filesystems/fuse/fusectl_test.c (revision 6238729bfce13f94b701766996a5d116d2df8bff)
1*1a7b1378SChen Linxuan // SPDX-License-Identifier: GPL-2.0-or-later
2*1a7b1378SChen Linxuan // Copyright (c) 2025 Chen Linxuan <chenlinxuan@uniontech.com>
3*1a7b1378SChen Linxuan 
4*1a7b1378SChen Linxuan #define _GNU_SOURCE
5*1a7b1378SChen Linxuan 
6*1a7b1378SChen Linxuan #include <errno.h>
7*1a7b1378SChen Linxuan #include <fcntl.h>
8*1a7b1378SChen Linxuan #include <stdio.h>
9*1a7b1378SChen Linxuan #include <stdlib.h>
10*1a7b1378SChen Linxuan #include <string.h>
11*1a7b1378SChen Linxuan #include <sys/mount.h>
12*1a7b1378SChen Linxuan #include <sys/stat.h>
13*1a7b1378SChen Linxuan #include <sys/types.h>
14*1a7b1378SChen Linxuan #include <sys/wait.h>
15*1a7b1378SChen Linxuan #include <unistd.h>
16*1a7b1378SChen Linxuan #include <dirent.h>
17*1a7b1378SChen Linxuan #include <sched.h>
18*1a7b1378SChen Linxuan #include <linux/limits.h>
19*1a7b1378SChen Linxuan 
20*1a7b1378SChen Linxuan #include "../../kselftest_harness.h"
21*1a7b1378SChen Linxuan 
22*1a7b1378SChen Linxuan #define FUSECTL_MOUNTPOINT "/sys/fs/fuse/connections"
23*1a7b1378SChen Linxuan #define FUSE_MOUNTPOINT "/tmp/fuse_mnt_XXXXXX"
24*1a7b1378SChen Linxuan #define FUSE_DEVICE "/dev/fuse"
25*1a7b1378SChen Linxuan #define FUSECTL_TEST_VALUE "1"
26*1a7b1378SChen Linxuan 
write_file(struct __test_metadata * const _metadata,const char * path,const char * val)27*1a7b1378SChen Linxuan static void write_file(struct __test_metadata *const _metadata,
28*1a7b1378SChen Linxuan 		       const char *path, const char *val)
29*1a7b1378SChen Linxuan {
30*1a7b1378SChen Linxuan 	int fd = open(path, O_WRONLY);
31*1a7b1378SChen Linxuan 	size_t len = strlen(val);
32*1a7b1378SChen Linxuan 
33*1a7b1378SChen Linxuan 	ASSERT_GE(fd, 0);
34*1a7b1378SChen Linxuan 	ASSERT_EQ(write(fd, val, len), len);
35*1a7b1378SChen Linxuan 	ASSERT_EQ(close(fd), 0);
36*1a7b1378SChen Linxuan }
37*1a7b1378SChen Linxuan 
FIXTURE(fusectl)38*1a7b1378SChen Linxuan FIXTURE(fusectl){
39*1a7b1378SChen Linxuan 	char fuse_mountpoint[sizeof(FUSE_MOUNTPOINT)];
40*1a7b1378SChen Linxuan 	int connection;
41*1a7b1378SChen Linxuan };
42*1a7b1378SChen Linxuan 
FIXTURE_SETUP(fusectl)43*1a7b1378SChen Linxuan FIXTURE_SETUP(fusectl)
44*1a7b1378SChen Linxuan {
45*1a7b1378SChen Linxuan 	const char *fuse_mnt_prog = "./fuse_mnt";
46*1a7b1378SChen Linxuan 	int status, pid;
47*1a7b1378SChen Linxuan 	struct stat statbuf;
48*1a7b1378SChen Linxuan 	uid_t uid = getuid();
49*1a7b1378SChen Linxuan 	gid_t gid = getgid();
50*1a7b1378SChen Linxuan 	char buf[32];
51*1a7b1378SChen Linxuan 
52*1a7b1378SChen Linxuan 	/* Setup userns */
53*1a7b1378SChen Linxuan 	ASSERT_EQ(unshare(CLONE_NEWNS|CLONE_NEWUSER), 0);
54*1a7b1378SChen Linxuan 	sprintf(buf, "0 %d 1", uid);
55*1a7b1378SChen Linxuan 	write_file(_metadata, "/proc/self/uid_map", buf);
56*1a7b1378SChen Linxuan 	write_file(_metadata, "/proc/self/setgroups", "deny");
57*1a7b1378SChen Linxuan 	sprintf(buf, "0 %d 1", gid);
58*1a7b1378SChen Linxuan 	write_file(_metadata, "/proc/self/gid_map", buf);
59*1a7b1378SChen Linxuan 	ASSERT_EQ(mount("", "/", NULL, MS_REC|MS_PRIVATE, NULL), 0);
60*1a7b1378SChen Linxuan 
61*1a7b1378SChen Linxuan 	strcpy(self->fuse_mountpoint, FUSE_MOUNTPOINT);
62*1a7b1378SChen Linxuan 
63*1a7b1378SChen Linxuan 	if (!mkdtemp(self->fuse_mountpoint))
64*1a7b1378SChen Linxuan 		SKIP(return,
65*1a7b1378SChen Linxuan 		     "Failed to create FUSE mountpoint %s",
66*1a7b1378SChen Linxuan 		     strerror(errno));
67*1a7b1378SChen Linxuan 
68*1a7b1378SChen Linxuan 	if (access(FUSECTL_MOUNTPOINT, F_OK))
69*1a7b1378SChen Linxuan 		SKIP(return,
70*1a7b1378SChen Linxuan 		     "FUSE control filesystem not mounted");
71*1a7b1378SChen Linxuan 
72*1a7b1378SChen Linxuan 	pid = fork();
73*1a7b1378SChen Linxuan 	if (pid < 0)
74*1a7b1378SChen Linxuan 		SKIP(return,
75*1a7b1378SChen Linxuan 		     "Failed to fork FUSE daemon process: %s",
76*1a7b1378SChen Linxuan 		     strerror(errno));
77*1a7b1378SChen Linxuan 
78*1a7b1378SChen Linxuan 	if (pid == 0) {
79*1a7b1378SChen Linxuan 		execlp(fuse_mnt_prog, fuse_mnt_prog, self->fuse_mountpoint, NULL);
80*1a7b1378SChen Linxuan 		exit(errno);
81*1a7b1378SChen Linxuan 	}
82*1a7b1378SChen Linxuan 
83*1a7b1378SChen Linxuan 	waitpid(pid, &status, 0);
84*1a7b1378SChen Linxuan 	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
85*1a7b1378SChen Linxuan 		SKIP(return,
86*1a7b1378SChen Linxuan 		     "Failed to start FUSE daemon %s",
87*1a7b1378SChen Linxuan 		     strerror(WEXITSTATUS(status)));
88*1a7b1378SChen Linxuan 	}
89*1a7b1378SChen Linxuan 
90*1a7b1378SChen Linxuan 	if (stat(self->fuse_mountpoint, &statbuf))
91*1a7b1378SChen Linxuan 		SKIP(return,
92*1a7b1378SChen Linxuan 		     "Failed to stat FUSE mountpoint %s",
93*1a7b1378SChen Linxuan 		     strerror(errno));
94*1a7b1378SChen Linxuan 
95*1a7b1378SChen Linxuan 	self->connection = statbuf.st_dev;
96*1a7b1378SChen Linxuan }
97*1a7b1378SChen Linxuan 
FIXTURE_TEARDOWN(fusectl)98*1a7b1378SChen Linxuan FIXTURE_TEARDOWN(fusectl)
99*1a7b1378SChen Linxuan {
100*1a7b1378SChen Linxuan 	umount2(self->fuse_mountpoint, MNT_DETACH);
101*1a7b1378SChen Linxuan 	rmdir(self->fuse_mountpoint);
102*1a7b1378SChen Linxuan }
103*1a7b1378SChen Linxuan 
TEST_F(fusectl,abort)104*1a7b1378SChen Linxuan TEST_F(fusectl, abort)
105*1a7b1378SChen Linxuan {
106*1a7b1378SChen Linxuan 	char path_buf[PATH_MAX];
107*1a7b1378SChen Linxuan 	int abort_fd, test_fd, ret;
108*1a7b1378SChen Linxuan 
109*1a7b1378SChen Linxuan 	sprintf(path_buf, "/sys/fs/fuse/connections/%d/abort", self->connection);
110*1a7b1378SChen Linxuan 
111*1a7b1378SChen Linxuan 	ASSERT_EQ(0, access(path_buf, F_OK));
112*1a7b1378SChen Linxuan 
113*1a7b1378SChen Linxuan 	abort_fd = open(path_buf, O_WRONLY);
114*1a7b1378SChen Linxuan 	ASSERT_GE(abort_fd, 0);
115*1a7b1378SChen Linxuan 
116*1a7b1378SChen Linxuan 	sprintf(path_buf, "%s/test", self->fuse_mountpoint);
117*1a7b1378SChen Linxuan 
118*1a7b1378SChen Linxuan 	test_fd = open(path_buf, O_RDWR);
119*1a7b1378SChen Linxuan 	ASSERT_GE(test_fd, 0);
120*1a7b1378SChen Linxuan 
121*1a7b1378SChen Linxuan 	ret = read(test_fd, path_buf, sizeof(path_buf));
122*1a7b1378SChen Linxuan 	ASSERT_EQ(ret, 0);
123*1a7b1378SChen Linxuan 
124*1a7b1378SChen Linxuan 	ret = write(test_fd, "test", sizeof("test"));
125*1a7b1378SChen Linxuan 	ASSERT_EQ(ret, sizeof("test"));
126*1a7b1378SChen Linxuan 
127*1a7b1378SChen Linxuan 	ret = lseek(test_fd, 0, SEEK_SET);
128*1a7b1378SChen Linxuan 	ASSERT_GE(ret, 0);
129*1a7b1378SChen Linxuan 
130*1a7b1378SChen Linxuan 	ret = write(abort_fd, FUSECTL_TEST_VALUE, sizeof(FUSECTL_TEST_VALUE));
131*1a7b1378SChen Linxuan 	ASSERT_GT(ret, 0);
132*1a7b1378SChen Linxuan 
133*1a7b1378SChen Linxuan 	close(abort_fd);
134*1a7b1378SChen Linxuan 
135*1a7b1378SChen Linxuan 	ret = read(test_fd, path_buf, sizeof(path_buf));
136*1a7b1378SChen Linxuan 	ASSERT_EQ(ret, -1);
137*1a7b1378SChen Linxuan 	ASSERT_EQ(errno, ENOTCONN);
138*1a7b1378SChen Linxuan }
139*1a7b1378SChen Linxuan 
140*1a7b1378SChen Linxuan TEST_HARNESS_MAIN
141