109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * binfmt_misc.c
41da177e4SLinus Torvalds *
596de0e25SJan Engelhardt * Copyright (C) 1997 Richard Günther
61da177e4SLinus Torvalds *
71da177e4SLinus Torvalds * binfmt_misc detects binaries via a magic or filename extension and invokes
834962fb8SMauro Carvalho Chehab * a specified wrapper. See Documentation/admin-guide/binfmt-misc.rst for more details.
91da177e4SLinus Torvalds */
101da177e4SLinus Torvalds
116b899c4eSMike Frysinger #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
126b899c4eSMike Frysinger
136ceafb88SRasmus Villemoes #include <linux/kernel.h>
141da177e4SLinus Torvalds #include <linux/module.h>
151da177e4SLinus Torvalds #include <linux/init.h>
16589ee628SIngo Molnar #include <linux/sched/mm.h>
17b502bd11SMuthu Kumar #include <linux/magic.h>
181da177e4SLinus Torvalds #include <linux/binfmts.h>
191da177e4SLinus Torvalds #include <linux/slab.h>
201da177e4SLinus Torvalds #include <linux/ctype.h>
218d82e180SAndy Shevchenko #include <linux/string_helpers.h>
221da177e4SLinus Torvalds #include <linux/file.h>
231da177e4SLinus Torvalds #include <linux/pagemap.h>
241da177e4SLinus Torvalds #include <linux/namei.h>
251da177e4SLinus Torvalds #include <linux/mount.h>
26bc99a664SDavid Howells #include <linux/fs_context.h>
271da177e4SLinus Torvalds #include <linux/syscalls.h>
286e2c10a1SAkinobu Mita #include <linux/fs.h>
296b899c4eSMike Frysinger #include <linux/uaccess.h>
301da177e4SLinus Torvalds
31948b701aSJames Bottomley #include "internal.h"
32948b701aSJames Bottomley
336b899c4eSMike Frysinger #ifdef DEBUG
346b899c4eSMike Frysinger # define USE_DEBUG 1
356b899c4eSMike Frysinger #else
366b899c4eSMike Frysinger # define USE_DEBUG 0
376b899c4eSMike Frysinger #endif
381da177e4SLinus Torvalds
391da177e4SLinus Torvalds enum {
401da177e4SLinus Torvalds VERBOSE_STATUS = 1 /* make it zero to save 400 bytes kernel memory */
411da177e4SLinus Torvalds };
421da177e4SLinus Torvalds
431da177e4SLinus Torvalds static LIST_HEAD(entries);
441da177e4SLinus Torvalds static int enabled = 1;
451da177e4SLinus Torvalds
461da177e4SLinus Torvalds enum {Enabled, Magic};
476a46bf55SLiu Shixin #define MISC_FMT_PRESERVE_ARGV0 (1UL << 31)
486a46bf55SLiu Shixin #define MISC_FMT_OPEN_BINARY (1UL << 30)
496a46bf55SLiu Shixin #define MISC_FMT_CREDENTIALS (1UL << 29)
506a46bf55SLiu Shixin #define MISC_FMT_OPEN_FILE (1UL << 28)
511da177e4SLinus Torvalds
521da177e4SLinus Torvalds typedef struct {
531da177e4SLinus Torvalds struct list_head list;
541da177e4SLinus Torvalds unsigned long flags; /* type, status, etc. */
551da177e4SLinus Torvalds int offset; /* offset of magic */
561da177e4SLinus Torvalds int size; /* size of magic/mask */
571da177e4SLinus Torvalds char *magic; /* magic or filename extension */
581da177e4SLinus Torvalds char *mask; /* mask, NULL for exact match */
5950097f74SOleg Nesterov const char *interpreter; /* filename of interpreter */
601da177e4SLinus Torvalds char *name;
611da177e4SLinus Torvalds struct dentry *dentry;
62948b701aSJames Bottomley struct file *interp_file;
631da177e4SLinus Torvalds } Node;
641da177e4SLinus Torvalds
651da177e4SLinus Torvalds static DEFINE_RWLOCK(entries_lock);
661f5ce9e9STrond Myklebust static struct file_system_type bm_fs_type;
671da177e4SLinus Torvalds static struct vfsmount *bm_mnt;
681da177e4SLinus Torvalds static int entry_count;
691da177e4SLinus Torvalds
701da177e4SLinus Torvalds /*
71bbaecc08SMike Frysinger * Max length of the register string. Determined by:
72bbaecc08SMike Frysinger * - 7 delimiters
73bbaecc08SMike Frysinger * - name: ~50 bytes
74bbaecc08SMike Frysinger * - type: 1 byte
75bbaecc08SMike Frysinger * - offset: 3 bytes (has to be smaller than BINPRM_BUF_SIZE)
76bbaecc08SMike Frysinger * - magic: 128 bytes (512 in escaped form)
77bbaecc08SMike Frysinger * - mask: 128 bytes (512 in escaped form)
78bbaecc08SMike Frysinger * - interp: ~50 bytes
79bbaecc08SMike Frysinger * - flags: 5 bytes
80bbaecc08SMike Frysinger * Round that up a bit, and then back off to hold the internal data
81bbaecc08SMike Frysinger * (like struct Node).
82bbaecc08SMike Frysinger */
83bbaecc08SMike Frysinger #define MAX_REGISTER_LENGTH 1920
84bbaecc08SMike Frysinger
85bbaecc08SMike Frysinger /*
861da177e4SLinus Torvalds * Check if we support the binfmt
871da177e4SLinus Torvalds * if we do, return the node, else NULL
881da177e4SLinus Torvalds * locking is done in load_misc_binary
891da177e4SLinus Torvalds */
check_file(struct linux_binprm * bprm)901da177e4SLinus Torvalds static Node *check_file(struct linux_binprm *bprm)
911da177e4SLinus Torvalds {
921da177e4SLinus Torvalds char *p = strrchr(bprm->interp, '.');
931da177e4SLinus Torvalds struct list_head *l;
941da177e4SLinus Torvalds
956b899c4eSMike Frysinger /* Walk all the registered handlers. */
961da177e4SLinus Torvalds list_for_each(l, &entries) {
971da177e4SLinus Torvalds Node *e = list_entry(l, Node, list);
981da177e4SLinus Torvalds char *s;
991da177e4SLinus Torvalds int j;
1001da177e4SLinus Torvalds
1016b899c4eSMike Frysinger /* Make sure this one is currently enabled. */
1021da177e4SLinus Torvalds if (!test_bit(Enabled, &e->flags))
1031da177e4SLinus Torvalds continue;
1041da177e4SLinus Torvalds
1056b899c4eSMike Frysinger /* Do matching based on extension if applicable. */
1061da177e4SLinus Torvalds if (!test_bit(Magic, &e->flags)) {
1071da177e4SLinus Torvalds if (p && !strcmp(e->magic, p + 1))
1081da177e4SLinus Torvalds return e;
1091da177e4SLinus Torvalds continue;
1101da177e4SLinus Torvalds }
1111da177e4SLinus Torvalds
1126b899c4eSMike Frysinger /* Do matching based on magic & mask. */
1131da177e4SLinus Torvalds s = bprm->buf + e->offset;
1141da177e4SLinus Torvalds if (e->mask) {
1151da177e4SLinus Torvalds for (j = 0; j < e->size; j++)
1161da177e4SLinus Torvalds if ((*s++ ^ e->magic[j]) & e->mask[j])
1171da177e4SLinus Torvalds break;
1181da177e4SLinus Torvalds } else {
1191da177e4SLinus Torvalds for (j = 0; j < e->size; j++)
1201da177e4SLinus Torvalds if ((*s++ ^ e->magic[j]))
1211da177e4SLinus Torvalds break;
1221da177e4SLinus Torvalds }
1231da177e4SLinus Torvalds if (j == e->size)
1241da177e4SLinus Torvalds return e;
1251da177e4SLinus Torvalds }
1261da177e4SLinus Torvalds return NULL;
1271da177e4SLinus Torvalds }
1281da177e4SLinus Torvalds
1291da177e4SLinus Torvalds /*
1301da177e4SLinus Torvalds * the loader itself
1311da177e4SLinus Torvalds */
load_misc_binary(struct linux_binprm * bprm)13271613c3bSAl Viro static int load_misc_binary(struct linux_binprm *bprm)
1331da177e4SLinus Torvalds {
1341da177e4SLinus Torvalds Node *fmt;
1351da177e4SLinus Torvalds struct file *interp_file = NULL;
1361da177e4SLinus Torvalds int retval;
1371da177e4SLinus Torvalds
1381da177e4SLinus Torvalds retval = -ENOEXEC;
1391da177e4SLinus Torvalds if (!enabled)
14043a4f261SOleg Nesterov return retval;
1411da177e4SLinus Torvalds
1421da177e4SLinus Torvalds /* to keep locking time low, we copy the interpreter string */
1431da177e4SLinus Torvalds read_lock(&entries_lock);
1441da177e4SLinus Torvalds fmt = check_file(bprm);
14550097f74SOleg Nesterov if (fmt)
14643a4f261SOleg Nesterov dget(fmt->dentry);
1471da177e4SLinus Torvalds read_unlock(&entries_lock);
1481da177e4SLinus Torvalds if (!fmt)
14943a4f261SOleg Nesterov return retval;
1501da177e4SLinus Torvalds
15151f39a1fSDavid Drysdale /* Need to be able to load the file after exec */
15243a4f261SOleg Nesterov retval = -ENOENT;
15351f39a1fSDavid Drysdale if (bprm->interp_flags & BINPRM_FLAGS_PATH_INACCESSIBLE)
15443a4f261SOleg Nesterov goto ret;
15551f39a1fSDavid Drysdale
1562347961bSLaurent Vivier if (fmt->flags & MISC_FMT_PRESERVE_ARGV0) {
1572347961bSLaurent Vivier bprm->interp_flags |= BINPRM_FLAGS_PRESERVE_ARGV0;
1582347961bSLaurent Vivier } else {
159b6a2fea3SOllie Wild retval = remove_arg_zero(bprm);
160b6a2fea3SOllie Wild if (retval)
161e6084d4aSMike Frysinger goto ret;
1621da177e4SLinus Torvalds }
1631da177e4SLinus Torvalds
164bc2bf338SEric W. Biederman if (fmt->flags & MISC_FMT_OPEN_BINARY)
165b8a61c9eSEric W. Biederman bprm->have_execfd = 1;
1661da177e4SLinus Torvalds
1671da177e4SLinus Torvalds /* make argv[1] be the path to the binary */
168986db2d1SChristoph Hellwig retval = copy_string_kernel(bprm->interp, bprm);
1691da177e4SLinus Torvalds if (retval < 0)
170b8a61c9eSEric W. Biederman goto ret;
1711da177e4SLinus Torvalds bprm->argc++;
1721da177e4SLinus Torvalds
1731da177e4SLinus Torvalds /* add the interp as argv[0] */
174986db2d1SChristoph Hellwig retval = copy_string_kernel(fmt->interpreter, bprm);
1751da177e4SLinus Torvalds if (retval < 0)
176b8a61c9eSEric W. Biederman goto ret;
1771da177e4SLinus Torvalds bprm->argc++;
1781da177e4SLinus Torvalds
179b66c5984SKees Cook /* Update interp in case binfmt_script needs it. */
18050097f74SOleg Nesterov retval = bprm_change_interp(fmt->interpreter, bprm);
181b66c5984SKees Cook if (retval < 0)
182b8a61c9eSEric W. Biederman goto ret;
1831da177e4SLinus Torvalds
184eb23aa03SOleg Nesterov if (fmt->flags & MISC_FMT_OPEN_FILE) {
18519f391ebSAl Viro interp_file = file_clone_open(fmt->interp_file);
186948b701aSJames Bottomley if (!IS_ERR(interp_file))
187948b701aSJames Bottomley deny_write_access(interp_file);
188948b701aSJames Bottomley } else {
18950097f74SOleg Nesterov interp_file = open_exec(fmt->interpreter);
190948b701aSJames Bottomley }
1911da177e4SLinus Torvalds retval = PTR_ERR(interp_file);
1921da177e4SLinus Torvalds if (IS_ERR(interp_file))
193b8a61c9eSEric W. Biederman goto ret;
1941da177e4SLinus Torvalds
195bc2bf338SEric W. Biederman bprm->interpreter = interp_file;
196a16b3357SEric W. Biederman if (fmt->flags & MISC_FMT_CREDENTIALS)
19756305aa9SEric W. Biederman bprm->execfd_creds = 1;
198bdd1d2d3SChristoph Hellwig
199bc2bf338SEric W. Biederman retval = 0;
200e6084d4aSMike Frysinger ret:
20143a4f261SOleg Nesterov dput(fmt->dentry);
2021da177e4SLinus Torvalds return retval;
2031da177e4SLinus Torvalds }
2041da177e4SLinus Torvalds
2051da177e4SLinus Torvalds /* Command parsers */
2061da177e4SLinus Torvalds
2071da177e4SLinus Torvalds /*
2081da177e4SLinus Torvalds * parses and copies one argument enclosed in del from *sp to *dp,
2091da177e4SLinus Torvalds * recognising the \x special.
2101da177e4SLinus Torvalds * returns pointer to the copied argument or NULL in case of an
2111da177e4SLinus Torvalds * error (and sets err) or null argument length.
2121da177e4SLinus Torvalds */
scanarg(char * s,char del)2131da177e4SLinus Torvalds static char *scanarg(char *s, char del)
2141da177e4SLinus Torvalds {
2151da177e4SLinus Torvalds char c;
2161da177e4SLinus Torvalds
2171da177e4SLinus Torvalds while ((c = *s++) != del) {
2181da177e4SLinus Torvalds if (c == '\\' && *s == 'x') {
2191da177e4SLinus Torvalds s++;
2201da177e4SLinus Torvalds if (!isxdigit(*s++))
2211da177e4SLinus Torvalds return NULL;
2221da177e4SLinus Torvalds if (!isxdigit(*s++))
2231da177e4SLinus Torvalds return NULL;
2241da177e4SLinus Torvalds }
2251da177e4SLinus Torvalds }
2267d65cf10SAl Viro s[-1] ='\0';
2271da177e4SLinus Torvalds return s;
2281da177e4SLinus Torvalds }
2291da177e4SLinus Torvalds
check_special_flags(char * sfs,Node * e)230858119e1SArjan van de Ven static char *check_special_flags(char *sfs, Node *e)
2311da177e4SLinus Torvalds {
2321da177e4SLinus Torvalds char *p = sfs;
2331da177e4SLinus Torvalds int cont = 1;
2341da177e4SLinus Torvalds
2351da177e4SLinus Torvalds /* special flags */
2361da177e4SLinus Torvalds while (cont) {
2371da177e4SLinus Torvalds switch (*p) {
2381da177e4SLinus Torvalds case 'P':
2396b899c4eSMike Frysinger pr_debug("register: flag: P (preserve argv0)\n");
2401da177e4SLinus Torvalds p++;
2411da177e4SLinus Torvalds e->flags |= MISC_FMT_PRESERVE_ARGV0;
2421da177e4SLinus Torvalds break;
2431da177e4SLinus Torvalds case 'O':
2446b899c4eSMike Frysinger pr_debug("register: flag: O (open binary)\n");
2451da177e4SLinus Torvalds p++;
2461da177e4SLinus Torvalds e->flags |= MISC_FMT_OPEN_BINARY;
2471da177e4SLinus Torvalds break;
2481da177e4SLinus Torvalds case 'C':
2496b899c4eSMike Frysinger pr_debug("register: flag: C (preserve creds)\n");
2501da177e4SLinus Torvalds p++;
2511da177e4SLinus Torvalds /* this flags also implies the
2521da177e4SLinus Torvalds open-binary flag */
2531da177e4SLinus Torvalds e->flags |= (MISC_FMT_CREDENTIALS |
2541da177e4SLinus Torvalds MISC_FMT_OPEN_BINARY);
2551da177e4SLinus Torvalds break;
256948b701aSJames Bottomley case 'F':
257948b701aSJames Bottomley pr_debug("register: flag: F: open interpreter file now\n");
258948b701aSJames Bottomley p++;
259948b701aSJames Bottomley e->flags |= MISC_FMT_OPEN_FILE;
260948b701aSJames Bottomley break;
2611da177e4SLinus Torvalds default:
2621da177e4SLinus Torvalds cont = 0;
2631da177e4SLinus Torvalds }
2641da177e4SLinus Torvalds }
2651da177e4SLinus Torvalds
2661da177e4SLinus Torvalds return p;
2671da177e4SLinus Torvalds }
268e6084d4aSMike Frysinger
2691da177e4SLinus Torvalds /*
2701da177e4SLinus Torvalds * This registers a new binary format, it recognises the syntax
2711da177e4SLinus Torvalds * ':name:type:offset:magic:mask:interpreter:flags'
2721da177e4SLinus Torvalds * where the ':' is the IFS, that can be chosen with the first char
2731da177e4SLinus Torvalds */
create_entry(const char __user * buffer,size_t count)2741da177e4SLinus Torvalds static Node *create_entry(const char __user *buffer, size_t count)
2751da177e4SLinus Torvalds {
2761da177e4SLinus Torvalds Node *e;
2771da177e4SLinus Torvalds int memsize, err;
2781da177e4SLinus Torvalds char *buf, *p;
2791da177e4SLinus Torvalds char del;
2801da177e4SLinus Torvalds
2816b899c4eSMike Frysinger pr_debug("register: received %zu bytes\n", count);
2826b899c4eSMike Frysinger
2831da177e4SLinus Torvalds /* some sanity checks */
2841da177e4SLinus Torvalds err = -EINVAL;
285bbaecc08SMike Frysinger if ((count < 11) || (count > MAX_REGISTER_LENGTH))
2861da177e4SLinus Torvalds goto out;
2871da177e4SLinus Torvalds
2881da177e4SLinus Torvalds err = -ENOMEM;
2891da177e4SLinus Torvalds memsize = sizeof(Node) + count + 8;
290f7e1ad1aSAndrew Morton e = kmalloc(memsize, GFP_KERNEL);
2911da177e4SLinus Torvalds if (!e)
2921da177e4SLinus Torvalds goto out;
2931da177e4SLinus Torvalds
2941da177e4SLinus Torvalds p = buf = (char *)e + sizeof(Node);
2951da177e4SLinus Torvalds
2961da177e4SLinus Torvalds memset(e, 0, sizeof(Node));
2971da177e4SLinus Torvalds if (copy_from_user(buf, buffer, count))
298e6084d4aSMike Frysinger goto efault;
2991da177e4SLinus Torvalds
3001da177e4SLinus Torvalds del = *p++; /* delimeter */
3011da177e4SLinus Torvalds
3026b899c4eSMike Frysinger pr_debug("register: delim: %#x {%c}\n", del, del);
3036b899c4eSMike Frysinger
3046b899c4eSMike Frysinger /* Pad the buffer with the delim to simplify parsing below. */
3051da177e4SLinus Torvalds memset(buf + count, del, 8);
3061da177e4SLinus Torvalds
3076b899c4eSMike Frysinger /* Parse the 'name' field. */
3081da177e4SLinus Torvalds e->name = p;
3091da177e4SLinus Torvalds p = strchr(p, del);
3101da177e4SLinus Torvalds if (!p)
311e6084d4aSMike Frysinger goto einval;
3121da177e4SLinus Torvalds *p++ = '\0';
3131da177e4SLinus Torvalds if (!e->name[0] ||
3141da177e4SLinus Torvalds !strcmp(e->name, ".") ||
3151da177e4SLinus Torvalds !strcmp(e->name, "..") ||
3161da177e4SLinus Torvalds strchr(e->name, '/'))
317e6084d4aSMike Frysinger goto einval;
3186b899c4eSMike Frysinger
3196b899c4eSMike Frysinger pr_debug("register: name: {%s}\n", e->name);
3206b899c4eSMike Frysinger
3216b899c4eSMike Frysinger /* Parse the 'type' field. */
3221da177e4SLinus Torvalds switch (*p++) {
3236b899c4eSMike Frysinger case 'E':
3246b899c4eSMike Frysinger pr_debug("register: type: E (extension)\n");
3256b899c4eSMike Frysinger e->flags = 1 << Enabled;
3266b899c4eSMike Frysinger break;
3276b899c4eSMike Frysinger case 'M':
3286b899c4eSMike Frysinger pr_debug("register: type: M (magic)\n");
3296b899c4eSMike Frysinger e->flags = (1 << Enabled) | (1 << Magic);
3306b899c4eSMike Frysinger break;
3316b899c4eSMike Frysinger default:
332e6084d4aSMike Frysinger goto einval;
3331da177e4SLinus Torvalds }
3341da177e4SLinus Torvalds if (*p++ != del)
335e6084d4aSMike Frysinger goto einval;
3366b899c4eSMike Frysinger
3371da177e4SLinus Torvalds if (test_bit(Magic, &e->flags)) {
3386b899c4eSMike Frysinger /* Handle the 'M' (magic) format. */
3396b899c4eSMike Frysinger char *s;
3406b899c4eSMike Frysinger
3416b899c4eSMike Frysinger /* Parse the 'offset' field. */
3426b899c4eSMike Frysinger s = strchr(p, del);
3431da177e4SLinus Torvalds if (!s)
344e6084d4aSMike Frysinger goto einval;
3455cc41e09SThadeu Lima de Souza Cascardo *s = '\0';
3465cc41e09SThadeu Lima de Souza Cascardo if (p != s) {
3475cc41e09SThadeu Lima de Souza Cascardo int r = kstrtoint(p, 10, &e->offset);
3485cc41e09SThadeu Lima de Souza Cascardo if (r != 0 || e->offset < 0)
3495cc41e09SThadeu Lima de Souza Cascardo goto einval;
3505cc41e09SThadeu Lima de Souza Cascardo }
3515cc41e09SThadeu Lima de Souza Cascardo p = s;
3521da177e4SLinus Torvalds if (*p++)
353e6084d4aSMike Frysinger goto einval;
3546b899c4eSMike Frysinger pr_debug("register: offset: %#x\n", e->offset);
3556b899c4eSMike Frysinger
3566b899c4eSMike Frysinger /* Parse the 'magic' field. */
3571da177e4SLinus Torvalds e->magic = p;
3581da177e4SLinus Torvalds p = scanarg(p, del);
3591da177e4SLinus Torvalds if (!p)
360e6084d4aSMike Frysinger goto einval;
3617d65cf10SAl Viro if (!e->magic[0])
362e6084d4aSMike Frysinger goto einval;
3636b899c4eSMike Frysinger if (USE_DEBUG)
3646b899c4eSMike Frysinger print_hex_dump_bytes(
3656b899c4eSMike Frysinger KBUILD_MODNAME ": register: magic[raw]: ",
3666b899c4eSMike Frysinger DUMP_PREFIX_NONE, e->magic, p - e->magic);
3676b899c4eSMike Frysinger
3686b899c4eSMike Frysinger /* Parse the 'mask' field. */
3691da177e4SLinus Torvalds e->mask = p;
3701da177e4SLinus Torvalds p = scanarg(p, del);
3711da177e4SLinus Torvalds if (!p)
372e6084d4aSMike Frysinger goto einval;
3737d65cf10SAl Viro if (!e->mask[0]) {
3741da177e4SLinus Torvalds e->mask = NULL;
3756b899c4eSMike Frysinger pr_debug("register: mask[raw]: none\n");
3766b899c4eSMike Frysinger } else if (USE_DEBUG)
3776b899c4eSMike Frysinger print_hex_dump_bytes(
3786b899c4eSMike Frysinger KBUILD_MODNAME ": register: mask[raw]: ",
3796b899c4eSMike Frysinger DUMP_PREFIX_NONE, e->mask, p - e->mask);
3806b899c4eSMike Frysinger
3816b899c4eSMike Frysinger /*
3826b899c4eSMike Frysinger * Decode the magic & mask fields.
3836b899c4eSMike Frysinger * Note: while we might have accepted embedded NUL bytes from
3846b899c4eSMike Frysinger * above, the unescape helpers here will stop at the first one
3856b899c4eSMike Frysinger * it encounters.
3866b899c4eSMike Frysinger */
3878d82e180SAndy Shevchenko e->size = string_unescape_inplace(e->magic, UNESCAPE_HEX);
3888d82e180SAndy Shevchenko if (e->mask &&
3898d82e180SAndy Shevchenko string_unescape_inplace(e->mask, UNESCAPE_HEX) != e->size)
390e6084d4aSMike Frysinger goto einval;
3915cc41e09SThadeu Lima de Souza Cascardo if (e->size > BINPRM_BUF_SIZE ||
3925cc41e09SThadeu Lima de Souza Cascardo BINPRM_BUF_SIZE - e->size < e->offset)
393e6084d4aSMike Frysinger goto einval;
3946b899c4eSMike Frysinger pr_debug("register: magic/mask length: %i\n", e->size);
3956b899c4eSMike Frysinger if (USE_DEBUG) {
3966b899c4eSMike Frysinger print_hex_dump_bytes(
3976b899c4eSMike Frysinger KBUILD_MODNAME ": register: magic[decoded]: ",
3986b899c4eSMike Frysinger DUMP_PREFIX_NONE, e->magic, e->size);
3996b899c4eSMike Frysinger
4006b899c4eSMike Frysinger if (e->mask) {
4016b899c4eSMike Frysinger int i;
402f7e1ad1aSAndrew Morton char *masked = kmalloc(e->size, GFP_KERNEL);
4036b899c4eSMike Frysinger
4046b899c4eSMike Frysinger print_hex_dump_bytes(
4056b899c4eSMike Frysinger KBUILD_MODNAME ": register: mask[decoded]: ",
4066b899c4eSMike Frysinger DUMP_PREFIX_NONE, e->mask, e->size);
4076b899c4eSMike Frysinger
4086b899c4eSMike Frysinger if (masked) {
4096b899c4eSMike Frysinger for (i = 0; i < e->size; ++i)
4106b899c4eSMike Frysinger masked[i] = e->magic[i] & e->mask[i];
4116b899c4eSMike Frysinger print_hex_dump_bytes(
4126b899c4eSMike Frysinger KBUILD_MODNAME ": register: magic[masked]: ",
4136b899c4eSMike Frysinger DUMP_PREFIX_NONE, masked, e->size);
4146b899c4eSMike Frysinger
4156b899c4eSMike Frysinger kfree(masked);
4166b899c4eSMike Frysinger }
4176b899c4eSMike Frysinger }
4186b899c4eSMike Frysinger }
4191da177e4SLinus Torvalds } else {
4206b899c4eSMike Frysinger /* Handle the 'E' (extension) format. */
4216b899c4eSMike Frysinger
4226b899c4eSMike Frysinger /* Skip the 'offset' field. */
4231da177e4SLinus Torvalds p = strchr(p, del);
4241da177e4SLinus Torvalds if (!p)
425e6084d4aSMike Frysinger goto einval;
4261da177e4SLinus Torvalds *p++ = '\0';
4276b899c4eSMike Frysinger
4286b899c4eSMike Frysinger /* Parse the 'magic' field. */
4291da177e4SLinus Torvalds e->magic = p;
4301da177e4SLinus Torvalds p = strchr(p, del);
4311da177e4SLinus Torvalds if (!p)
432e6084d4aSMike Frysinger goto einval;
4331da177e4SLinus Torvalds *p++ = '\0';
4341da177e4SLinus Torvalds if (!e->magic[0] || strchr(e->magic, '/'))
435e6084d4aSMike Frysinger goto einval;
4366b899c4eSMike Frysinger pr_debug("register: extension: {%s}\n", e->magic);
4376b899c4eSMike Frysinger
4386b899c4eSMike Frysinger /* Skip the 'mask' field. */
4391da177e4SLinus Torvalds p = strchr(p, del);
4401da177e4SLinus Torvalds if (!p)
441e6084d4aSMike Frysinger goto einval;
4421da177e4SLinus Torvalds *p++ = '\0';
4431da177e4SLinus Torvalds }
4446b899c4eSMike Frysinger
4456b899c4eSMike Frysinger /* Parse the 'interpreter' field. */
4461da177e4SLinus Torvalds e->interpreter = p;
4471da177e4SLinus Torvalds p = strchr(p, del);
4481da177e4SLinus Torvalds if (!p)
449e6084d4aSMike Frysinger goto einval;
4501da177e4SLinus Torvalds *p++ = '\0';
4511da177e4SLinus Torvalds if (!e->interpreter[0])
452e6084d4aSMike Frysinger goto einval;
4536b899c4eSMike Frysinger pr_debug("register: interpreter: {%s}\n", e->interpreter);
4541da177e4SLinus Torvalds
4556b899c4eSMike Frysinger /* Parse the 'flags' field. */
4561da177e4SLinus Torvalds p = check_special_flags(p, e);
4571da177e4SLinus Torvalds if (*p == '\n')
4581da177e4SLinus Torvalds p++;
4591da177e4SLinus Torvalds if (p != buf + count)
460e6084d4aSMike Frysinger goto einval;
461e6084d4aSMike Frysinger
4621da177e4SLinus Torvalds return e;
4631da177e4SLinus Torvalds
4641da177e4SLinus Torvalds out:
4651da177e4SLinus Torvalds return ERR_PTR(err);
4661da177e4SLinus Torvalds
467e6084d4aSMike Frysinger efault:
4681da177e4SLinus Torvalds kfree(e);
4691da177e4SLinus Torvalds return ERR_PTR(-EFAULT);
470e6084d4aSMike Frysinger einval:
4711da177e4SLinus Torvalds kfree(e);
4721da177e4SLinus Torvalds return ERR_PTR(-EINVAL);
4731da177e4SLinus Torvalds }
4741da177e4SLinus Torvalds
4751da177e4SLinus Torvalds /*
4761da177e4SLinus Torvalds * Set status of entry/binfmt_misc:
4771da177e4SLinus Torvalds * '1' enables, '0' disables and '-1' clears entry/binfmt_misc
4781da177e4SLinus Torvalds */
parse_command(const char __user * buffer,size_t count)4791da177e4SLinus Torvalds static int parse_command(const char __user *buffer, size_t count)
4801da177e4SLinus Torvalds {
4811da177e4SLinus Torvalds char s[4];
4821da177e4SLinus Torvalds
4831da177e4SLinus Torvalds if (count > 3)
4841da177e4SLinus Torvalds return -EINVAL;
4851da177e4SLinus Torvalds if (copy_from_user(s, buffer, count))
4861da177e4SLinus Torvalds return -EFAULT;
487de8288b1SArnd Bergmann if (!count)
488de8288b1SArnd Bergmann return 0;
4891da177e4SLinus Torvalds if (s[count - 1] == '\n')
4901da177e4SLinus Torvalds count--;
4911da177e4SLinus Torvalds if (count == 1 && s[0] == '0')
4921da177e4SLinus Torvalds return 1;
4931da177e4SLinus Torvalds if (count == 1 && s[0] == '1')
4941da177e4SLinus Torvalds return 2;
4951da177e4SLinus Torvalds if (count == 2 && s[0] == '-' && s[1] == '1')
4961da177e4SLinus Torvalds return 3;
4971da177e4SLinus Torvalds return -EINVAL;
4981da177e4SLinus Torvalds }
4991da177e4SLinus Torvalds
5001da177e4SLinus Torvalds /* generic stuff */
5011da177e4SLinus Torvalds
entry_status(Node * e,char * page)5021da177e4SLinus Torvalds static void entry_status(Node *e, char *page)
5031da177e4SLinus Torvalds {
5046ceafb88SRasmus Villemoes char *dp = page;
5056ceafb88SRasmus Villemoes const char *status = "disabled";
5061da177e4SLinus Torvalds
5071da177e4SLinus Torvalds if (test_bit(Enabled, &e->flags))
5081da177e4SLinus Torvalds status = "enabled";
5091da177e4SLinus Torvalds
5101da177e4SLinus Torvalds if (!VERBOSE_STATUS) {
5111da177e4SLinus Torvalds sprintf(page, "%s\n", status);
5121da177e4SLinus Torvalds return;
5131da177e4SLinus Torvalds }
5141da177e4SLinus Torvalds
5156ceafb88SRasmus Villemoes dp += sprintf(dp, "%s\ninterpreter %s\n", status, e->interpreter);
5161da177e4SLinus Torvalds
5171da177e4SLinus Torvalds /* print the special flags */
5186ceafb88SRasmus Villemoes dp += sprintf(dp, "flags: ");
519e6084d4aSMike Frysinger if (e->flags & MISC_FMT_PRESERVE_ARGV0)
5201da177e4SLinus Torvalds *dp++ = 'P';
521e6084d4aSMike Frysinger if (e->flags & MISC_FMT_OPEN_BINARY)
5221da177e4SLinus Torvalds *dp++ = 'O';
523e6084d4aSMike Frysinger if (e->flags & MISC_FMT_CREDENTIALS)
5241da177e4SLinus Torvalds *dp++ = 'C';
525948b701aSJames Bottomley if (e->flags & MISC_FMT_OPEN_FILE)
526948b701aSJames Bottomley *dp++ = 'F';
5271da177e4SLinus Torvalds *dp++ = '\n';
5281da177e4SLinus Torvalds
5291da177e4SLinus Torvalds if (!test_bit(Magic, &e->flags)) {
5301da177e4SLinus Torvalds sprintf(dp, "extension .%s\n", e->magic);
5311da177e4SLinus Torvalds } else {
5326ceafb88SRasmus Villemoes dp += sprintf(dp, "offset %i\nmagic ", e->offset);
5336ceafb88SRasmus Villemoes dp = bin2hex(dp, e->magic, e->size);
5341da177e4SLinus Torvalds if (e->mask) {
5356ceafb88SRasmus Villemoes dp += sprintf(dp, "\nmask ");
5366ceafb88SRasmus Villemoes dp = bin2hex(dp, e->mask, e->size);
5371da177e4SLinus Torvalds }
5381da177e4SLinus Torvalds *dp++ = '\n';
5391da177e4SLinus Torvalds *dp = '\0';
5401da177e4SLinus Torvalds }
5411da177e4SLinus Torvalds }
5421da177e4SLinus Torvalds
bm_get_inode(struct super_block * sb,int mode)5431da177e4SLinus Torvalds static struct inode *bm_get_inode(struct super_block *sb, int mode)
5441da177e4SLinus Torvalds {
5451da177e4SLinus Torvalds struct inode *inode = new_inode(sb);
5461da177e4SLinus Torvalds
5471da177e4SLinus Torvalds if (inode) {
54885fe4025SChristoph Hellwig inode->i_ino = get_next_ino();
5491da177e4SLinus Torvalds inode->i_mode = mode;
550*2276e5baSJeff Layton inode->i_atime = inode->i_mtime = inode_set_ctime_current(inode);
5511da177e4SLinus Torvalds }
5521da177e4SLinus Torvalds return inode;
5531da177e4SLinus Torvalds }
5541da177e4SLinus Torvalds
bm_evict_inode(struct inode * inode)555b57922d9SAl Viro static void bm_evict_inode(struct inode *inode)
5561da177e4SLinus Torvalds {
55783f91827SOleg Nesterov Node *e = inode->i_private;
55883f91827SOleg Nesterov
5597e866006SEryu Guan if (e && e->flags & MISC_FMT_OPEN_FILE)
56083f91827SOleg Nesterov filp_close(e->interp_file, NULL);
56183f91827SOleg Nesterov
562dbd5768fSJan Kara clear_inode(inode);
56383f91827SOleg Nesterov kfree(e);
5641da177e4SLinus Torvalds }
5651da177e4SLinus Torvalds
kill_node(Node * e)5661da177e4SLinus Torvalds static void kill_node(Node *e)
5671da177e4SLinus Torvalds {
5681da177e4SLinus Torvalds struct dentry *dentry;
5691da177e4SLinus Torvalds
5701da177e4SLinus Torvalds write_lock(&entries_lock);
5711da177e4SLinus Torvalds list_del_init(&e->list);
5721da177e4SLinus Torvalds write_unlock(&entries_lock);
5731da177e4SLinus Torvalds
574baba1b29SOleg Nesterov dentry = e->dentry;
57575c3cfa8SDavid Howells drop_nlink(d_inode(dentry));
5761da177e4SLinus Torvalds d_drop(dentry);
5771da177e4SLinus Torvalds dput(dentry);
5781da177e4SLinus Torvalds simple_release_fs(&bm_mnt, &entry_count);
5791da177e4SLinus Torvalds }
5801da177e4SLinus Torvalds
5811da177e4SLinus Torvalds /* /<entry> */
5821da177e4SLinus Torvalds
5831da177e4SLinus Torvalds static ssize_t
bm_entry_read(struct file * file,char __user * buf,size_t nbytes,loff_t * ppos)5841da177e4SLinus Torvalds bm_entry_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
5851da177e4SLinus Torvalds {
586496ad9aaSAl Viro Node *e = file_inode(file)->i_private;
5871da177e4SLinus Torvalds ssize_t res;
5881da177e4SLinus Torvalds char *page;
5891da177e4SLinus Torvalds
590e6084d4aSMike Frysinger page = (char *) __get_free_page(GFP_KERNEL);
591e6084d4aSMike Frysinger if (!page)
5921da177e4SLinus Torvalds return -ENOMEM;
5931da177e4SLinus Torvalds
5941da177e4SLinus Torvalds entry_status(e, page);
5951da177e4SLinus Torvalds
5966e2c10a1SAkinobu Mita res = simple_read_from_buffer(buf, nbytes, ppos, page, strlen(page));
5976e2c10a1SAkinobu Mita
5981da177e4SLinus Torvalds free_page((unsigned long) page);
5991da177e4SLinus Torvalds return res;
6001da177e4SLinus Torvalds }
6011da177e4SLinus Torvalds
bm_entry_write(struct file * file,const char __user * buffer,size_t count,loff_t * ppos)6021da177e4SLinus Torvalds static ssize_t bm_entry_write(struct file *file, const char __user *buffer,
6031da177e4SLinus Torvalds size_t count, loff_t *ppos)
6041da177e4SLinus Torvalds {
6051da177e4SLinus Torvalds struct dentry *root;
606496ad9aaSAl Viro Node *e = file_inode(file)->i_private;
6071da177e4SLinus Torvalds int res = parse_command(buffer, count);
6081da177e4SLinus Torvalds
6091da177e4SLinus Torvalds switch (res) {
6106b899c4eSMike Frysinger case 1:
6116b899c4eSMike Frysinger /* Disable this handler. */
6126b899c4eSMike Frysinger clear_bit(Enabled, &e->flags);
6131da177e4SLinus Torvalds break;
6146b899c4eSMike Frysinger case 2:
6156b899c4eSMike Frysinger /* Enable this handler. */
6166b899c4eSMike Frysinger set_bit(Enabled, &e->flags);
6171da177e4SLinus Torvalds break;
6186b899c4eSMike Frysinger case 3:
6196b899c4eSMike Frysinger /* Delete this handler. */
620ea7d4c04SAl Viro root = file_inode(file)->i_sb->s_root;
6215955102cSAl Viro inode_lock(d_inode(root));
6221da177e4SLinus Torvalds
623baba1b29SOleg Nesterov if (!list_empty(&e->list))
6241da177e4SLinus Torvalds kill_node(e);
6251da177e4SLinus Torvalds
6265955102cSAl Viro inode_unlock(d_inode(root));
6271da177e4SLinus Torvalds break;
628e6084d4aSMike Frysinger default:
629e6084d4aSMike Frysinger return res;
6301da177e4SLinus Torvalds }
631e6084d4aSMike Frysinger
6321da177e4SLinus Torvalds return count;
6331da177e4SLinus Torvalds }
6341da177e4SLinus Torvalds
6354b6f5d20SArjan van de Ven static const struct file_operations bm_entry_operations = {
6361da177e4SLinus Torvalds .read = bm_entry_read,
6371da177e4SLinus Torvalds .write = bm_entry_write,
6386038f373SArnd Bergmann .llseek = default_llseek,
6391da177e4SLinus Torvalds };
6401da177e4SLinus Torvalds
6411da177e4SLinus Torvalds /* /register */
6421da177e4SLinus Torvalds
bm_register_write(struct file * file,const char __user * buffer,size_t count,loff_t * ppos)6431da177e4SLinus Torvalds static ssize_t bm_register_write(struct file *file, const char __user *buffer,
6441da177e4SLinus Torvalds size_t count, loff_t *ppos)
6451da177e4SLinus Torvalds {
6461da177e4SLinus Torvalds Node *e;
6471da177e4SLinus Torvalds struct inode *inode;
648ea7d4c04SAl Viro struct super_block *sb = file_inode(file)->i_sb;
649ea7d4c04SAl Viro struct dentry *root = sb->s_root, *dentry;
6501da177e4SLinus Torvalds int err = 0;
651e7850f4dSLior Ribak struct file *f = NULL;
6521da177e4SLinus Torvalds
6531da177e4SLinus Torvalds e = create_entry(buffer, count);
6541da177e4SLinus Torvalds
6551da177e4SLinus Torvalds if (IS_ERR(e))
6561da177e4SLinus Torvalds return PTR_ERR(e);
6571da177e4SLinus Torvalds
658e7850f4dSLior Ribak if (e->flags & MISC_FMT_OPEN_FILE) {
659e7850f4dSLior Ribak f = open_exec(e->interpreter);
660e7850f4dSLior Ribak if (IS_ERR(f)) {
661e7850f4dSLior Ribak pr_notice("register: failed to install interpreter file %s\n",
662e7850f4dSLior Ribak e->interpreter);
663e7850f4dSLior Ribak kfree(e);
664e7850f4dSLior Ribak return PTR_ERR(f);
665e7850f4dSLior Ribak }
666e7850f4dSLior Ribak e->interp_file = f;
667e7850f4dSLior Ribak }
668e7850f4dSLior Ribak
6695955102cSAl Viro inode_lock(d_inode(root));
6701da177e4SLinus Torvalds dentry = lookup_one_len(e->name, root, strlen(e->name));
6711da177e4SLinus Torvalds err = PTR_ERR(dentry);
6721da177e4SLinus Torvalds if (IS_ERR(dentry))
6731da177e4SLinus Torvalds goto out;
6741da177e4SLinus Torvalds
6751da177e4SLinus Torvalds err = -EEXIST;
67675c3cfa8SDavid Howells if (d_really_is_positive(dentry))
6771da177e4SLinus Torvalds goto out2;
6781da177e4SLinus Torvalds
6791da177e4SLinus Torvalds inode = bm_get_inode(sb, S_IFREG | 0644);
6801da177e4SLinus Torvalds
6811da177e4SLinus Torvalds err = -ENOMEM;
6821da177e4SLinus Torvalds if (!inode)
6831da177e4SLinus Torvalds goto out2;
6841da177e4SLinus Torvalds
6851f5ce9e9STrond Myklebust err = simple_pin_fs(&bm_fs_type, &bm_mnt, &entry_count);
6861da177e4SLinus Torvalds if (err) {
6871da177e4SLinus Torvalds iput(inode);
6881da177e4SLinus Torvalds inode = NULL;
6891da177e4SLinus Torvalds goto out2;
6901da177e4SLinus Torvalds }
6911da177e4SLinus Torvalds
6921da177e4SLinus Torvalds e->dentry = dget(dentry);
6938e18e294STheodore Ts'o inode->i_private = e;
6941da177e4SLinus Torvalds inode->i_fop = &bm_entry_operations;
6951da177e4SLinus Torvalds
6961da177e4SLinus Torvalds d_instantiate(dentry, inode);
6971da177e4SLinus Torvalds write_lock(&entries_lock);
6981da177e4SLinus Torvalds list_add(&e->list, &entries);
6991da177e4SLinus Torvalds write_unlock(&entries_lock);
7001da177e4SLinus Torvalds
7011da177e4SLinus Torvalds err = 0;
7021da177e4SLinus Torvalds out2:
7031da177e4SLinus Torvalds dput(dentry);
7041da177e4SLinus Torvalds out:
7055955102cSAl Viro inode_unlock(d_inode(root));
7061da177e4SLinus Torvalds
7071da177e4SLinus Torvalds if (err) {
708e7850f4dSLior Ribak if (f)
709e7850f4dSLior Ribak filp_close(f, NULL);
7101da177e4SLinus Torvalds kfree(e);
711948b701aSJames Bottomley return err;
7121da177e4SLinus Torvalds }
7131da177e4SLinus Torvalds return count;
7141da177e4SLinus Torvalds }
7151da177e4SLinus Torvalds
7164b6f5d20SArjan van de Ven static const struct file_operations bm_register_operations = {
7171da177e4SLinus Torvalds .write = bm_register_write,
7186038f373SArnd Bergmann .llseek = noop_llseek,
7191da177e4SLinus Torvalds };
7201da177e4SLinus Torvalds
7211da177e4SLinus Torvalds /* /status */
7221da177e4SLinus Torvalds
7231da177e4SLinus Torvalds static ssize_t
bm_status_read(struct file * file,char __user * buf,size_t nbytes,loff_t * ppos)7241da177e4SLinus Torvalds bm_status_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
7251da177e4SLinus Torvalds {
72687113e80SQinghuang Feng char *s = enabled ? "enabled\n" : "disabled\n";
7271da177e4SLinus Torvalds
72892f4c701SAkinobu Mita return simple_read_from_buffer(buf, nbytes, ppos, s, strlen(s));
7291da177e4SLinus Torvalds }
7301da177e4SLinus Torvalds
bm_status_write(struct file * file,const char __user * buffer,size_t count,loff_t * ppos)7311da177e4SLinus Torvalds static ssize_t bm_status_write(struct file *file, const char __user *buffer,
7321da177e4SLinus Torvalds size_t count, loff_t *ppos)
7331da177e4SLinus Torvalds {
7341da177e4SLinus Torvalds int res = parse_command(buffer, count);
7351da177e4SLinus Torvalds struct dentry *root;
7361da177e4SLinus Torvalds
7371da177e4SLinus Torvalds switch (res) {
7386b899c4eSMike Frysinger case 1:
7396b899c4eSMike Frysinger /* Disable all handlers. */
7406b899c4eSMike Frysinger enabled = 0;
7416b899c4eSMike Frysinger break;
7426b899c4eSMike Frysinger case 2:
7436b899c4eSMike Frysinger /* Enable all handlers. */
7446b899c4eSMike Frysinger enabled = 1;
7456b899c4eSMike Frysinger break;
7466b899c4eSMike Frysinger case 3:
7476b899c4eSMike Frysinger /* Delete all handlers. */
748ea7d4c04SAl Viro root = file_inode(file)->i_sb->s_root;
7495955102cSAl Viro inode_lock(d_inode(root));
7501da177e4SLinus Torvalds
7511da177e4SLinus Torvalds while (!list_empty(&entries))
752baba1b29SOleg Nesterov kill_node(list_first_entry(&entries, Node, list));
7531da177e4SLinus Torvalds
7545955102cSAl Viro inode_unlock(d_inode(root));
755b003f965SLuis Henriques break;
756e6084d4aSMike Frysinger default:
757e6084d4aSMike Frysinger return res;
7581da177e4SLinus Torvalds }
759e6084d4aSMike Frysinger
7601da177e4SLinus Torvalds return count;
7611da177e4SLinus Torvalds }
7621da177e4SLinus Torvalds
7634b6f5d20SArjan van de Ven static const struct file_operations bm_status_operations = {
7641da177e4SLinus Torvalds .read = bm_status_read,
7651da177e4SLinus Torvalds .write = bm_status_write,
7666038f373SArnd Bergmann .llseek = default_llseek,
7671da177e4SLinus Torvalds };
7681da177e4SLinus Torvalds
7691da177e4SLinus Torvalds /* Superblock handling */
7701da177e4SLinus Torvalds
771ee9b6d61SJosef 'Jeff' Sipek static const struct super_operations s_ops = {
7721da177e4SLinus Torvalds .statfs = simple_statfs,
773b57922d9SAl Viro .evict_inode = bm_evict_inode,
7741da177e4SLinus Torvalds };
7751da177e4SLinus Torvalds
bm_fill_super(struct super_block * sb,struct fs_context * fc)776bc99a664SDavid Howells static int bm_fill_super(struct super_block *sb, struct fs_context *fc)
7771da177e4SLinus Torvalds {
778e6084d4aSMike Frysinger int err;
779cda37124SEric Biggers static const struct tree_descr bm_files[] = {
7801a1c9bb4SJeff Layton [2] = {"status", &bm_status_operations, S_IWUSR|S_IRUGO},
7811a1c9bb4SJeff Layton [3] = {"register", &bm_register_operations, S_IWUSR},
7821da177e4SLinus Torvalds /* last one */ {""}
7831da177e4SLinus Torvalds };
784e6084d4aSMike Frysinger
785e6084d4aSMike Frysinger err = simple_fill_super(sb, BINFMTFS_MAGIC, bm_files);
7861da177e4SLinus Torvalds if (!err)
7871da177e4SLinus Torvalds sb->s_op = &s_ops;
7881da177e4SLinus Torvalds return err;
7891da177e4SLinus Torvalds }
7901da177e4SLinus Torvalds
bm_get_tree(struct fs_context * fc)791bc99a664SDavid Howells static int bm_get_tree(struct fs_context *fc)
7921da177e4SLinus Torvalds {
793bc99a664SDavid Howells return get_tree_single(fc, bm_fill_super);
794bc99a664SDavid Howells }
795bc99a664SDavid Howells
796bc99a664SDavid Howells static const struct fs_context_operations bm_context_ops = {
797bc99a664SDavid Howells .get_tree = bm_get_tree,
798bc99a664SDavid Howells };
799bc99a664SDavid Howells
bm_init_fs_context(struct fs_context * fc)800bc99a664SDavid Howells static int bm_init_fs_context(struct fs_context *fc)
801bc99a664SDavid Howells {
802bc99a664SDavid Howells fc->ops = &bm_context_ops;
803bc99a664SDavid Howells return 0;
8041da177e4SLinus Torvalds }
8051da177e4SLinus Torvalds
8061da177e4SLinus Torvalds static struct linux_binfmt misc_format = {
8071da177e4SLinus Torvalds .module = THIS_MODULE,
8081da177e4SLinus Torvalds .load_binary = load_misc_binary,
8091da177e4SLinus Torvalds };
8101da177e4SLinus Torvalds
8111da177e4SLinus Torvalds static struct file_system_type bm_fs_type = {
8121da177e4SLinus Torvalds .owner = THIS_MODULE,
8131da177e4SLinus Torvalds .name = "binfmt_misc",
814bc99a664SDavid Howells .init_fs_context = bm_init_fs_context,
8151da177e4SLinus Torvalds .kill_sb = kill_litter_super,
8161da177e4SLinus Torvalds };
8177f78e035SEric W. Biederman MODULE_ALIAS_FS("binfmt_misc");
8181da177e4SLinus Torvalds
init_misc_binfmt(void)8191da177e4SLinus Torvalds static int __init init_misc_binfmt(void)
8201da177e4SLinus Torvalds {
8211da177e4SLinus Torvalds int err = register_filesystem(&bm_fs_type);
8228fc3dc5aSAl Viro if (!err)
8238fc3dc5aSAl Viro insert_binfmt(&misc_format);
824b42bc9a3SDomenico Andreoli return err;
8251da177e4SLinus Torvalds }
8261da177e4SLinus Torvalds
exit_misc_binfmt(void)8271da177e4SLinus Torvalds static void __exit exit_misc_binfmt(void)
8281da177e4SLinus Torvalds {
8291da177e4SLinus Torvalds unregister_binfmt(&misc_format);
8301da177e4SLinus Torvalds unregister_filesystem(&bm_fs_type);
8311da177e4SLinus Torvalds }
8321da177e4SLinus Torvalds
8331da177e4SLinus Torvalds core_initcall(init_misc_binfmt);
8341da177e4SLinus Torvalds module_exit(exit_misc_binfmt);
8351da177e4SLinus Torvalds MODULE_LICENSE("GPL");
836