1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2018 Linaro Limited. All rights reserved.
4 * Author: Rafael David Tinoco <rafael.tinoco@linaro.org>
5 */
6
7 /*\
8 * [Description]
9 *
10 * lremovexattr(2) removes the extended attribute identified by a name and
11 * associated with a given path in the filesystem. Unlike removexattr(2),
12 * lremovexattr(2) removes the attribute from the symbolic link only, and not
13 * the file. This test verifies that a simple call to lremovexattr(2) removes,
14 * indeed, a previously set attribute key/value from a symbolic link, and the
15 * symbolic link _only_.
16 *
17 * Note:
18 * According to attr(5), extended attributes are interpreted differently from
19 * regular files, directories and symbolic links. User attributes are only
20 * allowed for regular files and directories, thus the need of using trusted.*
21 * attributes for this test.
22 */
23
24 #include "config.h"
25 #include <errno.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <fcntl.h>
30
31 #ifdef HAVE_SYS_XATTR_H
32 # include <sys/xattr.h>
33 #endif
34
35 #include "tst_test.h"
36
37 #ifdef HAVE_SYS_XATTR_H
38
39 #define ENOATTR ENODATA
40
41 #define XATTR_KEY "trusted.key1"
42 #define XATTR_VALUE "file and link"
43 #define XATTR_VALUE_SIZE 13
44
45 #define MNTPOINT "mntpoint"
46 #define FILENAME MNTPOINT"/lremovexattr01testfile"
47 #define SYMLINK MNTPOINT"/lremovexattr01symlink"
48
49 static char got_value[XATTR_VALUE_SIZE];
50
verify_lremovexattr(void)51 static void verify_lremovexattr(void)
52 {
53 /* set attribute on both: file and symlink */
54
55 SAFE_SETXATTR(FILENAME, XATTR_KEY, XATTR_VALUE, XATTR_VALUE_SIZE,
56 XATTR_CREATE);
57
58 SAFE_LSETXATTR(SYMLINK, XATTR_KEY, XATTR_VALUE, XATTR_VALUE_SIZE,
59 XATTR_CREATE);
60
61 /* remove attribute from symlink only */
62
63 TEST(lremovexattr(SYMLINK, XATTR_KEY));
64
65 if (TST_RET != 0) {
66 tst_res(TFAIL | TTERRNO, "lremovexattr(2) failed");
67 return;
68 }
69
70 /* make sure attribute is gone from symlink */
71
72 memset(&got_value, 0, XATTR_VALUE_SIZE);
73
74 TEST(lgetxattr(SYMLINK, XATTR_KEY, &got_value, XATTR_VALUE_SIZE));
75
76 if (TST_RET >= 0) {
77 tst_res(TFAIL, "lremovexattr(2) did not work");
78 return;
79 }
80
81 if (TST_ERR != ENOATTR) {
82 tst_brk(TBROK | TTERRNO, "lgetxattr(2) failed unexpectedly");
83 return;
84 }
85
86 /* check if file is unchanged, like it should be */
87
88 memset(&got_value, 0, XATTR_VALUE_SIZE);
89
90 TEST(getxattr(FILENAME, XATTR_KEY, &got_value, XATTR_VALUE_SIZE));
91
92 if (TST_RET <= 0) {
93 tst_res(TFAIL, "lremovexattr(2) deleted file attribute");
94 return;
95 }
96
97 if (strncmp(got_value, XATTR_VALUE, XATTR_VALUE_SIZE)) {
98 tst_res(TFAIL, "lremovexattr(2) changed file attribute");
99 return;
100 }
101
102 /* cleanup file attribute for iteration */
103
104 SAFE_REMOVEXATTR(FILENAME, XATTR_KEY);
105
106 tst_res(TPASS, "lremovexattr(2) removed attribute as expected");
107 }
108
setup(void)109 static void setup(void)
110 {
111 SAFE_TOUCH(FILENAME, 0644, NULL);
112
113 if (symlink(FILENAME, SYMLINK) < 0)
114 tst_brk(TCONF, "symlink() not supported");
115 }
116
117 static struct tst_test test = {
118 .setup = setup,
119 .test_all = verify_lremovexattr,
120 .mntpoint = MNTPOINT,
121 .mount_device = 1,
122 .all_filesystems = 1,
123 .needs_root = 1,
124 };
125
126 #else /* HAVE_SYS_XATTR_H */
127 TST_TEST_TCONF("<sys/xattr.h> does not exist");
128 #endif
129