xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/getxattr/getxattr05.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2018 FUJITSU LIMITED. All rights reserved.
4  * Author: Xiao Yang <[email protected]>
5  */
6 
7 /*\
8  * [Description]
9  *
10  * This test verifies that:
11  *
12  * - Without a user namespace, getxattr(2) should get same data when
13  *   acquiring the value of system.posix_acl_access twice.
14  * - With/Without mapped root UID in a user namespaces, getxattr(2) should
15  *   get same data when acquiring the value of system.posix_acl_access twice.
16  *
17  * This issue included by getxattr05 has been fixed in kernel:
18  * 82c9a927bc5d ("getxattr: use correct xattr length")
19  */
20 
21 #define _GNU_SOURCE
22 #include "config.h"
23 #include <errno.h>
24 #include <unistd.h>
25 #include <sys/types.h>
26 #include <stdlib.h>
27 
28 #ifdef HAVE_SYS_XATTR_H
29 # include <sys/xattr.h>
30 #endif
31 
32 #ifdef HAVE_LIBACL
33 # include <sys/acl.h>
34 #endif
35 
36 #include "tst_test.h"
37 #include "lapi/sched.h"
38 
39 #if defined(HAVE_SYS_XATTR_H) && defined(HAVE_LIBACL)
40 
41 #define TEST_FILE	"testfile"
42 #define SELF_USERNS	"/proc/self/ns/user"
43 #define MAX_USERNS	"/proc/sys/user/max_user_namespaces"
44 #define UID_MAP	"/proc/self/uid_map"
45 
46 static acl_t acl;
47 static int orig_max_userns = -1;
48 static int user_ns_supported = 1;
49 
50 static struct tcase {
51 	/* 0: without userns, 1: with userns */
52 	int set_userns;
53 	/* 0: don't map root UID in userns, 1: map root UID in userns */
54 	int map_root;
55 } tcases[] = {
56 	{0, 0},
57 	{1, 0},
58 	{1, 1},
59 };
60 
verify_getxattr(void)61 static void verify_getxattr(void)
62 {
63 	ssize_t i, res1, res2;
64 	char buf1[128], buf2[132];
65 
66 	res1 = SAFE_GETXATTR(TEST_FILE, "system.posix_acl_access",
67 			     buf1, sizeof(buf1));
68 	res2 = SAFE_GETXATTR(TEST_FILE, "system.posix_acl_access",
69 			     buf2, sizeof(buf2));
70 
71 	if (res1 != res2) {
72 		tst_res(TFAIL, "Return different sizes when acquiring "
73 			"the value of system.posix_acl_access twice");
74 		return;
75 	}
76 
77 	for (i = 0; i < res1; i++) {
78 		if (buf1[i] != buf2[i])
79 			break;
80 	}
81 
82 	if (i < res1) {
83 		tst_res(TFAIL, "Got different data(%02x != %02x) at %ld",
84 			buf1[i], buf2[i], i);
85 		return;
86 	}
87 
88 	tst_res(TPASS, "Got same data when acquiring the value of "
89 		"system.posix_acl_access twice");
90 }
91 
do_unshare(int map_root)92 static void do_unshare(int map_root)
93 {
94 	int res;
95 
96 	/* unshare() should support CLONE_NEWUSER flag since Linux 3.8 */
97 	res = unshare(CLONE_NEWUSER);
98 	if (res == -1)
99 		tst_brk(TFAIL | TERRNO, "unshare(CLONE_NEWUSER) failed");
100 
101 	if (map_root) {
102 		/* uid_map file should exist since Linux 3.8 because
103 		 * it is available on Linux 3.5
104 		 */
105 		SAFE_ACCESS(UID_MAP, F_OK);
106 
107 		SAFE_FILE_PRINTF(UID_MAP, "%d %d %d", 0, 0, 1);
108 	}
109 }
110 
do_getxattr(unsigned int n)111 static void do_getxattr(unsigned int n)
112 {
113 	struct tcase *tc = &tcases[n];
114 	pid_t pid;
115 
116 	if (tc->set_userns && !user_ns_supported) {
117 		tst_res(TCONF, "user namespace not available");
118 		return;
119 	}
120 
121 	pid = SAFE_FORK();
122 	if (!pid) {
123 		if (tc->set_userns)
124 			do_unshare(tc->map_root);
125 
126 		verify_getxattr();
127 		exit(0);
128 	}
129 
130 	tst_reap_children();
131 }
132 
setup(void)133 static void setup(void)
134 {
135 	const char *acl_text = "u::rw-,u:root:rwx,g::r--,o::r--,m::rwx";
136 	int res;
137 
138 	SAFE_TOUCH(TEST_FILE, 0644, NULL);
139 
140 	acl = acl_from_text(acl_text);
141 	if (!acl)
142 		tst_brk(TBROK | TERRNO, "acl_from_text() failed");
143 
144 	res = acl_set_file(TEST_FILE, ACL_TYPE_ACCESS, acl);
145 	if (res == -1) {
146 		if (errno == EOPNOTSUPP)
147 			tst_brk(TCONF | TERRNO, "acl_set_file()");
148 
149 		tst_brk(TBROK | TERRNO, "acl_set_file(%s) failed", TEST_FILE);
150 	}
151 
152 	/* The default value of max_user_namespaces is set to 0 on some distros,
153 	 * We need to change the default value to call unshare().
154 	 */
155 	if (access(SELF_USERNS, F_OK) != 0) {
156 		user_ns_supported = 0;
157 	} else if (!access(MAX_USERNS, F_OK)) {
158 		SAFE_FILE_SCANF(MAX_USERNS, "%d", &orig_max_userns);
159 		SAFE_FILE_PRINTF(MAX_USERNS, "%d", 10);
160 	}
161 
162 }
163 
cleanup(void)164 static void cleanup(void)
165 {
166 	if (orig_max_userns != -1)
167 		SAFE_FILE_PRINTF(MAX_USERNS, "%d", orig_max_userns);
168 
169 	if (acl)
170 		acl_free(acl);
171 }
172 
173 static struct tst_test test = {
174 	.needs_tmpdir = 1,
175 	.needs_root = 1,
176 	.forks_child = 1,
177 	.setup = setup,
178 	.cleanup = cleanup,
179 	.tcnt = ARRAY_SIZE(tcases),
180 	.test = do_getxattr,
181 	.tags = (const struct tst_tag[]) {
182 		{"linux-git", "82c9a927bc5d"},
183 		{}
184 },
185 };
186 
187 #else /* HAVE_SYS_XATTR_H && HAVE_LIBACL*/
188 	TST_TEST_TCONF("<sys/xattr.h> or <sys/acl.h> does not exist.");
189 #endif
190