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