1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2017 Fujitsu Ltd.
4 * Author: Xiao Yang <yangx.jy@cn.fujitsu.com>
5 */
6
7 /*
8 * This is a regression test for the race between getting an existing
9 * xattr and setting/removing a large xattr. This bug leads to that
10 * getxattr() fails to get an existing xattr and returns ENOATTR in xfs
11 * filesystem.
12 *
13 * Thie bug has been fixed in:
14 *
15 * commit 5a93790d4e2df73e30c965ec6e49be82fc3ccfce
16 * Author: Brian Foster <bfoster@redhat.com>
17 * Date: Wed Jan 25 07:53:43 2017 -0800
18 *
19 * xfs: remove racy hasattr check from attr ops
20 */
21
22 #include "config.h"
23 #include <errno.h>
24 #include <sys/types.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <signal.h>
28
29 #ifdef HAVE_SYS_XATTR_H
30 # include <sys/xattr.h>
31 #endif
32
33 #include "tst_test.h"
34
35 #ifdef HAVE_SYS_XATTR_H
36
37 #define MNTPOINT "mntpoint"
38 #define TEST_FILE MNTPOINT "/file"
39 #define TRUSTED_BIG "trusted.big"
40 #define TRUSTED_SMALL "trusted.small"
41
42 static volatile int end;
43 static char big_value[512];
44 static char small_value[32];
45
sigproc(int sig)46 static void sigproc(int sig)
47 {
48 end = sig;
49 }
50
loop_getxattr(void)51 static void loop_getxattr(void)
52 {
53 int res;
54
55 while (!end) {
56 res = getxattr(TEST_FILE, TRUSTED_SMALL, NULL, 0);
57 if (res == -1) {
58 if (errno == ENODATA) {
59 tst_res(TFAIL, "getxattr() failed to get an "
60 "existing attribute");
61 } else {
62 tst_res(TFAIL | TERRNO,
63 "getxattr() failed without ENOATTR");
64 }
65
66 exit(0);
67 }
68 }
69
70 tst_res(TPASS, "getxattr() succeeded to get an existing attribute");
71 exit(0);
72 }
73
verify_getxattr(void)74 static void verify_getxattr(void)
75 {
76 pid_t pid;
77 int n;
78
79 end = 0;
80
81 pid = SAFE_FORK();
82 if (!pid)
83 loop_getxattr();
84
85 for (n = 0; n < 99; n++) {
86 SAFE_SETXATTR(TEST_FILE, TRUSTED_BIG, big_value,
87 sizeof(big_value), XATTR_CREATE);
88 SAFE_REMOVEXATTR(TEST_FILE, TRUSTED_BIG);
89 }
90
91 kill(pid, SIGUSR1);
92 tst_reap_children();
93 }
94
setup(void)95 static void setup(void)
96 {
97 SAFE_SIGNAL(SIGUSR1, sigproc);
98
99 SAFE_TOUCH(TEST_FILE, 0644, NULL);
100
101 memset(big_value, 'a', sizeof(big_value));
102 memset(small_value, 'a', sizeof(small_value));
103
104 SAFE_SETXATTR(TEST_FILE, TRUSTED_SMALL, small_value,
105 sizeof(small_value), XATTR_CREATE);
106 }
107
108 static struct tst_test test = {
109 .needs_root = 1,
110 .mount_device = 1,
111 .dev_fs_type = "xfs",
112 .mntpoint = MNTPOINT,
113 .forks_child = 1,
114 .test_all = verify_getxattr,
115 .setup = setup,
116 .tags = (const struct tst_tag[]) {
117 {"linux-git", "5a93790d4e2d"},
118 {}
119 }
120 };
121
122 #else /* HAVE_SYS_XATTR_H */
123 TST_TEST_TCONF("<sys/xattr.h> does not exist.");
124 #endif
125