xref: /freebsd/sys/contrib/openzfs/include/os/linux/kernel/linux/idmap_compat.h (revision 22649d4dba730d46244fd2dff4fd174903c8379f)
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