1 // SPDX-License-Identifier: CDDL-1.0 2 /* 3 * This file and its contents are supplied under the terms of the 4 * Common Development and Distribution License ("CDDL"), version 1.0. 5 * You may only use this file in accordance with the terms of version 6 * 1.0 of the CDDL. 7 * 8 * A full copy of the text of the CDDL should have accompanied this 9 * source. A copy of the CDDL is also available via the Internet at 10 * https://opensource.org/license/CDDL-1.0. 11 */ 12 13 /* 14 * Copyright (c) 2026, TrueNAS. 15 */ 16 17 #ifndef _ZFS_IDMAP_COMPAT_H 18 #define _ZFS_IDMAP_COMPAT_H 19 20 /* 21 * Linux has a notion of a "user namespace", the set of users & groups. 22 * Processes and mounts can exist in different namespaces, such that an 23 * operation performed by a user in one namespace may need to be applied 24 * as a user in a different namespace. 25 * 26 * Example: a regular user (id=1000) runs a program in a container. A host 27 * filesystem is mounted into the container. Inside the container, the 28 * filesystem is written to by the "root" user (id=0). So, the id needs to 29 * be "mapped" to the other namespace. 30 * 31 * The VFS takes care of most of this for us, however, inode operations can 32 * access the object representing the id mapping in case they need to do 33 * further work (eg permission checks), or pass it back into the kernel when 34 * using generic helper functions. 35 * 36 * The type and method for accessing the mapping object has changed over the 37 * years: 38 * 39 * - 3.8: user namespaces were introduce in 3.8. the "active" user namespace 40 * was bound to the current task credential, available to the inode 41 * operation via kcred->user_ns. 42 * 43 * - 5.12: to distinguish between the user namespace the current task is 44 * operating in vs the user namespace of the target inode (mount), 45 * a struct user_namespace is passed to the inode operation in the 46 * first arg. 47 * 48 * - 6.3: to allow the id mapping process to be changed in the future to 49 * consider more than just the user namespaces, inode operations now 50 * now get passed a struct mnt_idmap, an abstract object with methods 51 * to request the "mapped" value for particular things. 52 * 53 * We currently support kernels that span this range, so we need to support all 54 * three methods. Fortunately, the kernel core switched in its entirety in the 55 * same release, so we don't need to handle conversions between eg 56 * user_namespace and mnt_idmap or anything like that. 57 * 58 * This file contains the types and macros needed for this support. 59 */ 60 61 /* 62 * zidmap_t will always match the type of the thing carrying the mapping for 63 * the current context. It can't ever be used directly, but we can name it 64 * and cast to and from it safely in prototypes and calls. 65 */ 66 #ifdef HAVE_IDMAP_MNTIDMAP 67 typedef struct mnt_idmap zidmap_t; 68 #else 69 typedef struct user_namespace zidmap_t; 70 #endif 71 72 /* 73 * The "identity" idmap, typically that of "host" namespace, "root" mount or 74 * similar. Prepared in advance by the SPL. 75 */ 76 extern zidmap_t *zfs_init_idmap; 77 78 /* 79 * Below is a macro system for defining inode_operations function callbacks 80 * that always receive a zidmap_t in their params, regardless of how they were 81 * called. 82 * 83 * Typical use: 84 * 85 * ZPL_IDMAP_IOP_DEFINE(int, zpl_create, 4, 86 * struct inode *, dir, struct dentry *, dentry, umode_t, mode, bool, flag) 87 * { 88 * ... 89 * } 90 * 91 * This emits a trampoline function for the inode_operations table, with 92 * first arg appropriate to the idmap type, one of: 93 * 94 * static int zpl_create(struct mnt_idmap *, [args...]) 95 * static int zpl_create(struct user_namespace *, [args...]) 96 * static int zpl_create([args...]) 97 * 98 * and the header for the implementing function: 99 * 100 * static int __zpl_create(zidmap_t *idmap, struct inode * dir, 101 * struct dentry * dentry, umode_t mode, bool flag) 102 * 103 * The trampoline function calls the implementing function with the first arg 104 * filled in appropriately for the type & method. Since it's a zidmap_t, it 105 * can be passed safely back to the kernel through the matching wrappers (eg 106 * zpl_setattr_prepare(idmap, ...). 107 */ 108 109 /* Helper: expand (type, name) pairs into "type name" for function prototypes */ 110 #define __ZPL_ARGS_1(t, n) t n 111 #define __ZPL_ARGS_2(t, n, ...) t n, __ZPL_ARGS_1(__VA_ARGS__) 112 #define __ZPL_ARGS_3(t, n, ...) t n, __ZPL_ARGS_2(__VA_ARGS__) 113 #define __ZPL_ARGS_4(t, n, ...) t n, __ZPL_ARGS_3(__VA_ARGS__) 114 #define __ZPL_ARGS_5(t, n, ...) t n, __ZPL_ARGS_4(__VA_ARGS__) 115 #define __ZPL_ARGS_6(t, n, ...) t n, __ZPL_ARGS_5(__VA_ARGS__) 116 117 /* Helper: expend (type, name) pairs into "name" for function calls */ 118 #define __ZPL_ARGNAMES_1(t, n) n 119 #define __ZPL_ARGNAMES_2(t, n, ...) n, __ZPL_ARGNAMES_1(__VA_ARGS__) 120 #define __ZPL_ARGNAMES_3(t, n, ...) n, __ZPL_ARGNAMES_2(__VA_ARGS__) 121 #define __ZPL_ARGNAMES_4(t, n, ...) n, __ZPL_ARGNAMES_3(__VA_ARGS__) 122 #define __ZPL_ARGNAMES_5(t, n, ...) n, __ZPL_ARGNAMES_4(__VA_ARGS__) 123 #define __ZPL_ARGNAMES_6(t, n, ...) n, __ZPL_ARGNAMES_5(__VA_ARGS__) 124 125 /* Define the appropriate wrapper by the configure checks. */ 126 #if defined(HAVE_IDMAP_MNTIDMAP) 127 #define _ZPL_IDMAP_IOP_WRAPPER(rty, fn, n, ...) \ 128 static rty fn(struct mnt_idmap *idmap, __ZPL_ARGS_##n(__VA_ARGS__)) \ 129 { \ 130 return (__##fn(idmap, __ZPL_ARGNAMES_##n(__VA_ARGS__))); \ 131 } 132 #elif defined(HAVE_IDMAP_USERNS) 133 #define _ZPL_IDMAP_IOP_WRAPPER(rty, fn, n, ...) \ 134 static rty fn(struct user_namespace *user_ns, __ZPL_ARGS_##n(__VA_ARGS__)) \ 135 { \ 136 return (__##fn(user_ns, __ZPL_ARGNAMES_##n(__VA_ARGS__))); \ 137 } 138 #else 139 #define _ZPL_IDMAP_IOP_WRAPPER(rty, fn, n, ...) \ 140 static rty fn(__ZPL_ARGS_##n(__VA_ARGS__)) \ 141 { \ 142 return (__##fn(kcred->user_ns, __ZPL_ARGNAMES_##n(__VA_ARGS__))); \ 143 } 144 #endif 145 146 /* 147 * Declare the implementing function, then fill in the wrapper, then emit the 148 * header for the implementation to follow. 149 * 150 * Note that idmap __maybe_unused, to avoid needing every function not using it 151 * (most of them) to have to silence the compiler warning. 152 */ 153 #define _ZPL_IDMAP_IOP_DEFINE(rty, fn, n, ...) \ 154 static rty __##fn(zidmap_t *idmap, __ZPL_ARGS_##n(__VA_ARGS__)); \ 155 _ZPL_IDMAP_IOP_WRAPPER(rty, fn, n, __VA_ARGS__) \ 156 static rty __##fn(zidmap_t *idmap __maybe_unused, __ZPL_ARGS_##n(__VA_ARGS__)) 157 158 #define ZPL_IDMAP_IOP_DEFINE(rty, fn, n, ...) \ 159 _ZPL_IDMAP_IOP_DEFINE(rty, fn, n, ##__VA_ARGS__) 160 161 #endif 162