162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * binfmt_misc.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 1997 Richard Günther 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * binfmt_misc detects binaries via a magic or filename extension and invokes 862306a36Sopenharmony_ci * a specified wrapper. See Documentation/admin-guide/binfmt-misc.rst for more details. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/kernel.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/init.h> 1662306a36Sopenharmony_ci#include <linux/sched/mm.h> 1762306a36Sopenharmony_ci#include <linux/magic.h> 1862306a36Sopenharmony_ci#include <linux/binfmts.h> 1962306a36Sopenharmony_ci#include <linux/slab.h> 2062306a36Sopenharmony_ci#include <linux/ctype.h> 2162306a36Sopenharmony_ci#include <linux/string_helpers.h> 2262306a36Sopenharmony_ci#include <linux/file.h> 2362306a36Sopenharmony_ci#include <linux/pagemap.h> 2462306a36Sopenharmony_ci#include <linux/namei.h> 2562306a36Sopenharmony_ci#include <linux/mount.h> 2662306a36Sopenharmony_ci#include <linux/fs_context.h> 2762306a36Sopenharmony_ci#include <linux/syscalls.h> 2862306a36Sopenharmony_ci#include <linux/fs.h> 2962306a36Sopenharmony_ci#include <linux/uaccess.h> 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#include "internal.h" 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#ifdef DEBUG 3462306a36Sopenharmony_ci# define USE_DEBUG 1 3562306a36Sopenharmony_ci#else 3662306a36Sopenharmony_ci# define USE_DEBUG 0 3762306a36Sopenharmony_ci#endif 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cienum { 4062306a36Sopenharmony_ci VERBOSE_STATUS = 1 /* make it zero to save 400 bytes kernel memory */ 4162306a36Sopenharmony_ci}; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic LIST_HEAD(entries); 4462306a36Sopenharmony_cistatic int enabled = 1; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cienum {Enabled, Magic}; 4762306a36Sopenharmony_ci#define MISC_FMT_PRESERVE_ARGV0 (1UL << 31) 4862306a36Sopenharmony_ci#define MISC_FMT_OPEN_BINARY (1UL << 30) 4962306a36Sopenharmony_ci#define MISC_FMT_CREDENTIALS (1UL << 29) 5062306a36Sopenharmony_ci#define MISC_FMT_OPEN_FILE (1UL << 28) 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_citypedef struct { 5362306a36Sopenharmony_ci struct list_head list; 5462306a36Sopenharmony_ci unsigned long flags; /* type, status, etc. */ 5562306a36Sopenharmony_ci int offset; /* offset of magic */ 5662306a36Sopenharmony_ci int size; /* size of magic/mask */ 5762306a36Sopenharmony_ci char *magic; /* magic or filename extension */ 5862306a36Sopenharmony_ci char *mask; /* mask, NULL for exact match */ 5962306a36Sopenharmony_ci const char *interpreter; /* filename of interpreter */ 6062306a36Sopenharmony_ci char *name; 6162306a36Sopenharmony_ci struct dentry *dentry; 6262306a36Sopenharmony_ci struct file *interp_file; 6362306a36Sopenharmony_ci} Node; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic DEFINE_RWLOCK(entries_lock); 6662306a36Sopenharmony_cistatic struct file_system_type bm_fs_type; 6762306a36Sopenharmony_cistatic struct vfsmount *bm_mnt; 6862306a36Sopenharmony_cistatic int entry_count; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci/* 7162306a36Sopenharmony_ci * Max length of the register string. Determined by: 7262306a36Sopenharmony_ci * - 7 delimiters 7362306a36Sopenharmony_ci * - name: ~50 bytes 7462306a36Sopenharmony_ci * - type: 1 byte 7562306a36Sopenharmony_ci * - offset: 3 bytes (has to be smaller than BINPRM_BUF_SIZE) 7662306a36Sopenharmony_ci * - magic: 128 bytes (512 in escaped form) 7762306a36Sopenharmony_ci * - mask: 128 bytes (512 in escaped form) 7862306a36Sopenharmony_ci * - interp: ~50 bytes 7962306a36Sopenharmony_ci * - flags: 5 bytes 8062306a36Sopenharmony_ci * Round that up a bit, and then back off to hold the internal data 8162306a36Sopenharmony_ci * (like struct Node). 8262306a36Sopenharmony_ci */ 8362306a36Sopenharmony_ci#define MAX_REGISTER_LENGTH 1920 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci/* 8662306a36Sopenharmony_ci * Check if we support the binfmt 8762306a36Sopenharmony_ci * if we do, return the node, else NULL 8862306a36Sopenharmony_ci * locking is done in load_misc_binary 8962306a36Sopenharmony_ci */ 9062306a36Sopenharmony_cistatic Node *check_file(struct linux_binprm *bprm) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci char *p = strrchr(bprm->interp, '.'); 9362306a36Sopenharmony_ci struct list_head *l; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci /* Walk all the registered handlers. */ 9662306a36Sopenharmony_ci list_for_each(l, &entries) { 9762306a36Sopenharmony_ci Node *e = list_entry(l, Node, list); 9862306a36Sopenharmony_ci char *s; 9962306a36Sopenharmony_ci int j; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci /* Make sure this one is currently enabled. */ 10262306a36Sopenharmony_ci if (!test_bit(Enabled, &e->flags)) 10362306a36Sopenharmony_ci continue; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci /* Do matching based on extension if applicable. */ 10662306a36Sopenharmony_ci if (!test_bit(Magic, &e->flags)) { 10762306a36Sopenharmony_ci if (p && !strcmp(e->magic, p + 1)) 10862306a36Sopenharmony_ci return e; 10962306a36Sopenharmony_ci continue; 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci /* Do matching based on magic & mask. */ 11362306a36Sopenharmony_ci s = bprm->buf + e->offset; 11462306a36Sopenharmony_ci if (e->mask) { 11562306a36Sopenharmony_ci for (j = 0; j < e->size; j++) 11662306a36Sopenharmony_ci if ((*s++ ^ e->magic[j]) & e->mask[j]) 11762306a36Sopenharmony_ci break; 11862306a36Sopenharmony_ci } else { 11962306a36Sopenharmony_ci for (j = 0; j < e->size; j++) 12062306a36Sopenharmony_ci if ((*s++ ^ e->magic[j])) 12162306a36Sopenharmony_ci break; 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci if (j == e->size) 12462306a36Sopenharmony_ci return e; 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci return NULL; 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci/* 13062306a36Sopenharmony_ci * the loader itself 13162306a36Sopenharmony_ci */ 13262306a36Sopenharmony_cistatic int load_misc_binary(struct linux_binprm *bprm) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci Node *fmt; 13562306a36Sopenharmony_ci struct file *interp_file = NULL; 13662306a36Sopenharmony_ci int retval; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci retval = -ENOEXEC; 13962306a36Sopenharmony_ci if (!enabled) 14062306a36Sopenharmony_ci return retval; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci /* to keep locking time low, we copy the interpreter string */ 14362306a36Sopenharmony_ci read_lock(&entries_lock); 14462306a36Sopenharmony_ci fmt = check_file(bprm); 14562306a36Sopenharmony_ci if (fmt) 14662306a36Sopenharmony_ci dget(fmt->dentry); 14762306a36Sopenharmony_ci read_unlock(&entries_lock); 14862306a36Sopenharmony_ci if (!fmt) 14962306a36Sopenharmony_ci return retval; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci /* Need to be able to load the file after exec */ 15262306a36Sopenharmony_ci retval = -ENOENT; 15362306a36Sopenharmony_ci if (bprm->interp_flags & BINPRM_FLAGS_PATH_INACCESSIBLE) 15462306a36Sopenharmony_ci goto ret; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci if (fmt->flags & MISC_FMT_PRESERVE_ARGV0) { 15762306a36Sopenharmony_ci bprm->interp_flags |= BINPRM_FLAGS_PRESERVE_ARGV0; 15862306a36Sopenharmony_ci } else { 15962306a36Sopenharmony_ci retval = remove_arg_zero(bprm); 16062306a36Sopenharmony_ci if (retval) 16162306a36Sopenharmony_ci goto ret; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci if (fmt->flags & MISC_FMT_OPEN_BINARY) 16562306a36Sopenharmony_ci bprm->have_execfd = 1; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci /* make argv[1] be the path to the binary */ 16862306a36Sopenharmony_ci retval = copy_string_kernel(bprm->interp, bprm); 16962306a36Sopenharmony_ci if (retval < 0) 17062306a36Sopenharmony_ci goto ret; 17162306a36Sopenharmony_ci bprm->argc++; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci /* add the interp as argv[0] */ 17462306a36Sopenharmony_ci retval = copy_string_kernel(fmt->interpreter, bprm); 17562306a36Sopenharmony_ci if (retval < 0) 17662306a36Sopenharmony_ci goto ret; 17762306a36Sopenharmony_ci bprm->argc++; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci /* Update interp in case binfmt_script needs it. */ 18062306a36Sopenharmony_ci retval = bprm_change_interp(fmt->interpreter, bprm); 18162306a36Sopenharmony_ci if (retval < 0) 18262306a36Sopenharmony_ci goto ret; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci if (fmt->flags & MISC_FMT_OPEN_FILE) { 18562306a36Sopenharmony_ci interp_file = file_clone_open(fmt->interp_file); 18662306a36Sopenharmony_ci if (!IS_ERR(interp_file)) 18762306a36Sopenharmony_ci deny_write_access(interp_file); 18862306a36Sopenharmony_ci } else { 18962306a36Sopenharmony_ci interp_file = open_exec(fmt->interpreter); 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci retval = PTR_ERR(interp_file); 19262306a36Sopenharmony_ci if (IS_ERR(interp_file)) 19362306a36Sopenharmony_ci goto ret; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci bprm->interpreter = interp_file; 19662306a36Sopenharmony_ci if (fmt->flags & MISC_FMT_CREDENTIALS) 19762306a36Sopenharmony_ci bprm->execfd_creds = 1; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci retval = 0; 20062306a36Sopenharmony_ciret: 20162306a36Sopenharmony_ci dput(fmt->dentry); 20262306a36Sopenharmony_ci return retval; 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci/* Command parsers */ 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci/* 20862306a36Sopenharmony_ci * parses and copies one argument enclosed in del from *sp to *dp, 20962306a36Sopenharmony_ci * recognising the \x special. 21062306a36Sopenharmony_ci * returns pointer to the copied argument or NULL in case of an 21162306a36Sopenharmony_ci * error (and sets err) or null argument length. 21262306a36Sopenharmony_ci */ 21362306a36Sopenharmony_cistatic char *scanarg(char *s, char del) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci char c; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci while ((c = *s++) != del) { 21862306a36Sopenharmony_ci if (c == '\\' && *s == 'x') { 21962306a36Sopenharmony_ci s++; 22062306a36Sopenharmony_ci if (!isxdigit(*s++)) 22162306a36Sopenharmony_ci return NULL; 22262306a36Sopenharmony_ci if (!isxdigit(*s++)) 22362306a36Sopenharmony_ci return NULL; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci s[-1] ='\0'; 22762306a36Sopenharmony_ci return s; 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic char *check_special_flags(char *sfs, Node *e) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci char *p = sfs; 23362306a36Sopenharmony_ci int cont = 1; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci /* special flags */ 23662306a36Sopenharmony_ci while (cont) { 23762306a36Sopenharmony_ci switch (*p) { 23862306a36Sopenharmony_ci case 'P': 23962306a36Sopenharmony_ci pr_debug("register: flag: P (preserve argv0)\n"); 24062306a36Sopenharmony_ci p++; 24162306a36Sopenharmony_ci e->flags |= MISC_FMT_PRESERVE_ARGV0; 24262306a36Sopenharmony_ci break; 24362306a36Sopenharmony_ci case 'O': 24462306a36Sopenharmony_ci pr_debug("register: flag: O (open binary)\n"); 24562306a36Sopenharmony_ci p++; 24662306a36Sopenharmony_ci e->flags |= MISC_FMT_OPEN_BINARY; 24762306a36Sopenharmony_ci break; 24862306a36Sopenharmony_ci case 'C': 24962306a36Sopenharmony_ci pr_debug("register: flag: C (preserve creds)\n"); 25062306a36Sopenharmony_ci p++; 25162306a36Sopenharmony_ci /* this flags also implies the 25262306a36Sopenharmony_ci open-binary flag */ 25362306a36Sopenharmony_ci e->flags |= (MISC_FMT_CREDENTIALS | 25462306a36Sopenharmony_ci MISC_FMT_OPEN_BINARY); 25562306a36Sopenharmony_ci break; 25662306a36Sopenharmony_ci case 'F': 25762306a36Sopenharmony_ci pr_debug("register: flag: F: open interpreter file now\n"); 25862306a36Sopenharmony_ci p++; 25962306a36Sopenharmony_ci e->flags |= MISC_FMT_OPEN_FILE; 26062306a36Sopenharmony_ci break; 26162306a36Sopenharmony_ci default: 26262306a36Sopenharmony_ci cont = 0; 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci return p; 26762306a36Sopenharmony_ci} 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci/* 27062306a36Sopenharmony_ci * This registers a new binary format, it recognises the syntax 27162306a36Sopenharmony_ci * ':name:type:offset:magic:mask:interpreter:flags' 27262306a36Sopenharmony_ci * where the ':' is the IFS, that can be chosen with the first char 27362306a36Sopenharmony_ci */ 27462306a36Sopenharmony_cistatic Node *create_entry(const char __user *buffer, size_t count) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci Node *e; 27762306a36Sopenharmony_ci int memsize, err; 27862306a36Sopenharmony_ci char *buf, *p; 27962306a36Sopenharmony_ci char del; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci pr_debug("register: received %zu bytes\n", count); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci /* some sanity checks */ 28462306a36Sopenharmony_ci err = -EINVAL; 28562306a36Sopenharmony_ci if ((count < 11) || (count > MAX_REGISTER_LENGTH)) 28662306a36Sopenharmony_ci goto out; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci err = -ENOMEM; 28962306a36Sopenharmony_ci memsize = sizeof(Node) + count + 8; 29062306a36Sopenharmony_ci e = kmalloc(memsize, GFP_KERNEL); 29162306a36Sopenharmony_ci if (!e) 29262306a36Sopenharmony_ci goto out; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci p = buf = (char *)e + sizeof(Node); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci memset(e, 0, sizeof(Node)); 29762306a36Sopenharmony_ci if (copy_from_user(buf, buffer, count)) 29862306a36Sopenharmony_ci goto efault; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci del = *p++; /* delimeter */ 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci pr_debug("register: delim: %#x {%c}\n", del, del); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci /* Pad the buffer with the delim to simplify parsing below. */ 30562306a36Sopenharmony_ci memset(buf + count, del, 8); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci /* Parse the 'name' field. */ 30862306a36Sopenharmony_ci e->name = p; 30962306a36Sopenharmony_ci p = strchr(p, del); 31062306a36Sopenharmony_ci if (!p) 31162306a36Sopenharmony_ci goto einval; 31262306a36Sopenharmony_ci *p++ = '\0'; 31362306a36Sopenharmony_ci if (!e->name[0] || 31462306a36Sopenharmony_ci !strcmp(e->name, ".") || 31562306a36Sopenharmony_ci !strcmp(e->name, "..") || 31662306a36Sopenharmony_ci strchr(e->name, '/')) 31762306a36Sopenharmony_ci goto einval; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci pr_debug("register: name: {%s}\n", e->name); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci /* Parse the 'type' field. */ 32262306a36Sopenharmony_ci switch (*p++) { 32362306a36Sopenharmony_ci case 'E': 32462306a36Sopenharmony_ci pr_debug("register: type: E (extension)\n"); 32562306a36Sopenharmony_ci e->flags = 1 << Enabled; 32662306a36Sopenharmony_ci break; 32762306a36Sopenharmony_ci case 'M': 32862306a36Sopenharmony_ci pr_debug("register: type: M (magic)\n"); 32962306a36Sopenharmony_ci e->flags = (1 << Enabled) | (1 << Magic); 33062306a36Sopenharmony_ci break; 33162306a36Sopenharmony_ci default: 33262306a36Sopenharmony_ci goto einval; 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci if (*p++ != del) 33562306a36Sopenharmony_ci goto einval; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci if (test_bit(Magic, &e->flags)) { 33862306a36Sopenharmony_ci /* Handle the 'M' (magic) format. */ 33962306a36Sopenharmony_ci char *s; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci /* Parse the 'offset' field. */ 34262306a36Sopenharmony_ci s = strchr(p, del); 34362306a36Sopenharmony_ci if (!s) 34462306a36Sopenharmony_ci goto einval; 34562306a36Sopenharmony_ci *s = '\0'; 34662306a36Sopenharmony_ci if (p != s) { 34762306a36Sopenharmony_ci int r = kstrtoint(p, 10, &e->offset); 34862306a36Sopenharmony_ci if (r != 0 || e->offset < 0) 34962306a36Sopenharmony_ci goto einval; 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci p = s; 35262306a36Sopenharmony_ci if (*p++) 35362306a36Sopenharmony_ci goto einval; 35462306a36Sopenharmony_ci pr_debug("register: offset: %#x\n", e->offset); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci /* Parse the 'magic' field. */ 35762306a36Sopenharmony_ci e->magic = p; 35862306a36Sopenharmony_ci p = scanarg(p, del); 35962306a36Sopenharmony_ci if (!p) 36062306a36Sopenharmony_ci goto einval; 36162306a36Sopenharmony_ci if (!e->magic[0]) 36262306a36Sopenharmony_ci goto einval; 36362306a36Sopenharmony_ci if (USE_DEBUG) 36462306a36Sopenharmony_ci print_hex_dump_bytes( 36562306a36Sopenharmony_ci KBUILD_MODNAME ": register: magic[raw]: ", 36662306a36Sopenharmony_ci DUMP_PREFIX_NONE, e->magic, p - e->magic); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci /* Parse the 'mask' field. */ 36962306a36Sopenharmony_ci e->mask = p; 37062306a36Sopenharmony_ci p = scanarg(p, del); 37162306a36Sopenharmony_ci if (!p) 37262306a36Sopenharmony_ci goto einval; 37362306a36Sopenharmony_ci if (!e->mask[0]) { 37462306a36Sopenharmony_ci e->mask = NULL; 37562306a36Sopenharmony_ci pr_debug("register: mask[raw]: none\n"); 37662306a36Sopenharmony_ci } else if (USE_DEBUG) 37762306a36Sopenharmony_ci print_hex_dump_bytes( 37862306a36Sopenharmony_ci KBUILD_MODNAME ": register: mask[raw]: ", 37962306a36Sopenharmony_ci DUMP_PREFIX_NONE, e->mask, p - e->mask); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci /* 38262306a36Sopenharmony_ci * Decode the magic & mask fields. 38362306a36Sopenharmony_ci * Note: while we might have accepted embedded NUL bytes from 38462306a36Sopenharmony_ci * above, the unescape helpers here will stop at the first one 38562306a36Sopenharmony_ci * it encounters. 38662306a36Sopenharmony_ci */ 38762306a36Sopenharmony_ci e->size = string_unescape_inplace(e->magic, UNESCAPE_HEX); 38862306a36Sopenharmony_ci if (e->mask && 38962306a36Sopenharmony_ci string_unescape_inplace(e->mask, UNESCAPE_HEX) != e->size) 39062306a36Sopenharmony_ci goto einval; 39162306a36Sopenharmony_ci if (e->size > BINPRM_BUF_SIZE || 39262306a36Sopenharmony_ci BINPRM_BUF_SIZE - e->size < e->offset) 39362306a36Sopenharmony_ci goto einval; 39462306a36Sopenharmony_ci pr_debug("register: magic/mask length: %i\n", e->size); 39562306a36Sopenharmony_ci if (USE_DEBUG) { 39662306a36Sopenharmony_ci print_hex_dump_bytes( 39762306a36Sopenharmony_ci KBUILD_MODNAME ": register: magic[decoded]: ", 39862306a36Sopenharmony_ci DUMP_PREFIX_NONE, e->magic, e->size); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci if (e->mask) { 40162306a36Sopenharmony_ci int i; 40262306a36Sopenharmony_ci char *masked = kmalloc(e->size, GFP_KERNEL); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci print_hex_dump_bytes( 40562306a36Sopenharmony_ci KBUILD_MODNAME ": register: mask[decoded]: ", 40662306a36Sopenharmony_ci DUMP_PREFIX_NONE, e->mask, e->size); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if (masked) { 40962306a36Sopenharmony_ci for (i = 0; i < e->size; ++i) 41062306a36Sopenharmony_ci masked[i] = e->magic[i] & e->mask[i]; 41162306a36Sopenharmony_ci print_hex_dump_bytes( 41262306a36Sopenharmony_ci KBUILD_MODNAME ": register: magic[masked]: ", 41362306a36Sopenharmony_ci DUMP_PREFIX_NONE, masked, e->size); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci kfree(masked); 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci } else { 42062306a36Sopenharmony_ci /* Handle the 'E' (extension) format. */ 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci /* Skip the 'offset' field. */ 42362306a36Sopenharmony_ci p = strchr(p, del); 42462306a36Sopenharmony_ci if (!p) 42562306a36Sopenharmony_ci goto einval; 42662306a36Sopenharmony_ci *p++ = '\0'; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci /* Parse the 'magic' field. */ 42962306a36Sopenharmony_ci e->magic = p; 43062306a36Sopenharmony_ci p = strchr(p, del); 43162306a36Sopenharmony_ci if (!p) 43262306a36Sopenharmony_ci goto einval; 43362306a36Sopenharmony_ci *p++ = '\0'; 43462306a36Sopenharmony_ci if (!e->magic[0] || strchr(e->magic, '/')) 43562306a36Sopenharmony_ci goto einval; 43662306a36Sopenharmony_ci pr_debug("register: extension: {%s}\n", e->magic); 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci /* Skip the 'mask' field. */ 43962306a36Sopenharmony_ci p = strchr(p, del); 44062306a36Sopenharmony_ci if (!p) 44162306a36Sopenharmony_ci goto einval; 44262306a36Sopenharmony_ci *p++ = '\0'; 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci /* Parse the 'interpreter' field. */ 44662306a36Sopenharmony_ci e->interpreter = p; 44762306a36Sopenharmony_ci p = strchr(p, del); 44862306a36Sopenharmony_ci if (!p) 44962306a36Sopenharmony_ci goto einval; 45062306a36Sopenharmony_ci *p++ = '\0'; 45162306a36Sopenharmony_ci if (!e->interpreter[0]) 45262306a36Sopenharmony_ci goto einval; 45362306a36Sopenharmony_ci pr_debug("register: interpreter: {%s}\n", e->interpreter); 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci /* Parse the 'flags' field. */ 45662306a36Sopenharmony_ci p = check_special_flags(p, e); 45762306a36Sopenharmony_ci if (*p == '\n') 45862306a36Sopenharmony_ci p++; 45962306a36Sopenharmony_ci if (p != buf + count) 46062306a36Sopenharmony_ci goto einval; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci return e; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ciout: 46562306a36Sopenharmony_ci return ERR_PTR(err); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ciefault: 46862306a36Sopenharmony_ci kfree(e); 46962306a36Sopenharmony_ci return ERR_PTR(-EFAULT); 47062306a36Sopenharmony_cieinval: 47162306a36Sopenharmony_ci kfree(e); 47262306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci/* 47662306a36Sopenharmony_ci * Set status of entry/binfmt_misc: 47762306a36Sopenharmony_ci * '1' enables, '0' disables and '-1' clears entry/binfmt_misc 47862306a36Sopenharmony_ci */ 47962306a36Sopenharmony_cistatic int parse_command(const char __user *buffer, size_t count) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci char s[4]; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci if (count > 3) 48462306a36Sopenharmony_ci return -EINVAL; 48562306a36Sopenharmony_ci if (copy_from_user(s, buffer, count)) 48662306a36Sopenharmony_ci return -EFAULT; 48762306a36Sopenharmony_ci if (!count) 48862306a36Sopenharmony_ci return 0; 48962306a36Sopenharmony_ci if (s[count - 1] == '\n') 49062306a36Sopenharmony_ci count--; 49162306a36Sopenharmony_ci if (count == 1 && s[0] == '0') 49262306a36Sopenharmony_ci return 1; 49362306a36Sopenharmony_ci if (count == 1 && s[0] == '1') 49462306a36Sopenharmony_ci return 2; 49562306a36Sopenharmony_ci if (count == 2 && s[0] == '-' && s[1] == '1') 49662306a36Sopenharmony_ci return 3; 49762306a36Sopenharmony_ci return -EINVAL; 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci/* generic stuff */ 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_cistatic void entry_status(Node *e, char *page) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci char *dp = page; 50562306a36Sopenharmony_ci const char *status = "disabled"; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci if (test_bit(Enabled, &e->flags)) 50862306a36Sopenharmony_ci status = "enabled"; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci if (!VERBOSE_STATUS) { 51162306a36Sopenharmony_ci sprintf(page, "%s\n", status); 51262306a36Sopenharmony_ci return; 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci dp += sprintf(dp, "%s\ninterpreter %s\n", status, e->interpreter); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci /* print the special flags */ 51862306a36Sopenharmony_ci dp += sprintf(dp, "flags: "); 51962306a36Sopenharmony_ci if (e->flags & MISC_FMT_PRESERVE_ARGV0) 52062306a36Sopenharmony_ci *dp++ = 'P'; 52162306a36Sopenharmony_ci if (e->flags & MISC_FMT_OPEN_BINARY) 52262306a36Sopenharmony_ci *dp++ = 'O'; 52362306a36Sopenharmony_ci if (e->flags & MISC_FMT_CREDENTIALS) 52462306a36Sopenharmony_ci *dp++ = 'C'; 52562306a36Sopenharmony_ci if (e->flags & MISC_FMT_OPEN_FILE) 52662306a36Sopenharmony_ci *dp++ = 'F'; 52762306a36Sopenharmony_ci *dp++ = '\n'; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci if (!test_bit(Magic, &e->flags)) { 53062306a36Sopenharmony_ci sprintf(dp, "extension .%s\n", e->magic); 53162306a36Sopenharmony_ci } else { 53262306a36Sopenharmony_ci dp += sprintf(dp, "offset %i\nmagic ", e->offset); 53362306a36Sopenharmony_ci dp = bin2hex(dp, e->magic, e->size); 53462306a36Sopenharmony_ci if (e->mask) { 53562306a36Sopenharmony_ci dp += sprintf(dp, "\nmask "); 53662306a36Sopenharmony_ci dp = bin2hex(dp, e->mask, e->size); 53762306a36Sopenharmony_ci } 53862306a36Sopenharmony_ci *dp++ = '\n'; 53962306a36Sopenharmony_ci *dp = '\0'; 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci} 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_cistatic struct inode *bm_get_inode(struct super_block *sb, int mode) 54462306a36Sopenharmony_ci{ 54562306a36Sopenharmony_ci struct inode *inode = new_inode(sb); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci if (inode) { 54862306a36Sopenharmony_ci inode->i_ino = get_next_ino(); 54962306a36Sopenharmony_ci inode->i_mode = mode; 55062306a36Sopenharmony_ci inode->i_atime = inode->i_mtime = inode_set_ctime_current(inode); 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci return inode; 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_cistatic void bm_evict_inode(struct inode *inode) 55662306a36Sopenharmony_ci{ 55762306a36Sopenharmony_ci Node *e = inode->i_private; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci if (e && e->flags & MISC_FMT_OPEN_FILE) 56062306a36Sopenharmony_ci filp_close(e->interp_file, NULL); 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci clear_inode(inode); 56362306a36Sopenharmony_ci kfree(e); 56462306a36Sopenharmony_ci} 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_cistatic void kill_node(Node *e) 56762306a36Sopenharmony_ci{ 56862306a36Sopenharmony_ci struct dentry *dentry; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci write_lock(&entries_lock); 57162306a36Sopenharmony_ci list_del_init(&e->list); 57262306a36Sopenharmony_ci write_unlock(&entries_lock); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci dentry = e->dentry; 57562306a36Sopenharmony_ci drop_nlink(d_inode(dentry)); 57662306a36Sopenharmony_ci d_drop(dentry); 57762306a36Sopenharmony_ci dput(dentry); 57862306a36Sopenharmony_ci simple_release_fs(&bm_mnt, &entry_count); 57962306a36Sopenharmony_ci} 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci/* /<entry> */ 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_cistatic ssize_t 58462306a36Sopenharmony_cibm_entry_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) 58562306a36Sopenharmony_ci{ 58662306a36Sopenharmony_ci Node *e = file_inode(file)->i_private; 58762306a36Sopenharmony_ci ssize_t res; 58862306a36Sopenharmony_ci char *page; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci page = (char *) __get_free_page(GFP_KERNEL); 59162306a36Sopenharmony_ci if (!page) 59262306a36Sopenharmony_ci return -ENOMEM; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci entry_status(e, page); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci res = simple_read_from_buffer(buf, nbytes, ppos, page, strlen(page)); 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci free_page((unsigned long) page); 59962306a36Sopenharmony_ci return res; 60062306a36Sopenharmony_ci} 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_cistatic ssize_t bm_entry_write(struct file *file, const char __user *buffer, 60362306a36Sopenharmony_ci size_t count, loff_t *ppos) 60462306a36Sopenharmony_ci{ 60562306a36Sopenharmony_ci struct dentry *root; 60662306a36Sopenharmony_ci Node *e = file_inode(file)->i_private; 60762306a36Sopenharmony_ci int res = parse_command(buffer, count); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci switch (res) { 61062306a36Sopenharmony_ci case 1: 61162306a36Sopenharmony_ci /* Disable this handler. */ 61262306a36Sopenharmony_ci clear_bit(Enabled, &e->flags); 61362306a36Sopenharmony_ci break; 61462306a36Sopenharmony_ci case 2: 61562306a36Sopenharmony_ci /* Enable this handler. */ 61662306a36Sopenharmony_ci set_bit(Enabled, &e->flags); 61762306a36Sopenharmony_ci break; 61862306a36Sopenharmony_ci case 3: 61962306a36Sopenharmony_ci /* Delete this handler. */ 62062306a36Sopenharmony_ci root = file_inode(file)->i_sb->s_root; 62162306a36Sopenharmony_ci inode_lock(d_inode(root)); 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci if (!list_empty(&e->list)) 62462306a36Sopenharmony_ci kill_node(e); 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci inode_unlock(d_inode(root)); 62762306a36Sopenharmony_ci break; 62862306a36Sopenharmony_ci default: 62962306a36Sopenharmony_ci return res; 63062306a36Sopenharmony_ci } 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci return count; 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_cistatic const struct file_operations bm_entry_operations = { 63662306a36Sopenharmony_ci .read = bm_entry_read, 63762306a36Sopenharmony_ci .write = bm_entry_write, 63862306a36Sopenharmony_ci .llseek = default_llseek, 63962306a36Sopenharmony_ci}; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci/* /register */ 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_cistatic ssize_t bm_register_write(struct file *file, const char __user *buffer, 64462306a36Sopenharmony_ci size_t count, loff_t *ppos) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci Node *e; 64762306a36Sopenharmony_ci struct inode *inode; 64862306a36Sopenharmony_ci struct super_block *sb = file_inode(file)->i_sb; 64962306a36Sopenharmony_ci struct dentry *root = sb->s_root, *dentry; 65062306a36Sopenharmony_ci int err = 0; 65162306a36Sopenharmony_ci struct file *f = NULL; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci e = create_entry(buffer, count); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci if (IS_ERR(e)) 65662306a36Sopenharmony_ci return PTR_ERR(e); 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci if (e->flags & MISC_FMT_OPEN_FILE) { 65962306a36Sopenharmony_ci f = open_exec(e->interpreter); 66062306a36Sopenharmony_ci if (IS_ERR(f)) { 66162306a36Sopenharmony_ci pr_notice("register: failed to install interpreter file %s\n", 66262306a36Sopenharmony_ci e->interpreter); 66362306a36Sopenharmony_ci kfree(e); 66462306a36Sopenharmony_ci return PTR_ERR(f); 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci e->interp_file = f; 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci inode_lock(d_inode(root)); 67062306a36Sopenharmony_ci dentry = lookup_one_len(e->name, root, strlen(e->name)); 67162306a36Sopenharmony_ci err = PTR_ERR(dentry); 67262306a36Sopenharmony_ci if (IS_ERR(dentry)) 67362306a36Sopenharmony_ci goto out; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci err = -EEXIST; 67662306a36Sopenharmony_ci if (d_really_is_positive(dentry)) 67762306a36Sopenharmony_ci goto out2; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci inode = bm_get_inode(sb, S_IFREG | 0644); 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci err = -ENOMEM; 68262306a36Sopenharmony_ci if (!inode) 68362306a36Sopenharmony_ci goto out2; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci err = simple_pin_fs(&bm_fs_type, &bm_mnt, &entry_count); 68662306a36Sopenharmony_ci if (err) { 68762306a36Sopenharmony_ci iput(inode); 68862306a36Sopenharmony_ci inode = NULL; 68962306a36Sopenharmony_ci goto out2; 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci e->dentry = dget(dentry); 69362306a36Sopenharmony_ci inode->i_private = e; 69462306a36Sopenharmony_ci inode->i_fop = &bm_entry_operations; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci d_instantiate(dentry, inode); 69762306a36Sopenharmony_ci write_lock(&entries_lock); 69862306a36Sopenharmony_ci list_add(&e->list, &entries); 69962306a36Sopenharmony_ci write_unlock(&entries_lock); 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci err = 0; 70262306a36Sopenharmony_ciout2: 70362306a36Sopenharmony_ci dput(dentry); 70462306a36Sopenharmony_ciout: 70562306a36Sopenharmony_ci inode_unlock(d_inode(root)); 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci if (err) { 70862306a36Sopenharmony_ci if (f) 70962306a36Sopenharmony_ci filp_close(f, NULL); 71062306a36Sopenharmony_ci kfree(e); 71162306a36Sopenharmony_ci return err; 71262306a36Sopenharmony_ci } 71362306a36Sopenharmony_ci return count; 71462306a36Sopenharmony_ci} 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_cistatic const struct file_operations bm_register_operations = { 71762306a36Sopenharmony_ci .write = bm_register_write, 71862306a36Sopenharmony_ci .llseek = noop_llseek, 71962306a36Sopenharmony_ci}; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci/* /status */ 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_cistatic ssize_t 72462306a36Sopenharmony_cibm_status_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) 72562306a36Sopenharmony_ci{ 72662306a36Sopenharmony_ci char *s = enabled ? "enabled\n" : "disabled\n"; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci return simple_read_from_buffer(buf, nbytes, ppos, s, strlen(s)); 72962306a36Sopenharmony_ci} 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_cistatic ssize_t bm_status_write(struct file *file, const char __user *buffer, 73262306a36Sopenharmony_ci size_t count, loff_t *ppos) 73362306a36Sopenharmony_ci{ 73462306a36Sopenharmony_ci int res = parse_command(buffer, count); 73562306a36Sopenharmony_ci struct dentry *root; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci switch (res) { 73862306a36Sopenharmony_ci case 1: 73962306a36Sopenharmony_ci /* Disable all handlers. */ 74062306a36Sopenharmony_ci enabled = 0; 74162306a36Sopenharmony_ci break; 74262306a36Sopenharmony_ci case 2: 74362306a36Sopenharmony_ci /* Enable all handlers. */ 74462306a36Sopenharmony_ci enabled = 1; 74562306a36Sopenharmony_ci break; 74662306a36Sopenharmony_ci case 3: 74762306a36Sopenharmony_ci /* Delete all handlers. */ 74862306a36Sopenharmony_ci root = file_inode(file)->i_sb->s_root; 74962306a36Sopenharmony_ci inode_lock(d_inode(root)); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci while (!list_empty(&entries)) 75262306a36Sopenharmony_ci kill_node(list_first_entry(&entries, Node, list)); 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci inode_unlock(d_inode(root)); 75562306a36Sopenharmony_ci break; 75662306a36Sopenharmony_ci default: 75762306a36Sopenharmony_ci return res; 75862306a36Sopenharmony_ci } 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci return count; 76162306a36Sopenharmony_ci} 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_cistatic const struct file_operations bm_status_operations = { 76462306a36Sopenharmony_ci .read = bm_status_read, 76562306a36Sopenharmony_ci .write = bm_status_write, 76662306a36Sopenharmony_ci .llseek = default_llseek, 76762306a36Sopenharmony_ci}; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci/* Superblock handling */ 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_cistatic const struct super_operations s_ops = { 77262306a36Sopenharmony_ci .statfs = simple_statfs, 77362306a36Sopenharmony_ci .evict_inode = bm_evict_inode, 77462306a36Sopenharmony_ci}; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_cistatic int bm_fill_super(struct super_block *sb, struct fs_context *fc) 77762306a36Sopenharmony_ci{ 77862306a36Sopenharmony_ci int err; 77962306a36Sopenharmony_ci static const struct tree_descr bm_files[] = { 78062306a36Sopenharmony_ci [2] = {"status", &bm_status_operations, S_IWUSR|S_IRUGO}, 78162306a36Sopenharmony_ci [3] = {"register", &bm_register_operations, S_IWUSR}, 78262306a36Sopenharmony_ci /* last one */ {""} 78362306a36Sopenharmony_ci }; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci err = simple_fill_super(sb, BINFMTFS_MAGIC, bm_files); 78662306a36Sopenharmony_ci if (!err) 78762306a36Sopenharmony_ci sb->s_op = &s_ops; 78862306a36Sopenharmony_ci return err; 78962306a36Sopenharmony_ci} 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_cistatic int bm_get_tree(struct fs_context *fc) 79262306a36Sopenharmony_ci{ 79362306a36Sopenharmony_ci return get_tree_single(fc, bm_fill_super); 79462306a36Sopenharmony_ci} 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_cistatic const struct fs_context_operations bm_context_ops = { 79762306a36Sopenharmony_ci .get_tree = bm_get_tree, 79862306a36Sopenharmony_ci}; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_cistatic int bm_init_fs_context(struct fs_context *fc) 80162306a36Sopenharmony_ci{ 80262306a36Sopenharmony_ci fc->ops = &bm_context_ops; 80362306a36Sopenharmony_ci return 0; 80462306a36Sopenharmony_ci} 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_cistatic struct linux_binfmt misc_format = { 80762306a36Sopenharmony_ci .module = THIS_MODULE, 80862306a36Sopenharmony_ci .load_binary = load_misc_binary, 80962306a36Sopenharmony_ci}; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_cistatic struct file_system_type bm_fs_type = { 81262306a36Sopenharmony_ci .owner = THIS_MODULE, 81362306a36Sopenharmony_ci .name = "binfmt_misc", 81462306a36Sopenharmony_ci .init_fs_context = bm_init_fs_context, 81562306a36Sopenharmony_ci .kill_sb = kill_litter_super, 81662306a36Sopenharmony_ci}; 81762306a36Sopenharmony_ciMODULE_ALIAS_FS("binfmt_misc"); 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_cistatic int __init init_misc_binfmt(void) 82062306a36Sopenharmony_ci{ 82162306a36Sopenharmony_ci int err = register_filesystem(&bm_fs_type); 82262306a36Sopenharmony_ci if (!err) 82362306a36Sopenharmony_ci insert_binfmt(&misc_format); 82462306a36Sopenharmony_ci return err; 82562306a36Sopenharmony_ci} 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_cistatic void __exit exit_misc_binfmt(void) 82862306a36Sopenharmony_ci{ 82962306a36Sopenharmony_ci unregister_binfmt(&misc_format); 83062306a36Sopenharmony_ci unregister_filesystem(&bm_fs_type); 83162306a36Sopenharmony_ci} 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_cicore_initcall(init_misc_binfmt); 83462306a36Sopenharmony_cimodule_exit(exit_misc_binfmt); 83562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 836