1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) 2018 FUJITSU LIMITED. All rights reserved. 4 * Copyright (c) 2021 CTERA Networks. All Rights Reserved. 5 * 6 * User ns support by: Xiao Yang <yangx.jy@cn.fujitsu.com> 7 * Forked from getxattr05.c by Amir Goldstein <amir73il@gmail.com> 8 */ 9 10/*\ 11 * [Description] 12 * Check that fanotify groups and marks limits are enforced correctly. 13 * If user ns is supported, verify that global limit and per user ns 14 * limits are both enforced. 15 * Otherwise, we only check that global groups limit is enforced. 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#include "tst_test.h" 26#include "lapi/sched.h" 27 28#ifdef HAVE_SYS_FANOTIFY_H 29#include "fanotify.h" 30 31#define MOUNT_PATH "fs_mnt" 32#define TEST_FILE MOUNT_PATH "/testfile" 33#define SELF_USERNS "/proc/self/ns/user" 34#define MAX_USERNS "/proc/sys/user/max_user_namespaces" 35#define UID_MAP "/proc/self/uid_map" 36 37#define GLOBAL_MAX_GROUPS "/proc/sys/fs/fanotify/max_user_groups" 38#define GLOBAL_MAX_MARKS "/proc/sys/fs/fanotify/max_user_marks" 39#define USERNS_MAX_GROUPS "/proc/sys/user/max_fanotify_groups" 40#define USERNS_MAX_MARKS "/proc/sys/user/max_fanotify_marks" 41 42/* 43 * In older kernels those limits were fixed in kernel. 44 * The fanotify_init() man page documents the max groups limit is 128, but the 45 * implementation actually allows one extra group. 46 */ 47#define DEFAULT_MAX_GROUPS 129 48#define DEFAULT_MAX_MARKS 8192 49 50static int orig_max_userns = -1; 51static int user_ns_supported = 1; 52static int max_groups = DEFAULT_MAX_GROUPS; 53static int max_marks = DEFAULT_MAX_MARKS; 54 55static struct tcase { 56 const char *tname; 57 unsigned int init_flags; 58 /* 0: without userns, 1: with userns */ 59 int set_userns; 60 /* 0: don't map root UID in userns, 1: map root UID in userns */ 61 int map_root; 62 /* 0: unlimited groups in userns */ 63 int max_user_groups; 64 /* 0: unlimited marks in userns */ 65 int max_user_marks; 66} tcases[] = { 67 { 68 "Global groups limit in init user ns", 69 FAN_CLASS_NOTIF, 70 0, 0, 0, 0, 71 }, 72 { 73 "Global groups limit in privileged user ns", 74 FANOTIFY_REQUIRED_USER_INIT_FLAGS, 75 1, 1, 0, 0, 76 }, 77 { 78 "Local groups limit in unprivileged user ns", 79 FANOTIFY_REQUIRED_USER_INIT_FLAGS, 80 1, 0, 10, 0, 81 }, 82 { 83 "Local marks limit in unprivileged user ns", 84 FANOTIFY_REQUIRED_USER_INIT_FLAGS, 85 1, 0, 0, 10, 86 }, 87}; 88 89/* Verify that groups and marks cannot be created beyond limit */ 90static void verify_user_limits(unsigned int init_flags, int groups, int marks) 91{ 92 int i, fd = 0, ret = 0; 93 94 for (i = 0; i <= groups; i++) { 95 fd = fanotify_init(init_flags, O_RDONLY); 96 /* 97 * Don't bother closing fd's, the child process will exit 98 * and all fd's will be closed. 99 */ 100 if (fd < 0) 101 break; 102 103 ret = fanotify_mark(fd, FAN_MARK_ADD, FAN_OPEN, AT_FDCWD, 104 TEST_FILE); 105 if (ret < 0) 106 break; 107 108 } 109 if (fd > 0 && i > groups) { 110 tst_res(TFAIL, 111 "Created %d groups and marks - " 112 "groups limit (%d) exceeded", i, groups); 113 } else if (!ret && i > marks) { 114 tst_res(TFAIL, 115 "Created %d groups and marks - " 116 "marks limit (%d) exceeded", i, marks); 117 } else if (ret < 0 && errno == ENOSPC && marks < groups) { 118 /* 119 * ENOSPC is to be returned to the calling process when 120 * fanotify marks limit is reached. 121 */ 122 tst_res(TPASS, 123 "Created %d marks - " 124 "below marks limit (%d)", i, marks); 125 } else if (fd < 0 && errno == EMFILE) { 126 /* 127 * EMFILE is to be returned to the calling process when 128 * fanotify groups limit is reached. 129 */ 130 tst_res(TPASS, 131 "Created %d groups - " 132 "below groups limit (%d)", i, groups); 133 } else if (errno == EPERM) { 134 tst_res(TCONF, 135 "unprivileged fanotify not supported by kernel?"); 136 } else if (fd < 0) { 137 tst_brk(TBROK | TERRNO, 138 "fd=%d, fanotify_init(%x, O_RDONLY) failed", 139 fd, init_flags); 140 } else if (ret < 0) { 141 tst_brk(TBROK | TERRNO, 142 "ret=%d, fanotify_mark(%d, FAN_MARK_ADD, FAN_OPEN, " 143 "AT_FDCWD, '" TEST_FILE "') failed", ret, fd); 144 } 145} 146 147static void do_unshare(int map_root) 148{ 149 int res; 150 151 /* unshare() should support CLONE_NEWUSER flag since Linux 3.8 */ 152 res = unshare(CLONE_NEWUSER); 153 if (res == -1) 154 tst_brk(TFAIL | TERRNO, "unshare(CLONE_NEWUSER) failed"); 155 156 if (map_root) { 157 /* 158 * uid_map file should exist since Linux 3.8 because 159 * it is available on Linux 3.5 160 */ 161 SAFE_ACCESS(UID_MAP, F_OK); 162 163 SAFE_FILE_PRINTF(UID_MAP, "%d %d %d", 0, 0, 1); 164 } 165} 166 167static void test_fanotify(unsigned int n) 168{ 169 struct tcase *tc = &tcases[n]; 170 int groups = max_groups; 171 int marks = max_marks; 172 pid_t pid; 173 174 tst_res(TINFO, "Test #%d: %s", n, tc->tname); 175 176 if (tc->set_userns && !user_ns_supported) { 177 tst_res(TCONF, "fanotify inside user namespace is not supported"); 178 return; 179 } 180 181 pid = SAFE_FORK(); 182 if (!pid) { 183 if (tc->set_userns) { 184 do_unshare(tc->map_root); 185 /* Not changing global limits, only per userns limits */ 186 if (tc->max_user_groups && tc->max_user_groups < groups) { 187 /* Further limit user ns groups */ 188 marks = groups = tc->max_user_groups; 189 SAFE_FILE_PRINTF(USERNS_MAX_GROUPS, "%d", groups); 190 } 191 if (tc->max_user_marks && tc->max_user_marks < marks) { 192 /* Further limit user ns marks */ 193 marks = tc->max_user_marks; 194 SAFE_FILE_PRINTF(USERNS_MAX_MARKS, "%d", marks); 195 } 196 } 197 verify_user_limits(tc->init_flags, groups, marks); 198 exit(0); 199 } 200 201 tst_reap_children(); 202} 203 204static void setup_rlimit(unsigned int max_files) 205{ 206 struct rlimit rlim; 207 208 SAFE_GETRLIMIT(RLIMIT_NOFILE, &rlim); 209 rlim.rlim_cur = max_files; 210 SAFE_SETRLIMIT(RLIMIT_NOFILE, &rlim); 211} 212 213static void setup(void) 214{ 215 SAFE_TOUCH(TEST_FILE, 0666, NULL); 216 /* Check for kernel fanotify support */ 217 REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_ON_FS(FAN_REPORT_FID, TEST_FILE); 218 219 /* 220 * The default value of max_user_namespaces is set to 0 on some distros, 221 * We need to change the default value to call unshare(). 222 */ 223 if (access(SELF_USERNS, F_OK) != 0) { 224 user_ns_supported = 0; 225 } else if (!access(MAX_USERNS, F_OK)) { 226 SAFE_FILE_SCANF(MAX_USERNS, "%d", &orig_max_userns); 227 SAFE_FILE_PRINTF(MAX_USERNS, "%d", 10); 228 } 229 230 /* 231 * In older kernels those limits were fixed in kernel and fanotify is 232 * not permitted inside user ns. 233 */ 234 if (access(GLOBAL_MAX_GROUPS, F_OK) && errno == ENOENT) { 235 user_ns_supported = 0; 236 } else { 237 SAFE_FILE_SCANF(GLOBAL_MAX_GROUPS, "%d", &max_groups); 238 SAFE_FILE_SCANF(GLOBAL_MAX_MARKS, "%d", &max_marks); 239 } 240 tst_res(TINFO, "max_fanotify_groups=%d max_fanotify_marks=%d", 241 max_groups, max_marks); 242 243 /* Make sure we are not limited by nr of open files */ 244 setup_rlimit(max_groups * 2); 245} 246 247static void cleanup(void) 248{ 249 if (orig_max_userns != -1) 250 SAFE_FILE_PRINTF(MAX_USERNS, "%d", orig_max_userns); 251} 252 253static struct tst_test test = { 254 .test = test_fanotify, 255 .tcnt = ARRAY_SIZE(tcases), 256 .setup = setup, 257 .cleanup = cleanup, 258 .needs_root = 1, 259 .forks_child = 1, 260 .mount_device = 1, 261 .mntpoint = MOUNT_PATH, 262}; 263#else 264 TST_TEST_TCONF("system doesn't have required fanotify support"); 265#endif 266