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 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 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 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 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 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