• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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