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