Lines Matching +full:- +full:e

1 // SPDX-License-Identifier: GPL-2.0-only
8 * a specified wrapper. See Documentation/admin-guide/binfmt-misc.rst for more details.
67 * - 7 delimiters
68 * - name: ~50 bytes
69 * - type: 1 byte
70 * - offset: 3 bytes (has to be smaller than BINPRM_BUF_SIZE)
71 * - magic: 128 bytes (512 in escaped form)
72 * - mask: 128 bytes (512 in escaped form)
73 * - interp: ~50 bytes
74 * - flags: 5 bytes
81 * search_binfmt_handler - search for a binary handler for @bprm
93 char *p = strrchr(bprm->interp, '.'); in search_binfmt_handler()
94 Node *e; in search_binfmt_handler() local
97 list_for_each_entry(e, &misc->entries, list) { in search_binfmt_handler()
102 if (!test_bit(Enabled, &e->flags)) in search_binfmt_handler()
106 if (!test_bit(Magic, &e->flags)) { in search_binfmt_handler()
107 if (p && !strcmp(e->magic, p + 1)) in search_binfmt_handler()
108 return e; in search_binfmt_handler()
113 s = bprm->buf + e->offset; in search_binfmt_handler()
114 if (e->mask) { in search_binfmt_handler()
115 for (j = 0; j < e->size; j++) in search_binfmt_handler()
116 if ((*s++ ^ e->magic[j]) & e->mask[j]) in search_binfmt_handler()
119 for (j = 0; j < e->size; j++) in search_binfmt_handler()
120 if ((*s++ ^ e->magic[j])) in search_binfmt_handler()
123 if (j == e->size) in search_binfmt_handler()
124 return e; in search_binfmt_handler()
131 * get_binfmt_handler - try to find a binary type handler
143 Node *e; in get_binfmt_handler() local
145 read_lock(&misc->entries_lock); in get_binfmt_handler()
146 e = search_binfmt_handler(misc, bprm); in get_binfmt_handler()
147 if (e) in get_binfmt_handler()
148 refcount_inc(&e->users); in get_binfmt_handler()
149 read_unlock(&misc->entries_lock); in get_binfmt_handler()
150 return e; in get_binfmt_handler()
154 * put_binfmt_handler - put binary handler node
155 * @e: node to put
161 static void put_binfmt_handler(Node *e) in put_binfmt_handler() argument
163 if (refcount_dec_and_test(&e->users)) { in put_binfmt_handler()
164 if (e->flags & MISC_FMT_OPEN_FILE) in put_binfmt_handler()
165 filp_close(e->interp_file, NULL); in put_binfmt_handler()
166 kfree(e); in put_binfmt_handler()
171 * load_binfmt_misc - load the binfmt_misc of the caller's user namespace
176 * pre-namespaced binfmt_misc where all registered binfmt_misc handlers where
189 misc = smp_load_acquire(&user_ns->binfmt_misc); in load_binfmt_misc()
193 user_ns = user_ns->parent; in load_binfmt_misc()
206 int retval = -ENOEXEC; in load_misc_binary()
210 if (!misc->enabled) in load_misc_binary()
218 retval = -ENOENT; in load_misc_binary()
219 if (bprm->interp_flags & BINPRM_FLAGS_PATH_INACCESSIBLE) in load_misc_binary()
222 if (fmt->flags & MISC_FMT_PRESERVE_ARGV0) { in load_misc_binary()
223 bprm->interp_flags |= BINPRM_FLAGS_PRESERVE_ARGV0; in load_misc_binary()
230 if (fmt->flags & MISC_FMT_OPEN_BINARY) in load_misc_binary()
231 bprm->have_execfd = 1; in load_misc_binary()
234 retval = copy_string_kernel(bprm->interp, bprm); in load_misc_binary()
237 bprm->argc++; in load_misc_binary()
240 retval = copy_string_kernel(fmt->interpreter, bprm); in load_misc_binary()
243 bprm->argc++; in load_misc_binary()
246 retval = bprm_change_interp(fmt->interpreter, bprm); in load_misc_binary()
250 if (fmt->flags & MISC_FMT_OPEN_FILE) { in load_misc_binary()
251 interp_file = file_clone_open(fmt->interp_file); in load_misc_binary()
255 interp_file = open_exec(fmt->interpreter); in load_misc_binary()
261 bprm->interpreter = interp_file; in load_misc_binary()
262 if (fmt->flags & MISC_FMT_CREDENTIALS) in load_misc_binary()
263 bprm->execfd_creds = 1; in load_misc_binary()
301 s[-1] ='\0'; in scanarg()
305 static char *check_special_flags(char *sfs, Node *e) in check_special_flags() argument
316 e->flags |= MISC_FMT_PRESERVE_ARGV0; in check_special_flags()
321 e->flags |= MISC_FMT_OPEN_BINARY; in check_special_flags()
327 open-binary flag */ in check_special_flags()
328 e->flags |= (MISC_FMT_CREDENTIALS | in check_special_flags()
334 e->flags |= MISC_FMT_OPEN_FILE; in check_special_flags()
351 Node *e; in create_entry() local
359 err = -EINVAL; in create_entry()
363 err = -ENOMEM; in create_entry()
365 e = kmalloc(memsize, GFP_KERNEL_ACCOUNT); in create_entry()
366 if (!e) in create_entry()
369 p = buf = (char *)e + sizeof(Node); in create_entry()
371 memset(e, 0, sizeof(Node)); in create_entry()
383 e->name = p; in create_entry()
388 if (!e->name[0] || in create_entry()
389 !strcmp(e->name, ".") || in create_entry()
390 !strcmp(e->name, "..") || in create_entry()
391 strchr(e->name, '/')) in create_entry()
394 pr_debug("register: name: {%s}\n", e->name); in create_entry()
398 case 'E': in create_entry()
399 pr_debug("register: type: E (extension)\n"); in create_entry()
400 e->flags = 1 << Enabled; in create_entry()
404 e->flags = (1 << Enabled) | (1 << Magic); in create_entry()
412 if (test_bit(Magic, &e->flags)) { in create_entry()
422 int r = kstrtoint(p, 10, &e->offset); in create_entry()
423 if (r != 0 || e->offset < 0) in create_entry()
429 pr_debug("register: offset: %#x\n", e->offset); in create_entry()
432 e->magic = p; in create_entry()
436 if (!e->magic[0]) in create_entry()
441 DUMP_PREFIX_NONE, e->magic, p - e->magic); in create_entry()
444 e->mask = p; in create_entry()
448 if (!e->mask[0]) { in create_entry()
449 e->mask = NULL; in create_entry()
454 DUMP_PREFIX_NONE, e->mask, p - e->mask); in create_entry()
462 e->size = string_unescape_inplace(e->magic, UNESCAPE_HEX); in create_entry()
463 if (e->mask && in create_entry()
464 string_unescape_inplace(e->mask, UNESCAPE_HEX) != e->size) in create_entry()
466 if (e->size > BINPRM_BUF_SIZE || in create_entry()
467 BINPRM_BUF_SIZE - e->size < e->offset) in create_entry()
469 pr_debug("register: magic/mask length: %i\n", e->size); in create_entry()
473 DUMP_PREFIX_NONE, e->magic, e->size); in create_entry()
475 if (e->mask) { in create_entry()
477 char *masked = kmalloc(e->size, GFP_KERNEL_ACCOUNT); in create_entry()
481 DUMP_PREFIX_NONE, e->mask, e->size); in create_entry()
484 for (i = 0; i < e->size; ++i) in create_entry()
485 masked[i] = e->magic[i] & e->mask[i]; in create_entry()
488 DUMP_PREFIX_NONE, masked, e->size); in create_entry()
495 /* Handle the 'E' (extension) format. */ in create_entry()
504 e->magic = p; in create_entry()
509 if (!e->magic[0] || strchr(e->magic, '/')) in create_entry()
511 pr_debug("register: extension: {%s}\n", e->magic); in create_entry()
521 e->interpreter = p; in create_entry()
526 if (!e->interpreter[0]) in create_entry()
528 pr_debug("register: interpreter: {%s}\n", e->interpreter); in create_entry()
531 p = check_special_flags(p, e); in create_entry()
537 return e; in create_entry()
543 kfree(e); in create_entry()
544 return ERR_PTR(-EFAULT); in create_entry()
546 kfree(e); in create_entry()
547 return ERR_PTR(-EINVAL); in create_entry()
552 * '1' enables, '0' disables and '-1' clears entry/binfmt_misc
559 return -EINVAL; in parse_command()
561 return -EFAULT; in parse_command()
564 if (s[count - 1] == '\n') in parse_command()
565 count--; in parse_command()
570 if (count == 2 && s[0] == '-' && s[1] == '1') in parse_command()
572 return -EINVAL; in parse_command()
577 static void entry_status(Node *e, char *page) in entry_status() argument
582 if (test_bit(Enabled, &e->flags)) in entry_status()
590 dp += sprintf(dp, "%s\ninterpreter %s\n", status, e->interpreter); in entry_status()
594 if (e->flags & MISC_FMT_PRESERVE_ARGV0) in entry_status()
596 if (e->flags & MISC_FMT_OPEN_BINARY) in entry_status()
598 if (e->flags & MISC_FMT_CREDENTIALS) in entry_status()
600 if (e->flags & MISC_FMT_OPEN_FILE) in entry_status()
604 if (!test_bit(Magic, &e->flags)) { in entry_status()
605 sprintf(dp, "extension .%s\n", e->magic); in entry_status()
607 dp += sprintf(dp, "offset %i\nmagic ", e->offset); in entry_status()
608 dp = bin2hex(dp, e->magic, e->size); in entry_status()
609 if (e->mask) { in entry_status()
611 dp = bin2hex(dp, e->mask, e->size); in entry_status()
623 inode->i_ino = get_next_ino(); in bm_get_inode()
624 inode->i_mode = mode; in bm_get_inode()
631 * i_binfmt_misc - retrieve struct binfmt_misc from a binfmt_misc inode
636 * user_ns->binfmt_misc is fully initialized. It was fully initialized when the
643 return inode->i_sb->s_user_ns->binfmt_misc; in i_binfmt_misc()
647 * bm_evict_inode - cleanup data associated with @inode
654 * If the ->evict call was not caused by a super block shutdown but by a write
661 Node *e = inode->i_private; in bm_evict_inode() local
665 if (e) { in bm_evict_inode()
669 write_lock(&misc->entries_lock); in bm_evict_inode()
670 if (!list_empty(&e->list)) in bm_evict_inode()
671 list_del_init(&e->list); in bm_evict_inode()
672 write_unlock(&misc->entries_lock); in bm_evict_inode()
673 put_binfmt_handler(e); in bm_evict_inode()
678 * unlink_binfmt_dentry - remove the dentry for the binary type handler
690 struct dentry *parent = dentry->d_parent; in unlink_binfmt_dentry()
694 if (WARN_ON_ONCE(dentry->d_sb->s_root != parent)) in unlink_binfmt_dentry()
699 if (WARN_ON_ONCE(!S_ISREG(inode->i_mode))) in unlink_binfmt_dentry()
716 * remove_binfmt_handler - remove a binary type handler
718 * @e: binary type handler to remove
723 * adding a proper ->unlink() method to binfmt_misc instead of forcing caller's
727 static void remove_binfmt_handler(struct binfmt_misc *misc, Node *e) in remove_binfmt_handler() argument
729 write_lock(&misc->entries_lock); in remove_binfmt_handler()
730 list_del_init(&e->list); in remove_binfmt_handler()
731 write_unlock(&misc->entries_lock); in remove_binfmt_handler()
732 unlink_binfmt_dentry(e->dentry); in remove_binfmt_handler()
740 Node *e = file_inode(file)->i_private; in bm_entry_read() local
746 return -ENOMEM; in bm_entry_read()
748 entry_status(e, page); in bm_entry_read()
760 Node *e = inode->i_private; in bm_entry_write() local
766 clear_bit(Enabled, &e->flags); in bm_entry_write()
770 set_bit(Enabled, &e->flags); in bm_entry_write()
774 inode = d_inode(inode->i_sb->s_root); in bm_entry_write()
783 * read-only. So we only need to take the write lock when we in bm_entry_write()
786 if (!list_empty(&e->list)) in bm_entry_write()
787 remove_binfmt_handler(i_binfmt_misc(inode), e); in bm_entry_write()
809 Node *e; in bm_register_write() local
811 struct super_block *sb = file_inode(file)->i_sb; in bm_register_write()
812 struct dentry *root = sb->s_root, *dentry; in bm_register_write()
817 e = create_entry(buffer, count); in bm_register_write()
819 if (IS_ERR(e)) in bm_register_write()
820 return PTR_ERR(e); in bm_register_write()
822 if (e->flags & MISC_FMT_OPEN_FILE) { in bm_register_write()
832 old_cred = override_creds(file->f_cred); in bm_register_write()
833 f = open_exec(e->interpreter); in bm_register_write()
837 e->interpreter); in bm_register_write()
838 kfree(e); in bm_register_write()
841 e->interp_file = f; in bm_register_write()
845 dentry = lookup_one_len(e->name, root, strlen(e->name)); in bm_register_write()
850 err = -EEXIST; in bm_register_write()
856 err = -ENOMEM; in bm_register_write()
860 refcount_set(&e->users, 1); in bm_register_write()
861 e->dentry = dget(dentry); in bm_register_write()
862 inode->i_private = e; in bm_register_write()
863 inode->i_fop = &bm_entry_operations; in bm_register_write()
867 write_lock(&misc->entries_lock); in bm_register_write()
868 list_add(&e->list, &misc->entries); in bm_register_write()
869 write_unlock(&misc->entries_lock); in bm_register_write()
880 kfree(e); in bm_register_write()
900 s = misc->enabled ? "enabled\n" : "disabled\n"; in bm_status_read()
909 Node *e, *next; in bm_status_write() local
916 misc->enabled = false; in bm_status_write()
920 misc->enabled = true; in bm_status_write()
924 inode = d_inode(file_inode(file)->i_sb->s_root); in bm_status_write()
933 * read-only. So we only need to take the write lock when we in bm_status_write()
936 list_for_each_entry_safe(e, next, &misc->entries, list) in bm_status_write()
937 remove_binfmt_handler(misc, e); in bm_status_write()
958 struct user_namespace *user_ns = sb->s_fs_info; in bm_put_super()
960 sb->s_fs_info = NULL; in bm_put_super()
973 struct user_namespace *user_ns = sb->s_user_ns; in bm_fill_super()
982 return -EINVAL; in bm_fill_super()
985 * Lazily allocate a new binfmt_misc instance for this namespace, i.e. in bm_fill_super()
999 misc = user_ns->binfmt_misc; in bm_fill_super()
1009 return -ENOMEM; in bm_fill_super()
1011 INIT_LIST_HEAD(&misc->entries); in bm_fill_super()
1012 rwlock_init(&misc->entries_lock); in bm_fill_super()
1015 smp_store_release(&user_ns->binfmt_misc, misc); in bm_fill_super()
1020 * ->enabled might have been set to false and we don't reinitialize in bm_fill_super()
1021 * ->enabled again in put_super() as someone might already be mounting in bm_fill_super()
1023 * ->put_super() is called we know that the binary type list for this in bm_fill_super()
1025 * -ENOEXEC independent of whether ->enabled is true. Instead, if in bm_fill_super()
1027 * reset ->enabled to true. in bm_fill_super()
1029 misc->enabled = true; in bm_fill_super()
1033 sb->s_op = &s_ops; in bm_fill_super()
1039 if (fc->s_fs_info) in bm_free()
1040 put_user_ns(fc->s_fs_info); in bm_free()
1045 return get_tree_keyed(fc, bm_fill_super, get_user_ns(fc->user_ns)); in bm_get_tree()
1055 fc->ops = &bm_context_ops; in bm_init_fs_context()