xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/setxattr/setxattr02.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2011 Red Hat, Inc.
4  * Copyright (c) Linux Test Project, 2011-2024
5  */
6 
7 /*\
8  * [Description]
9  *
10  * In the user.* namespace, only regular files and directories can
11  * have extended attributes. Otherwise setxattr(2) will return -1
12  * and set errno to EPERM.
13  *
14  * - SUCCEED - set attribute to a regular file
15  * - SUCCEED - set attribute to a directory
16  * - EEXIST - set attribute to a symlink which points to the regular file
17  * - EPERM - set attribute to a FIFO
18  * - EPERM - set attribute to a char special file
19  * - EPERM - set attribute to a block special file
20  * - EPERM - set attribute to a UNIX domain socket
21  */
22 
23 #include "config.h"
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <sys/sysmacros.h>
27 #include <sys/wait.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31 #include <signal.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #ifdef HAVE_SYS_XATTR_H
36 # include <sys/xattr.h>
37 #endif
38 #include "tst_test.h"
39 
40 #ifdef HAVE_SYS_XATTR_H
41 #define XATTR_TEST_KEY "user.testkey"
42 #define XATTR_TEST_VALUE "this is a test value"
43 #define XATTR_TEST_VALUE_SIZE 20
44 
45 #define OFFSET    10
46 #define FILENAME "setxattr02testfile"
47 #define DIRNAME  "setxattr02testdir"
48 #define SYMLINK  "setxattr02symlink"
49 #define FIFO     "setxattr02fifo"
50 #define CHR      "setxattr02chr"
51 #define BLK      "setxattr02blk"
52 #define SOCK     "setxattr02sock"
53 
54 struct test_case {
55 	char *fname;
56 	char *key;
57 	char *value;
58 	size_t size;
59 	int flags;
60 	int exp_err;
61 	int needskeyset;
62 };
63 static struct test_case tc[] = {
64 	{			/* case 00, set attr to reg */
65 	 .fname = FILENAME,
66 	 .key = XATTR_TEST_KEY,
67 	 .value = XATTR_TEST_VALUE,
68 	 .size = XATTR_TEST_VALUE_SIZE,
69 	 .flags = XATTR_CREATE,
70 	 .exp_err = 0,
71 	 },
72 	{			/* case 01, set attr to dir */
73 	 .fname = DIRNAME,
74 	 .key = XATTR_TEST_KEY,
75 	 .value = XATTR_TEST_VALUE,
76 	 .size = XATTR_TEST_VALUE_SIZE,
77 	 .flags = XATTR_CREATE,
78 	 .exp_err = 0,
79 	 },
80 	{			/* case 02, set attr to symlink */
81 	 .fname = SYMLINK,
82 	 .key = XATTR_TEST_KEY,
83 	 .value = XATTR_TEST_VALUE,
84 	 .size = XATTR_TEST_VALUE_SIZE,
85 	 .flags = XATTR_CREATE,
86 	 .exp_err = EEXIST,
87 	 .needskeyset = 1,
88 	 },
89 	{			/* case 03, set attr to fifo */
90 	 .fname = FIFO,
91 	 .key = XATTR_TEST_KEY,
92 	 .value = XATTR_TEST_VALUE,
93 	 .size = XATTR_TEST_VALUE_SIZE,
94 	 .flags = XATTR_CREATE,
95 	 .exp_err = EPERM,
96 	 },
97 	{			/* case 04, set attr to character special */
98 	 .fname = CHR,
99 	 .key = XATTR_TEST_KEY,
100 	 .value = XATTR_TEST_VALUE,
101 	 .size = XATTR_TEST_VALUE_SIZE,
102 	 .flags = XATTR_CREATE,
103 	 .exp_err = EPERM,
104 	 },
105 	{			/* case 05, set attr to block special */
106 	 .fname = BLK,
107 	 .key = XATTR_TEST_KEY,
108 	 .value = XATTR_TEST_VALUE,
109 	 .size = XATTR_TEST_VALUE_SIZE,
110 	 .flags = XATTR_CREATE,
111 	 .exp_err = EPERM,
112 	 },
113 	{			/* case 06, set attr to socket */
114 	 .fname = SOCK,
115 	 .key = XATTR_TEST_KEY,
116 	 .value = XATTR_TEST_VALUE,
117 	 .size = XATTR_TEST_VALUE_SIZE,
118 	 .flags = XATTR_CREATE,
119 	 .exp_err = EPERM,
120 	 },
121 };
122 
verify_setxattr(unsigned int i)123 static void verify_setxattr(unsigned int i)
124 {
125 	/* some tests might require existing keys for each iteration */
126 	if (tc[i].needskeyset) {
127 		SAFE_SETXATTR(tc[i].fname, tc[i].key, tc[i].value, tc[i].size,
128 				XATTR_CREATE);
129 	}
130 
131 	TEST(setxattr(tc[i].fname, tc[i].key, tc[i].value, tc[i].size,
132 			tc[i].flags));
133 
134 	if (TST_RET == -1 && TST_ERR == EOPNOTSUPP)
135 		tst_brk(TCONF, "setxattr(2) not supported");
136 
137 	/* success */
138 
139 	if (!tc[i].exp_err) {
140 		if (TST_RET) {
141 			tst_res(TFAIL | TTERRNO,
142 				"setxattr(2) on %s failed with %li",
143 				tc[i].fname + OFFSET, TST_RET);
144 			return;
145 		}
146 
147 		/* this is needed for subsequent iterations */
148 		SAFE_REMOVEXATTR(tc[i].fname, tc[i].key);
149 
150 		tst_res(TPASS, "setxattr(2) on %s passed",
151 				tc[i].fname + OFFSET);
152 		return;
153 	}
154 
155 	if (TST_RET == 0) {
156 		tst_res(TFAIL, "setxattr(2) on %s passed unexpectedly",
157 				tc[i].fname + OFFSET);
158 		return;
159 	}
160 
161 	/* fail */
162 
163 	if (tc[i].exp_err != TST_ERR) {
164 		tst_res(TFAIL | TTERRNO,
165 				"setxattr(2) on %s should have failed with %s",
166 				tc[i].fname + OFFSET,
167 				tst_strerrno(tc[i].exp_err));
168 		return;
169 	}
170 
171 	/* key might have been added AND test might have failed, remove it */
172 	if (tc[i].needskeyset)
173 		SAFE_REMOVEXATTR(tc[i].fname, tc[i].key);
174 
175 	tst_res(TPASS | TTERRNO, "setxattr(2) on %s failed",
176 			tc[i].fname + OFFSET);
177 }
178 
setup(void)179 static void setup(void)
180 {
181 	dev_t dev = makedev(1, 3);
182 
183 	SAFE_TOUCH(FILENAME, 0644, NULL);
184 	SAFE_MKDIR(DIRNAME, 0644);
185 	SAFE_SYMLINK(FILENAME, SYMLINK);
186 	SAFE_MKNOD(FIFO, S_IFIFO | 0777, 0);
187 	SAFE_MKNOD(CHR, S_IFCHR | 0777, dev);
188 	SAFE_MKNOD(BLK, S_IFBLK | 0777, 0);
189 	SAFE_MKNOD(SOCK, S_IFSOCK | 0777, 0);
190 }
191 
192 static struct tst_test test = {
193 	.setup = setup,
194 	.test = verify_setxattr,
195 	.tcnt = ARRAY_SIZE(tc),
196 	.needs_tmpdir = 1,
197 	.needs_root = 1,
198 };
199 
200 #else /* HAVE_SYS_XATTR_H */
201 TST_TEST_TCONF("<sys/xattr.h> does not exist");
202 #endif
203