1b4bfe2f6SChristian Brauner // SPDX-License-Identifier: GPL-2.0-only 2b4bfe2f6SChristian Brauner /* 3b4bfe2f6SChristian Brauner * BPF-backed binary type handlers for binfmt_misc. 4b4bfe2f6SChristian Brauner * 5b4bfe2f6SChristian Brauner * A handler is a struct binfmt_misc_ops struct_ops map. Loading and 6b4bfe2f6SChristian Brauner * registering it makes the handler available under its name in the user 7b4bfe2f6SChristian Brauner * namespace it was registered in. A binfmt_misc 'B' entry activates it: 8b4bfe2f6SChristian Brauner * 9b4bfe2f6SChristian Brauner * echo ':entry:B::::<handler-name>:' > <binfmt_misc>/register 10*6ec7c96bSChristian Brauner * 11*6ec7c96bSChristian Brauner * The entry can bind the interpreters the handler may run its binaries 12*6ec7c96bSChristian Brauner * with, each opened by the write that binds it and selected by name per 13*6ec7c96bSChristian Brauner * exec. An entry registered with 'D' is not matchable yet, which is what 14*6ec7c96bSChristian Brauner * leaves it open to being given them: 15*6ec7c96bSChristian Brauner * 16*6ec7c96bSChristian Brauner * echo ':entry:B::::<handler-name>:D' > <binfmt_misc>/register 17*6ec7c96bSChristian Brauner * echo '+<name> <path>' > <binfmt_misc>/entry 18*6ec7c96bSChristian Brauner * echo 1 > <binfmt_misc>/entry 19b4bfe2f6SChristian Brauner */ 20b4bfe2f6SChristian Brauner 21b4bfe2f6SChristian Brauner #include <linux/binfmt_misc.h> 22b4bfe2f6SChristian Brauner #include <linux/binfmts.h> 23b4bfe2f6SChristian Brauner #include <linux/bpf.h> 24b4bfe2f6SChristian Brauner #include <linux/bpf_verifier.h> 25b4bfe2f6SChristian Brauner #include <linux/btf.h> 26b4bfe2f6SChristian Brauner #include <linux/btf_ids.h> 27b4bfe2f6SChristian Brauner #include <linux/cred.h> 28*6ec7c96bSChristian Brauner #include <linux/file.h> 29*6ec7c96bSChristian Brauner #include <linux/fs.h> 30b4bfe2f6SChristian Brauner #include <linux/init.h> 31b4bfe2f6SChristian Brauner #include <linux/limits.h> 32b4bfe2f6SChristian Brauner #include <linux/slab.h> 33b4bfe2f6SChristian Brauner #include <linux/spinlock.h> 34b4bfe2f6SChristian Brauner #include <linux/string.h> 35b4bfe2f6SChristian Brauner #include <linux/user_namespace.h> 36b4bfe2f6SChristian Brauner 37b4bfe2f6SChristian Brauner struct bm_bpf_ops_reg { 38b4bfe2f6SChristian Brauner struct list_head list; 39b4bfe2f6SChristian Brauner const struct binfmt_misc_ops *ops; 40b4bfe2f6SChristian Brauner struct bpf_link *link; 41b4bfe2f6SChristian Brauner struct user_namespace *user_ns; 42b4bfe2f6SChristian Brauner }; 43b4bfe2f6SChristian Brauner 44b4bfe2f6SChristian Brauner static DEFINE_SPINLOCK(bm_bpf_ops_lock); 45b4bfe2f6SChristian Brauner static LIST_HEAD(bm_bpf_ops_list); 46b4bfe2f6SChristian Brauner 47b4bfe2f6SChristian Brauner static struct bpf_struct_ops bpf_binfmt_misc_ops; 48b4bfe2f6SChristian Brauner 49b4bfe2f6SChristian Brauner static struct bm_bpf_ops_reg *bm_bpf_ops_find(const struct user_namespace *user_ns, 50b4bfe2f6SChristian Brauner const char *name) 51b4bfe2f6SChristian Brauner { 52b4bfe2f6SChristian Brauner struct bm_bpf_ops_reg *reg; 53b4bfe2f6SChristian Brauner 54b4bfe2f6SChristian Brauner lockdep_assert_held(&bm_bpf_ops_lock); 55b4bfe2f6SChristian Brauner 56b4bfe2f6SChristian Brauner list_for_each_entry(reg, &bm_bpf_ops_list, list) { 57b4bfe2f6SChristian Brauner if (reg->user_ns == user_ns && !strcmp(reg->ops->name, name)) 58b4bfe2f6SChristian Brauner return reg; 59b4bfe2f6SChristian Brauner } 60b4bfe2f6SChristian Brauner return NULL; 61b4bfe2f6SChristian Brauner } 62b4bfe2f6SChristian Brauner 63b4bfe2f6SChristian Brauner /** 64b4bfe2f6SChristian Brauner * binfmt_misc_get_ops - look up a bpf binary type handler by name 65b4bfe2f6SChristian Brauner * @user_ns: user namespace of the binfmt_misc instance 66b4bfe2f6SChristian Brauner * @name: name the handler was registered under 67b4bfe2f6SChristian Brauner * 68b4bfe2f6SChristian Brauner * Look for a handler named @name registered in @user_ns. A handler is not 69b4bfe2f6SChristian Brauner * inherited from ancestor user namespaces: an entry can only name a handler 70b4bfe2f6SChristian Brauner * registered in the same user namespace as its instance. The returned handler 71b4bfe2f6SChristian Brauner * stays callable until binfmt_misc_put_ops() even if the backing struct_ops 72b4bfe2f6SChristian Brauner * map is detached or deleted in the meantime. 73b4bfe2f6SChristian Brauner * 74b4bfe2f6SChristian Brauner * Return: the handler on success, NULL on failure 75b4bfe2f6SChristian Brauner */ 76b4bfe2f6SChristian Brauner const struct binfmt_misc_ops *binfmt_misc_get_ops(struct user_namespace *user_ns, 77b4bfe2f6SChristian Brauner const char *name) 78b4bfe2f6SChristian Brauner { 79b4bfe2f6SChristian Brauner struct bm_bpf_ops_reg *reg; 80b4bfe2f6SChristian Brauner 81b4bfe2f6SChristian Brauner guard(spinlock)(&bm_bpf_ops_lock); 82b4bfe2f6SChristian Brauner 83b4bfe2f6SChristian Brauner reg = bm_bpf_ops_find(user_ns, name); 84b4bfe2f6SChristian Brauner if (!reg) 85b4bfe2f6SChristian Brauner return NULL; 86b4bfe2f6SChristian Brauner if (!bpf_struct_ops_get(reg->ops)) 87b4bfe2f6SChristian Brauner return NULL; 88b4bfe2f6SChristian Brauner return reg->ops; 89b4bfe2f6SChristian Brauner } 90b4bfe2f6SChristian Brauner 91b4bfe2f6SChristian Brauner void binfmt_misc_put_ops(const struct binfmt_misc_ops *ops) 92b4bfe2f6SChristian Brauner { 93b4bfe2f6SChristian Brauner bpf_struct_ops_put(ops); 94b4bfe2f6SChristian Brauner } 95b4bfe2f6SChristian Brauner 96b4bfe2f6SChristian Brauner bool bpf_prog_is_binfmt_misc_ops(const struct bpf_prog *prog) 97b4bfe2f6SChristian Brauner { 98b4bfe2f6SChristian Brauner return prog->type == BPF_PROG_TYPE_STRUCT_OPS && 99b4bfe2f6SChristian Brauner prog->aux->st_ops == &bpf_binfmt_misc_ops; 100b4bfe2f6SChristian Brauner } 101b4bfe2f6SChristian Brauner 102*6ec7c96bSChristian Brauner /* 103*6ec7c96bSChristian Brauner * Replace the staged interpreter selection: naming a path drops a bound 104*6ec7c96bSChristian Brauner * file, selecting a bound interpreter carries its file along. 105*6ec7c96bSChristian Brauner */ 106*6ec7c96bSChristian Brauner static void bm_bpf_stage_selection(struct linux_binprm *bprm, char *path, 107*6ec7c96bSChristian Brauner struct file *f) 108*6ec7c96bSChristian Brauner { 109*6ec7c96bSChristian Brauner if (bprm->bpf_interp_file) 110*6ec7c96bSChristian Brauner fput(bprm->bpf_interp_file); 111*6ec7c96bSChristian Brauner kfree(bprm->bpf_interp); 112*6ec7c96bSChristian Brauner bprm->bpf_interp = path; 113*6ec7c96bSChristian Brauner bprm->bpf_interp_file = f; 114*6ec7c96bSChristian Brauner } 115*6ec7c96bSChristian Brauner 116b4bfe2f6SChristian Brauner __bpf_kfunc_start_defs(); 117b4bfe2f6SChristian Brauner 118b4bfe2f6SChristian Brauner /** 119b4bfe2f6SChristian Brauner * bpf_binprm_set_interp - select the interpreter for the current exec 120b4bfe2f6SChristian Brauner * @bprm: binary that is being executed 121b4bfe2f6SChristian Brauner * @path: absolute path to the interpreter 122b4bfe2f6SChristian Brauner * @path__sz: size of the @path buffer, including the terminating NUL 123b4bfe2f6SChristian Brauner * 124b4bfe2f6SChristian Brauner * To be called from the load program of a struct binfmt_misc_ops handler 125b4bfe2f6SChristian Brauner * before returning zero; the verifier rejects the call from any other 126b4bfe2f6SChristian Brauner * program, including the handler's own match program. The path is opened 127b4bfe2f6SChristian Brauner * with the credentials of the task doing the exec after the program 128*6ec7c96bSChristian Brauner * returns. Calling it again replaces the selection, as does selecting an 129*6ec7c96bSChristian Brauner * interpreter the entry bound with bpf_binprm_select_interp(). 130b4bfe2f6SChristian Brauner * 131b4bfe2f6SChristian Brauner * Return: 0 on success, a negative errno on failure 132b4bfe2f6SChristian Brauner */ 133b4bfe2f6SChristian Brauner __bpf_kfunc int bpf_binprm_set_interp(struct linux_binprm *bprm, 134b4bfe2f6SChristian Brauner const char *path, size_t path__sz) 135b4bfe2f6SChristian Brauner { 136b4bfe2f6SChristian Brauner size_t len; 137b4bfe2f6SChristian Brauner char *interp; 138b4bfe2f6SChristian Brauner 139b4bfe2f6SChristian Brauner if (!path__sz) 140b4bfe2f6SChristian Brauner return -EINVAL; 141b4bfe2f6SChristian Brauner len = strnlen(path, path__sz); 142b4bfe2f6SChristian Brauner if (len == path__sz) 143b4bfe2f6SChristian Brauner return -EINVAL; 144b4bfe2f6SChristian Brauner if (path[0] != '/') 145b4bfe2f6SChristian Brauner return -EINVAL; 146b4bfe2f6SChristian Brauner if (len >= PATH_MAX) 147b4bfe2f6SChristian Brauner return -ENAMETOOLONG; 148b4bfe2f6SChristian Brauner 149b4bfe2f6SChristian Brauner interp = kmemdup_nul(path, len, GFP_KERNEL); 150b4bfe2f6SChristian Brauner if (!interp) 151b4bfe2f6SChristian Brauner return -ENOMEM; 152b4bfe2f6SChristian Brauner 153*6ec7c96bSChristian Brauner bm_bpf_stage_selection(bprm, interp, NULL); 154*6ec7c96bSChristian Brauner return 0; 155*6ec7c96bSChristian Brauner } 156*6ec7c96bSChristian Brauner 157*6ec7c96bSChristian Brauner /** 158*6ec7c96bSChristian Brauner * bpf_binprm_select_interp - run this exec under an interpreter the entry bound 159*6ec7c96bSChristian Brauner * @bprm: binary that is being executed 160*6ec7c96bSChristian Brauner * @name: name the interpreter was registered under 161*6ec7c96bSChristian Brauner * @name__sz: size of the @name buffer, including the terminating NUL 162*6ec7c96bSChristian Brauner * 163*6ec7c96bSChristian Brauner * To be called from the load program of a struct binfmt_misc_ops handler 164*6ec7c96bSChristian Brauner * instead of bpf_binprm_set_interp(). It selects one of the interpreters 165*6ec7c96bSChristian Brauner * the matched entry was registered with, each of which was opened once when 166*6ec7c96bSChristian Brauner * the entry was registered. Nothing is resolved at exec time, so no 167*6ec7c96bSChristian Brauner * filesystem view can redirect the interpreter. 168*6ec7c96bSChristian Brauner * 169*6ec7c96bSChristian Brauner * The interpreter runs under the path the entry registered it under. 170*6ec7c96bSChristian Brauner * Calling it again replaces the selection. 171*6ec7c96bSChristian Brauner * 172*6ec7c96bSChristian Brauner * Return: 0 on success, -ENOENT if the matched entry bound no interpreter 173*6ec7c96bSChristian Brauner * of that name, a negative errno on failure 174*6ec7c96bSChristian Brauner */ 175*6ec7c96bSChristian Brauner __bpf_kfunc int bpf_binprm_select_interp(struct linux_binprm *bprm, 176*6ec7c96bSChristian Brauner const char *name, size_t name__sz) 177*6ec7c96bSChristian Brauner { 178*6ec7c96bSChristian Brauner const struct binfmt_misc_interp *interp; 179*6ec7c96bSChristian Brauner size_t len; 180*6ec7c96bSChristian Brauner char *path; 181*6ec7c96bSChristian Brauner 182*6ec7c96bSChristian Brauner if (!name__sz) 183*6ec7c96bSChristian Brauner return -EINVAL; 184*6ec7c96bSChristian Brauner len = strnlen(name, name__sz); 185*6ec7c96bSChristian Brauner if (len == name__sz || !len) 186*6ec7c96bSChristian Brauner return -EINVAL; 187*6ec7c96bSChristian Brauner 188*6ec7c96bSChristian Brauner interp = binfmt_misc_find_interp(bprm->bpf_interps, name); 189*6ec7c96bSChristian Brauner if (!interp) 190*6ec7c96bSChristian Brauner return -ENOENT; 191*6ec7c96bSChristian Brauner 192*6ec7c96bSChristian Brauner path = kstrdup(interp->path, GFP_KERNEL); 193*6ec7c96bSChristian Brauner if (!path) 194*6ec7c96bSChristian Brauner return -ENOMEM; 195*6ec7c96bSChristian Brauner 196*6ec7c96bSChristian Brauner bm_bpf_stage_selection(bprm, path, get_file(interp->file)); 197b4bfe2f6SChristian Brauner return 0; 198b4bfe2f6SChristian Brauner } 199b4bfe2f6SChristian Brauner 200b4bfe2f6SChristian Brauner /** 201b4bfe2f6SChristian Brauner * bpf_binprm_set_interp_arg - set a single argument for the interpreter 202b4bfe2f6SChristian Brauner * @bprm: binary that is being executed 203b4bfe2f6SChristian Brauner * @arg: argument to pass to the interpreter 204b4bfe2f6SChristian Brauner * @arg__sz: size of the @arg buffer, including the terminating NUL 205b4bfe2f6SChristian Brauner * 206b4bfe2f6SChristian Brauner * To be called from the load program of a struct binfmt_misc_ops handler. The 207b4bfe2f6SChristian Brauner * argument is passed to the interpreter ahead of the binary, mirroring the 208b4bfe2f6SChristian Brauner * single optional argument of a #! interpreter line. Calling it again 209b4bfe2f6SChristian Brauner * replaces the argument. 210b4bfe2f6SChristian Brauner * 211b4bfe2f6SChristian Brauner * Return: 0 on success, a negative errno on failure 212b4bfe2f6SChristian Brauner */ 213b4bfe2f6SChristian Brauner __bpf_kfunc int bpf_binprm_set_interp_arg(struct linux_binprm *bprm, 214b4bfe2f6SChristian Brauner const char *arg, size_t arg__sz) 215b4bfe2f6SChristian Brauner { 216b4bfe2f6SChristian Brauner size_t len; 217b4bfe2f6SChristian Brauner char *val; 218b4bfe2f6SChristian Brauner 219b4bfe2f6SChristian Brauner if (!arg__sz) 220b4bfe2f6SChristian Brauner return -EINVAL; 221b4bfe2f6SChristian Brauner len = strnlen(arg, arg__sz); 222b4bfe2f6SChristian Brauner if (len == arg__sz) 223b4bfe2f6SChristian Brauner return -EINVAL; 224b4bfe2f6SChristian Brauner if (!len) 225b4bfe2f6SChristian Brauner return -EINVAL; 226b4bfe2f6SChristian Brauner 227b4bfe2f6SChristian Brauner val = kmemdup_nul(arg, len, GFP_KERNEL); 228b4bfe2f6SChristian Brauner if (!val) 229b4bfe2f6SChristian Brauner return -ENOMEM; 230b4bfe2f6SChristian Brauner 231b4bfe2f6SChristian Brauner kfree(bprm->bpf_interp_arg); 232b4bfe2f6SChristian Brauner bprm->bpf_interp_arg = val; 233b4bfe2f6SChristian Brauner return 0; 234b4bfe2f6SChristian Brauner } 235b4bfe2f6SChristian Brauner 236b4bfe2f6SChristian Brauner /** 237b4bfe2f6SChristian Brauner * bpf_binprm_set_flags - choose the interpreter invocation flags for this exec 238b4bfe2f6SChristian Brauner * @bprm: binary that is being executed 239b4bfe2f6SChristian Brauner * @flags: an OR of enum bpf_binprm_flags values 240b4bfe2f6SChristian Brauner * 241b4bfe2f6SChristian Brauner * To be called from the load program of a struct binfmt_misc_ops handler. It 242375e8a31SChristian Brauner * decides per exec what a static entry fixes at registration with the P, C, 243375e8a31SChristian Brauner * O, T and L flags: BPF_BINPRM_PRESERVE_ARGV0 keeps the caller's argv[0], 244b4bfe2f6SChristian Brauner * BPF_BINPRM_CREDENTIALS computes credentials from the binary, and 245b4bfe2f6SChristian Brauner * BPF_BINPRM_EXECFD hands the binary to the interpreter through AT_EXECFD. 24621e04378SChristian Brauner * BPF_BINPRM_TRANSPARENT additionally leaves the argument vector untouched, 247375e8a31SChristian Brauner * making the exec look like a direct execution of the binary. 248375e8a31SChristian Brauner * BPF_BINPRM_LOADER substitutes the interpreter for the binary's PT_INTERP 249375e8a31SChristian Brauner * and runs the binary as a native exec; it excludes every other flag. 250375e8a31SChristian Brauner * Calling it again replaces the flags, passing zero clears them again. 251b4bfe2f6SChristian Brauner * 25221e04378SChristian Brauner * Return: 0 on success, -EINVAL if @flags contains an unknown bit or an 25321e04378SChristian Brauner * invalid combination 254b4bfe2f6SChristian Brauner */ 255b4bfe2f6SChristian Brauner __bpf_kfunc int bpf_binprm_set_flags(struct linux_binprm *bprm, 256b4bfe2f6SChristian Brauner enum bpf_binprm_flags flags) 257b4bfe2f6SChristian Brauner { 258b4bfe2f6SChristian Brauner if (flags & ~(BPF_BINPRM_PRESERVE_ARGV0 | BPF_BINPRM_CREDENTIALS | 259375e8a31SChristian Brauner BPF_BINPRM_EXECFD | BPF_BINPRM_TRANSPARENT | 260375e8a31SChristian Brauner BPF_BINPRM_LOADER)) 261375e8a31SChristian Brauner return -EINVAL; 262375e8a31SChristian Brauner 263375e8a31SChristian Brauner /* Loader substitution is a native exec: no splice, execfd or creds work. */ 264375e8a31SChristian Brauner if ((flags & BPF_BINPRM_LOADER) && (flags & ~BPF_BINPRM_LOADER)) 26521e04378SChristian Brauner return -EINVAL; 26621e04378SChristian Brauner 26721e04378SChristian Brauner /* Transparency preserves the whole argv, argv[0] included. */ 26821e04378SChristian Brauner if ((flags & BPF_BINPRM_TRANSPARENT) && (flags & BPF_BINPRM_PRESERVE_ARGV0)) 269b4bfe2f6SChristian Brauner return -EINVAL; 270b4bfe2f6SChristian Brauner 271b4bfe2f6SChristian Brauner bprm->bpf_flags = flags; 272b4bfe2f6SChristian Brauner return 0; 273b4bfe2f6SChristian Brauner } 274b4bfe2f6SChristian Brauner 275b4bfe2f6SChristian Brauner __bpf_kfunc_end_defs(); 276b4bfe2f6SChristian Brauner 277b4bfe2f6SChristian Brauner BTF_KFUNCS_START(bm_bpf_kfunc_ids) 278b4bfe2f6SChristian Brauner BTF_ID_FLAGS(func, bpf_binprm_set_interp, KF_SLEEPABLE) 279*6ec7c96bSChristian Brauner BTF_ID_FLAGS(func, bpf_binprm_select_interp, KF_SLEEPABLE) 280b4bfe2f6SChristian Brauner BTF_ID_FLAGS(func, bpf_binprm_set_interp_arg, KF_SLEEPABLE) 281b4bfe2f6SChristian Brauner BTF_ID_FLAGS(func, bpf_binprm_set_flags, KF_SLEEPABLE) 282b4bfe2f6SChristian Brauner BTF_KFUNCS_END(bm_bpf_kfunc_ids) 283b4bfe2f6SChristian Brauner 284b4bfe2f6SChristian Brauner static int bm_bpf_kfunc_filter(const struct bpf_prog *prog, u32 kfunc_id) 285b4bfe2f6SChristian Brauner { 286b4bfe2f6SChristian Brauner if (!btf_id_set8_contains(&bm_bpf_kfunc_ids, kfunc_id)) 287b4bfe2f6SChristian Brauner return 0; 288b4bfe2f6SChristian Brauner if (prog->type != BPF_PROG_TYPE_STRUCT_OPS) 289b4bfe2f6SChristian Brauner return -EACCES; 290b4bfe2f6SChristian Brauner /* ->st_ops is unset during the cfg pass; enforced once it is set. */ 291b4bfe2f6SChristian Brauner if (!prog->aux->st_ops) 292b4bfe2f6SChristian Brauner return 0; 293b4bfe2f6SChristian Brauner /* Only the load program decides how a binary is run. */ 294b4bfe2f6SChristian Brauner if (bpf_prog_is_binfmt_misc_ops(prog) && 295b4bfe2f6SChristian Brauner prog->aux->attach_st_ops_member_off == offsetof(struct binfmt_misc_ops, load)) 296b4bfe2f6SChristian Brauner return 0; 297b4bfe2f6SChristian Brauner return -EACCES; 298b4bfe2f6SChristian Brauner } 299b4bfe2f6SChristian Brauner 300b4bfe2f6SChristian Brauner static const struct btf_kfunc_id_set bm_bpf_kfunc_set = { 301b4bfe2f6SChristian Brauner .owner = THIS_MODULE, 302b4bfe2f6SChristian Brauner .set = &bm_bpf_kfunc_ids, 303b4bfe2f6SChristian Brauner .filter = bm_bpf_kfunc_filter, 304b4bfe2f6SChristian Brauner }; 305b4bfe2f6SChristian Brauner 306b4bfe2f6SChristian Brauner static bool bm_bpf_ops__match(struct linux_binprm *bprm) 307b4bfe2f6SChristian Brauner { 308b4bfe2f6SChristian Brauner return false; 309b4bfe2f6SChristian Brauner } 310b4bfe2f6SChristian Brauner 311b4bfe2f6SChristian Brauner static int bm_bpf_ops__load(struct linux_binprm *bprm) 312b4bfe2f6SChristian Brauner { 313b4bfe2f6SChristian Brauner return 0; 314b4bfe2f6SChristian Brauner } 315b4bfe2f6SChristian Brauner 316b4bfe2f6SChristian Brauner static struct binfmt_misc_ops bm_bpf_ops_stubs = { 317b4bfe2f6SChristian Brauner .match = bm_bpf_ops__match, 318b4bfe2f6SChristian Brauner .load = bm_bpf_ops__load, 319b4bfe2f6SChristian Brauner }; 320b4bfe2f6SChristian Brauner 321b4bfe2f6SChristian Brauner static int bm_bpf_init(struct btf *btf) 322b4bfe2f6SChristian Brauner { 323b4bfe2f6SChristian Brauner return register_btf_kfunc_id_set(BPF_PROG_TYPE_STRUCT_OPS, 324b4bfe2f6SChristian Brauner &bm_bpf_kfunc_set); 325b4bfe2f6SChristian Brauner } 326b4bfe2f6SChristian Brauner 327b4bfe2f6SChristian Brauner static int bm_bpf_check_member(const struct btf_type *t, 328b4bfe2f6SChristian Brauner const struct btf_member *member, 329b4bfe2f6SChristian Brauner const struct bpf_prog *prog) 330b4bfe2f6SChristian Brauner { 331b4bfe2f6SChristian Brauner u32 moff = __btf_member_bit_offset(t, member) / 8; 332b4bfe2f6SChristian Brauner 333b4bfe2f6SChristian Brauner switch (moff) { 334b4bfe2f6SChristian Brauner case offsetof(struct binfmt_misc_ops, match): 335b4bfe2f6SChristian Brauner case offsetof(struct binfmt_misc_ops, load): 336b4bfe2f6SChristian Brauner /* Reliable file reads at exec time require sleeping. */ 337b4bfe2f6SChristian Brauner if (!prog->sleepable) 338b4bfe2f6SChristian Brauner return -EINVAL; 339b4bfe2f6SChristian Brauner break; 340b4bfe2f6SChristian Brauner } 341b4bfe2f6SChristian Brauner return 0; 342b4bfe2f6SChristian Brauner } 343b4bfe2f6SChristian Brauner 344b4bfe2f6SChristian Brauner static int bm_bpf_init_member(const struct btf_type *t, 345b4bfe2f6SChristian Brauner const struct btf_member *member, 346b4bfe2f6SChristian Brauner void *kdata, const void *udata) 347b4bfe2f6SChristian Brauner { 348b4bfe2f6SChristian Brauner const struct binfmt_misc_ops *uops = udata; 349b4bfe2f6SChristian Brauner struct binfmt_misc_ops *ops = kdata; 350b4bfe2f6SChristian Brauner u32 moff = __btf_member_bit_offset(t, member) / 8; 351b4bfe2f6SChristian Brauner 352b4bfe2f6SChristian Brauner switch (moff) { 353b4bfe2f6SChristian Brauner case offsetof(struct binfmt_misc_ops, name): 354b4bfe2f6SChristian Brauner if (bpf_obj_name_cpy(ops->name, uops->name, 355b4bfe2f6SChristian Brauner sizeof(ops->name)) <= 0) 356b4bfe2f6SChristian Brauner return -EINVAL; 357b4bfe2f6SChristian Brauner return 1; 358b4bfe2f6SChristian Brauner } 359b4bfe2f6SChristian Brauner return 0; 360b4bfe2f6SChristian Brauner } 361b4bfe2f6SChristian Brauner 362b4bfe2f6SChristian Brauner static int bm_bpf_validate(void *kdata) 363b4bfe2f6SChristian Brauner { 364b4bfe2f6SChristian Brauner struct binfmt_misc_ops *ops = kdata; 365b4bfe2f6SChristian Brauner 366b4bfe2f6SChristian Brauner if (!ops->match || !ops->load) 367b4bfe2f6SChristian Brauner return -EINVAL; 368b4bfe2f6SChristian Brauner return 0; 369b4bfe2f6SChristian Brauner } 370b4bfe2f6SChristian Brauner 371b4bfe2f6SChristian Brauner static int bm_bpf_reg(void *kdata, struct bpf_link *link) 372b4bfe2f6SChristian Brauner { 373b4bfe2f6SChristian Brauner struct binfmt_misc_ops *ops = kdata; 374b4bfe2f6SChristian Brauner struct bm_bpf_ops_reg *reg; 375b4bfe2f6SChristian Brauner 376b4bfe2f6SChristian Brauner reg = kzalloc_obj(*reg, GFP_KERNEL_ACCOUNT); 377b4bfe2f6SChristian Brauner if (!reg) 378b4bfe2f6SChristian Brauner return -ENOMEM; 379b4bfe2f6SChristian Brauner 380b4bfe2f6SChristian Brauner reg->ops = ops; 381b4bfe2f6SChristian Brauner reg->link = link; 382b4bfe2f6SChristian Brauner reg->user_ns = get_user_ns(current_user_ns()); 383b4bfe2f6SChristian Brauner 384b4bfe2f6SChristian Brauner guard(spinlock)(&bm_bpf_ops_lock); 385b4bfe2f6SChristian Brauner 386b4bfe2f6SChristian Brauner if (bm_bpf_ops_find(reg->user_ns, ops->name)) { 387b4bfe2f6SChristian Brauner put_user_ns(reg->user_ns); 388b4bfe2f6SChristian Brauner kfree(reg); 389b4bfe2f6SChristian Brauner return -EEXIST; 390b4bfe2f6SChristian Brauner } 391b4bfe2f6SChristian Brauner 392b4bfe2f6SChristian Brauner list_add(®->list, &bm_bpf_ops_list); 393b4bfe2f6SChristian Brauner return 0; 394b4bfe2f6SChristian Brauner } 395b4bfe2f6SChristian Brauner 396b4bfe2f6SChristian Brauner static void bm_bpf_unreg(void *kdata, struct bpf_link *link) 397b4bfe2f6SChristian Brauner { 398b4bfe2f6SChristian Brauner struct bm_bpf_ops_reg *reg; 399b4bfe2f6SChristian Brauner 400b4bfe2f6SChristian Brauner guard(spinlock)(&bm_bpf_ops_lock); 401b4bfe2f6SChristian Brauner 402b4bfe2f6SChristian Brauner list_for_each_entry(reg, &bm_bpf_ops_list, list) { 403b4bfe2f6SChristian Brauner if (reg->ops == kdata && reg->link == link) { 404b4bfe2f6SChristian Brauner list_del(®->list); 405b4bfe2f6SChristian Brauner put_user_ns(reg->user_ns); 406b4bfe2f6SChristian Brauner kfree(reg); 407b4bfe2f6SChristian Brauner return; 408b4bfe2f6SChristian Brauner } 409b4bfe2f6SChristian Brauner } 410b4bfe2f6SChristian Brauner } 411b4bfe2f6SChristian Brauner 412b4bfe2f6SChristian Brauner static const struct bpf_verifier_ops bm_bpf_verifier_ops = { 413b4bfe2f6SChristian Brauner .get_func_proto = bpf_base_func_proto, 414b4bfe2f6SChristian Brauner .is_valid_access = bpf_tracing_btf_ctx_access, 415b4bfe2f6SChristian Brauner }; 416b4bfe2f6SChristian Brauner 417b4bfe2f6SChristian Brauner static struct bpf_struct_ops bpf_binfmt_misc_ops = { 418b4bfe2f6SChristian Brauner .verifier_ops = &bm_bpf_verifier_ops, 419b4bfe2f6SChristian Brauner .init = bm_bpf_init, 420b4bfe2f6SChristian Brauner .check_member = bm_bpf_check_member, 421b4bfe2f6SChristian Brauner .init_member = bm_bpf_init_member, 422b4bfe2f6SChristian Brauner .validate = bm_bpf_validate, 423b4bfe2f6SChristian Brauner .reg = bm_bpf_reg, 424b4bfe2f6SChristian Brauner .unreg = bm_bpf_unreg, 425b4bfe2f6SChristian Brauner .cfi_stubs = &bm_bpf_ops_stubs, 426b4bfe2f6SChristian Brauner .name = "binfmt_misc_ops", 427b4bfe2f6SChristian Brauner .owner = THIS_MODULE, 428b4bfe2f6SChristian Brauner }; 429b4bfe2f6SChristian Brauner 430b4bfe2f6SChristian Brauner static int __init bm_bpf_struct_ops_init(void) 431b4bfe2f6SChristian Brauner { 432b4bfe2f6SChristian Brauner return register_bpf_struct_ops(&bpf_binfmt_misc_ops, binfmt_misc_ops); 433b4bfe2f6SChristian Brauner } 434b4bfe2f6SChristian Brauner late_initcall(bm_bpf_struct_ops_init); 435