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