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