• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2024 FUJITSU LIMITED. All Rights Reserved.
4  * Author: Yang Xu <xuyang2018.jy@fujitsu.com>
5  * Copyright (C) 2024 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
6  */
7 
8 /*\
9  * [Description]
10  *
11  * Verify that unlink(2) fails with EPERM when target file is marked as
12  * immutable or append-only.
13  */
14 
15 #include <sys/ioctl.h>
16 #include "tst_test.h"
17 #include "lapi/fs.h"
18 
19 #define MNTPOINT "mnt"
20 #define TEST_EPERM_IMMUTABLE MNTPOINT"/test_eperm_immutable"
21 #define TEST_EPERM_APPEND_ONLY MNTPOINT"/test_eperm_append_only"
22 
23 static int fd_immutable = -1;
24 static int fd_append_only = -1;
25 
26 static struct test_case_t {
27 	char *filename;
28 	int *fd;
29 	int flag;
30 	char *desc;
31 } tcases[] = {
32 	{TEST_EPERM_IMMUTABLE, &fd_immutable, FS_IMMUTABLE_FL,
33 		"target file is immutable"},
34 	{TEST_EPERM_APPEND_ONLY, &fd_append_only, FS_APPEND_FL,
35 		"target file is append-only"},
36 };
37 
setup_inode_flag(const int fd,const int flag,const int set)38 static void setup_inode_flag(const int fd, const int flag, const int set)
39 {
40 	int attr;
41 
42 	SAFE_IOCTL(fd, FS_IOC_GETFLAGS, &attr);
43 
44 	if (set)
45 		attr |= flag;
46 	else
47 		attr &= ~flag;
48 
49 	SAFE_IOCTL(fd, FS_IOC_SETFLAGS, &attr);
50 }
51 
setup(void)52 static void setup(void)
53 {
54 	int attr;
55 
56 	/* inode attributes in tmpfs are supported from kernel 6.0
57 	 * https://lore.kernel.org/all/20220715015912.2560575-1-tytso@mit.edu/
58 	 */
59 	if (!strcmp(tst_device->fs_type, "tmpfs") && tst_kvercmp(6, 0, 0) < 0)
60 		tst_brk(TCONF, "FS_IOC_GETFLAGS on tmpfs not supported for kernel<6.0");
61 
62 	fd_immutable = SAFE_CREAT(TEST_EPERM_IMMUTABLE, 0600);
63 	TEST(ioctl(fd_immutable, FS_IOC_GETFLAGS, &attr));
64 
65 	if (TST_RET == -1 && TST_ERR == ENOTTY) {
66 		SAFE_CLOSE(fd_immutable);
67 
68 		tst_brk(TBROK, "Inode attributes not supported by '%s'",
69 			tst_device->fs_type);
70 	}
71 
72 	attr |= FS_IMMUTABLE_FL;
73 	SAFE_IOCTL(fd_immutable, FS_IOC_SETFLAGS, &attr);
74 
75 	fd_append_only = SAFE_CREAT(TEST_EPERM_APPEND_ONLY, 0600);
76 	setup_inode_flag(fd_append_only, FS_APPEND_FL, 1);
77 }
78 
cleanup(void)79 static void cleanup(void)
80 {
81 	if (fd_immutable != -1) {
82 		setup_inode_flag(fd_immutable, FS_IMMUTABLE_FL, 0);
83 		SAFE_CLOSE(fd_immutable);
84 	}
85 
86 	if (fd_append_only != -1) {
87 		setup_inode_flag(fd_append_only, FS_APPEND_FL, 0);
88 		SAFE_CLOSE(fd_append_only);
89 	}
90 }
91 
verify_unlink(unsigned int i)92 static void verify_unlink(unsigned int i)
93 {
94 	struct test_case_t *tc = &tcases[i];
95 
96 	TST_EXP_FAIL(unlink(tc->filename), EPERM, "%s", tc->desc);
97 
98 	/* If unlink() succeeded unexpectedly, test file should be restored. */
99 	if (!TST_RET) {
100 		*(tc->fd) = SAFE_CREAT(tc->filename, 0600);
101 		setup_inode_flag(*(tc->fd), tc->flag, 1);
102 	}
103 }
104 
105 static struct tst_test test = {
106 	.setup = setup,
107 	.tcnt = ARRAY_SIZE(tcases),
108 	.cleanup = cleanup,
109 	.test = verify_unlink,
110 	.mntpoint = MNTPOINT,
111 	.needs_root = 1,
112 	.mount_device = 1,
113 	.all_filesystems = 1,
114 	.skip_filesystems = (const char *const[]) {
115 		"fuse",
116 		"exfat",
117 		"vfat",
118 		"ntfs",
119 		NULL
120 	},
121 };
122