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