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 * Tests for setxattr(2) and make sure setxattr(2) handles error
11 * conditions correctly.
12 *
13 * - EINVAL - any other flags being set except XATTR_CREATE and XATTR_REPLACE
14 * - ENODATA - with XATTR_REPLACE flag set but the attribute does not exist
15 * - ERANGE - create new attr with name length greater than XATTR_NAME_MAX(255)
16 * - E2BIG - create new attr whose value length is greater than XATTR_SIZE_MAX(65536)
17 * - SUCCEED - create new attr whose value length is zero
18 * - EEXIST - replace the attr value without XATTR_REPLACE flag being set
19 * - SUCCEED - replace attr value with XATTR_REPLACE flag being set
20 * - ERANGE - create new attr whose key length is zero
21 * - EFAULT - create new attr whose key is NULL
22 */
23
24 #include "config.h"
25 #include <sys/types.h>
26 #include <sys/stat.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_NAME_MAX 255
42 #define XATTR_NAME_LEN (XATTR_NAME_MAX + 2)
43 #define XATTR_SIZE_MAX 65536
44 #define XATTR_TEST_KEY "user.testkey"
45 #define XATTR_TEST_VALUE "this is a test value"
46 #define XATTR_TEST_VALUE_SIZE 20
47 #define MNTPOINT "mntpoint"
48 #define FNAME MNTPOINT"/setxattr01testfile"
49
50 static char long_key[XATTR_NAME_LEN];
51 static char *long_value;
52 static char *xattr_value = XATTR_TEST_VALUE;
53
54 struct test_case {
55 char *key;
56 char **value;
57 size_t size;
58 int flags;
59 int exp_err;
60 int keyneeded;
61 };
62 struct test_case tc[] = {
63 { /* case 00, invalid flags */
64 .key = XATTR_TEST_KEY,
65 .value = &xattr_value,
66 .size = XATTR_TEST_VALUE_SIZE,
67 .flags = ~0,
68 .exp_err = EINVAL,
69 },
70 { /* case 01, replace non-existing attribute */
71 .key = XATTR_TEST_KEY,
72 .value = &xattr_value,
73 .size = XATTR_TEST_VALUE_SIZE,
74 .flags = XATTR_REPLACE,
75 .exp_err = ENODATA,
76 },
77 { /* case 02, long key name */
78 .key = long_key,
79 .value = &xattr_value,
80 .size = XATTR_TEST_VALUE_SIZE,
81 .flags = XATTR_CREATE,
82 .exp_err = ERANGE,
83 },
84 { /* case 03, long value */
85 .key = XATTR_TEST_KEY,
86 .value = &long_value,
87 .size = XATTR_SIZE_MAX + 1,
88 .flags = XATTR_CREATE,
89 .exp_err = E2BIG,
90 },
91 { /* case 04, zero length value */
92 .key = XATTR_TEST_KEY,
93 .value = &xattr_value,
94 .size = 0,
95 .flags = XATTR_CREATE,
96 .exp_err = 0,
97 },
98 { /* case 05, create existing attribute */
99 .key = XATTR_TEST_KEY,
100 .value = &xattr_value,
101 .size = XATTR_TEST_VALUE_SIZE,
102 .flags = XATTR_CREATE,
103 .exp_err = EEXIST,
104 .keyneeded = 1,
105 },
106 { /* case 06, replace existing attribute */
107 .key = XATTR_TEST_KEY,
108 .value = &xattr_value,
109 .size = XATTR_TEST_VALUE_SIZE,
110 .flags = XATTR_REPLACE,
111 .exp_err = 0,
112 .keyneeded = 1,
113 },
114 { /* case 07, zero length key */
115 .key = "",
116 .value = &xattr_value,
117 .size = XATTR_TEST_VALUE_SIZE,
118 .flags = XATTR_CREATE,
119 .exp_err = ERANGE,
120 },
121 { /* case 08, NULL key */
122 .value = &xattr_value,
123 .size = XATTR_TEST_VALUE_SIZE,
124 .flags = XATTR_CREATE,
125 .exp_err = EFAULT,
126 },
127 };
128
verify_setxattr(unsigned int i)129 static void verify_setxattr(unsigned int i)
130 {
131 /* some tests might require existing keys for each iteration */
132 if (tc[i].keyneeded) {
133 SAFE_SETXATTR(FNAME, tc[i].key, *tc[i].value, tc[i].size,
134 XATTR_CREATE);
135 }
136
137 TEST(setxattr(FNAME, tc[i].key, *tc[i].value, tc[i].size, tc[i].flags));
138
139 if (TST_RET == -1 && TST_ERR == EOPNOTSUPP)
140 tst_brk(TCONF, "setxattr(2) not supported");
141
142 /* success */
143
144 if (!tc[i].exp_err) {
145 if (TST_RET) {
146 tst_res(TFAIL | TTERRNO,
147 "setxattr(2) failed with %li", TST_RET);
148 return;
149 }
150
151 /* this is needed for subsequent iterations */
152 SAFE_REMOVEXATTR(FNAME, tc[i].key);
153
154 tst_res(TPASS, "setxattr(2) passed");
155
156 return;
157 }
158
159 if (TST_RET == 0) {
160 tst_res(TFAIL, "setxattr(2) passed unexpectedly");
161 return;
162 }
163
164 /* error */
165
166 if (tc[i].exp_err != TST_ERR) {
167 tst_res(TFAIL | TTERRNO, "setxattr(2) should fail with %s",
168 tst_strerrno(tc[i].exp_err));
169 return;
170 }
171
172 /* key might have been added AND test might have failed, remove it */
173 if (tc[i].keyneeded)
174 SAFE_REMOVEXATTR(FNAME, tc[i].key);
175
176 tst_res(TPASS | TTERRNO, "setxattr(2) failed");
177 }
178
setup(void)179 static void setup(void)
180 {
181 size_t i = 0;
182
183 snprintf(long_key, 6, "%s", "user.");
184 memset(long_key + 5, 'k', XATTR_NAME_LEN - 5);
185 long_key[XATTR_NAME_LEN - 1] = '\0';
186
187 long_value = SAFE_MALLOC(XATTR_SIZE_MAX + 2);
188 memset(long_value, 'v', XATTR_SIZE_MAX + 2);
189 long_value[XATTR_SIZE_MAX + 1] = '\0';
190
191 SAFE_TOUCH(FNAME, 0644, NULL);
192
193 for (i = 0; i < ARRAY_SIZE(tc); i++) {
194 if (!tc[i].key)
195 tc[i].key = tst_get_bad_addr(NULL);
196 }
197 }
198
199 static struct tst_test test = {
200 .setup = setup,
201 .test = verify_setxattr,
202 .tcnt = ARRAY_SIZE(tc),
203 .mntpoint = MNTPOINT,
204 .mount_device = 1,
205 .all_filesystems = 1,
206 .needs_root = 1,
207 };
208
209 #else /* HAVE_SYS_XATTR_H */
210 TST_TEST_TCONF("<sys/xattr.h> does not exist");
211 #endif
212