1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * binfmt_misc.c
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 1997 Richard Günther
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * binfmt_misc detects binaries via a magic or filename extension and invokes
8*4882a593Smuzhiyun * a specified wrapper. See Documentation/admin-guide/binfmt-misc.rst for more details.
9*4882a593Smuzhiyun */
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include <linux/kernel.h>
14*4882a593Smuzhiyun #include <linux/module.h>
15*4882a593Smuzhiyun #include <linux/init.h>
16*4882a593Smuzhiyun #include <linux/sched/mm.h>
17*4882a593Smuzhiyun #include <linux/magic.h>
18*4882a593Smuzhiyun #include <linux/binfmts.h>
19*4882a593Smuzhiyun #include <linux/slab.h>
20*4882a593Smuzhiyun #include <linux/ctype.h>
21*4882a593Smuzhiyun #include <linux/string_helpers.h>
22*4882a593Smuzhiyun #include <linux/file.h>
23*4882a593Smuzhiyun #include <linux/pagemap.h>
24*4882a593Smuzhiyun #include <linux/namei.h>
25*4882a593Smuzhiyun #include <linux/mount.h>
26*4882a593Smuzhiyun #include <linux/fs_context.h>
27*4882a593Smuzhiyun #include <linux/syscalls.h>
28*4882a593Smuzhiyun #include <linux/fs.h>
29*4882a593Smuzhiyun #include <linux/uaccess.h>
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun #include "internal.h"
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #ifdef DEBUG
34*4882a593Smuzhiyun # define USE_DEBUG 1
35*4882a593Smuzhiyun #else
36*4882a593Smuzhiyun # define USE_DEBUG 0
37*4882a593Smuzhiyun #endif
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun enum {
40*4882a593Smuzhiyun VERBOSE_STATUS = 1 /* make it zero to save 400 bytes kernel memory */
41*4882a593Smuzhiyun };
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun static LIST_HEAD(entries);
44*4882a593Smuzhiyun static int enabled = 1;
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun enum {Enabled, Magic};
47*4882a593Smuzhiyun #define MISC_FMT_PRESERVE_ARGV0 (1 << 31)
48*4882a593Smuzhiyun #define MISC_FMT_OPEN_BINARY (1 << 30)
49*4882a593Smuzhiyun #define MISC_FMT_CREDENTIALS (1 << 29)
50*4882a593Smuzhiyun #define MISC_FMT_OPEN_FILE (1 << 28)
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun typedef struct {
53*4882a593Smuzhiyun struct list_head list;
54*4882a593Smuzhiyun unsigned long flags; /* type, status, etc. */
55*4882a593Smuzhiyun int offset; /* offset of magic */
56*4882a593Smuzhiyun int size; /* size of magic/mask */
57*4882a593Smuzhiyun char *magic; /* magic or filename extension */
58*4882a593Smuzhiyun char *mask; /* mask, NULL for exact match */
59*4882a593Smuzhiyun const char *interpreter; /* filename of interpreter */
60*4882a593Smuzhiyun char *name;
61*4882a593Smuzhiyun struct dentry *dentry;
62*4882a593Smuzhiyun struct file *interp_file;
63*4882a593Smuzhiyun } Node;
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun static DEFINE_RWLOCK(entries_lock);
66*4882a593Smuzhiyun static struct file_system_type bm_fs_type;
67*4882a593Smuzhiyun static struct vfsmount *bm_mnt;
68*4882a593Smuzhiyun static int entry_count;
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun /*
71*4882a593Smuzhiyun * Max length of the register string. Determined by:
72*4882a593Smuzhiyun * - 7 delimiters
73*4882a593Smuzhiyun * - name: ~50 bytes
74*4882a593Smuzhiyun * - type: 1 byte
75*4882a593Smuzhiyun * - offset: 3 bytes (has to be smaller than BINPRM_BUF_SIZE)
76*4882a593Smuzhiyun * - magic: 128 bytes (512 in escaped form)
77*4882a593Smuzhiyun * - mask: 128 bytes (512 in escaped form)
78*4882a593Smuzhiyun * - interp: ~50 bytes
79*4882a593Smuzhiyun * - flags: 5 bytes
80*4882a593Smuzhiyun * Round that up a bit, and then back off to hold the internal data
81*4882a593Smuzhiyun * (like struct Node).
82*4882a593Smuzhiyun */
83*4882a593Smuzhiyun #define MAX_REGISTER_LENGTH 1920
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun /*
86*4882a593Smuzhiyun * Check if we support the binfmt
87*4882a593Smuzhiyun * if we do, return the node, else NULL
88*4882a593Smuzhiyun * locking is done in load_misc_binary
89*4882a593Smuzhiyun */
check_file(struct linux_binprm * bprm)90*4882a593Smuzhiyun static Node *check_file(struct linux_binprm *bprm)
91*4882a593Smuzhiyun {
92*4882a593Smuzhiyun char *p = strrchr(bprm->interp, '.');
93*4882a593Smuzhiyun struct list_head *l;
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun /* Walk all the registered handlers. */
96*4882a593Smuzhiyun list_for_each(l, &entries) {
97*4882a593Smuzhiyun Node *e = list_entry(l, Node, list);
98*4882a593Smuzhiyun char *s;
99*4882a593Smuzhiyun int j;
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun /* Make sure this one is currently enabled. */
102*4882a593Smuzhiyun if (!test_bit(Enabled, &e->flags))
103*4882a593Smuzhiyun continue;
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun /* Do matching based on extension if applicable. */
106*4882a593Smuzhiyun if (!test_bit(Magic, &e->flags)) {
107*4882a593Smuzhiyun if (p && !strcmp(e->magic, p + 1))
108*4882a593Smuzhiyun return e;
109*4882a593Smuzhiyun continue;
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun /* Do matching based on magic & mask. */
113*4882a593Smuzhiyun s = bprm->buf + e->offset;
114*4882a593Smuzhiyun if (e->mask) {
115*4882a593Smuzhiyun for (j = 0; j < e->size; j++)
116*4882a593Smuzhiyun if ((*s++ ^ e->magic[j]) & e->mask[j])
117*4882a593Smuzhiyun break;
118*4882a593Smuzhiyun } else {
119*4882a593Smuzhiyun for (j = 0; j < e->size; j++)
120*4882a593Smuzhiyun if ((*s++ ^ e->magic[j]))
121*4882a593Smuzhiyun break;
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun if (j == e->size)
124*4882a593Smuzhiyun return e;
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun return NULL;
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun /*
130*4882a593Smuzhiyun * the loader itself
131*4882a593Smuzhiyun */
load_misc_binary(struct linux_binprm * bprm)132*4882a593Smuzhiyun static int load_misc_binary(struct linux_binprm *bprm)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun Node *fmt;
135*4882a593Smuzhiyun struct file *interp_file = NULL;
136*4882a593Smuzhiyun int retval;
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun retval = -ENOEXEC;
139*4882a593Smuzhiyun if (!enabled)
140*4882a593Smuzhiyun return retval;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun /* to keep locking time low, we copy the interpreter string */
143*4882a593Smuzhiyun read_lock(&entries_lock);
144*4882a593Smuzhiyun fmt = check_file(bprm);
145*4882a593Smuzhiyun if (fmt)
146*4882a593Smuzhiyun dget(fmt->dentry);
147*4882a593Smuzhiyun read_unlock(&entries_lock);
148*4882a593Smuzhiyun if (!fmt)
149*4882a593Smuzhiyun return retval;
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun /* Need to be able to load the file after exec */
152*4882a593Smuzhiyun retval = -ENOENT;
153*4882a593Smuzhiyun if (bprm->interp_flags & BINPRM_FLAGS_PATH_INACCESSIBLE)
154*4882a593Smuzhiyun goto ret;
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun if (!(fmt->flags & MISC_FMT_PRESERVE_ARGV0)) {
157*4882a593Smuzhiyun retval = remove_arg_zero(bprm);
158*4882a593Smuzhiyun if (retval)
159*4882a593Smuzhiyun goto ret;
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun if (fmt->flags & MISC_FMT_OPEN_BINARY)
163*4882a593Smuzhiyun bprm->have_execfd = 1;
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun /* make argv[1] be the path to the binary */
166*4882a593Smuzhiyun retval = copy_string_kernel(bprm->interp, bprm);
167*4882a593Smuzhiyun if (retval < 0)
168*4882a593Smuzhiyun goto ret;
169*4882a593Smuzhiyun bprm->argc++;
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun /* add the interp as argv[0] */
172*4882a593Smuzhiyun retval = copy_string_kernel(fmt->interpreter, bprm);
173*4882a593Smuzhiyun if (retval < 0)
174*4882a593Smuzhiyun goto ret;
175*4882a593Smuzhiyun bprm->argc++;
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun /* Update interp in case binfmt_script needs it. */
178*4882a593Smuzhiyun retval = bprm_change_interp(fmt->interpreter, bprm);
179*4882a593Smuzhiyun if (retval < 0)
180*4882a593Smuzhiyun goto ret;
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun if (fmt->flags & MISC_FMT_OPEN_FILE) {
183*4882a593Smuzhiyun interp_file = file_clone_open(fmt->interp_file);
184*4882a593Smuzhiyun if (!IS_ERR(interp_file))
185*4882a593Smuzhiyun deny_write_access(interp_file);
186*4882a593Smuzhiyun } else {
187*4882a593Smuzhiyun interp_file = open_exec(fmt->interpreter);
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun retval = PTR_ERR(interp_file);
190*4882a593Smuzhiyun if (IS_ERR(interp_file))
191*4882a593Smuzhiyun goto ret;
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun bprm->interpreter = interp_file;
194*4882a593Smuzhiyun if (fmt->flags & MISC_FMT_CREDENTIALS)
195*4882a593Smuzhiyun bprm->execfd_creds = 1;
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun retval = 0;
198*4882a593Smuzhiyun ret:
199*4882a593Smuzhiyun dput(fmt->dentry);
200*4882a593Smuzhiyun return retval;
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun /* Command parsers */
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun /*
206*4882a593Smuzhiyun * parses and copies one argument enclosed in del from *sp to *dp,
207*4882a593Smuzhiyun * recognising the \x special.
208*4882a593Smuzhiyun * returns pointer to the copied argument or NULL in case of an
209*4882a593Smuzhiyun * error (and sets err) or null argument length.
210*4882a593Smuzhiyun */
scanarg(char * s,char del)211*4882a593Smuzhiyun static char *scanarg(char *s, char del)
212*4882a593Smuzhiyun {
213*4882a593Smuzhiyun char c;
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun while ((c = *s++) != del) {
216*4882a593Smuzhiyun if (c == '\\' && *s == 'x') {
217*4882a593Smuzhiyun s++;
218*4882a593Smuzhiyun if (!isxdigit(*s++))
219*4882a593Smuzhiyun return NULL;
220*4882a593Smuzhiyun if (!isxdigit(*s++))
221*4882a593Smuzhiyun return NULL;
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun }
224*4882a593Smuzhiyun s[-1] ='\0';
225*4882a593Smuzhiyun return s;
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun
check_special_flags(char * sfs,Node * e)228*4882a593Smuzhiyun static char *check_special_flags(char *sfs, Node *e)
229*4882a593Smuzhiyun {
230*4882a593Smuzhiyun char *p = sfs;
231*4882a593Smuzhiyun int cont = 1;
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun /* special flags */
234*4882a593Smuzhiyun while (cont) {
235*4882a593Smuzhiyun switch (*p) {
236*4882a593Smuzhiyun case 'P':
237*4882a593Smuzhiyun pr_debug("register: flag: P (preserve argv0)\n");
238*4882a593Smuzhiyun p++;
239*4882a593Smuzhiyun e->flags |= MISC_FMT_PRESERVE_ARGV0;
240*4882a593Smuzhiyun break;
241*4882a593Smuzhiyun case 'O':
242*4882a593Smuzhiyun pr_debug("register: flag: O (open binary)\n");
243*4882a593Smuzhiyun p++;
244*4882a593Smuzhiyun e->flags |= MISC_FMT_OPEN_BINARY;
245*4882a593Smuzhiyun break;
246*4882a593Smuzhiyun case 'C':
247*4882a593Smuzhiyun pr_debug("register: flag: C (preserve creds)\n");
248*4882a593Smuzhiyun p++;
249*4882a593Smuzhiyun /* this flags also implies the
250*4882a593Smuzhiyun open-binary flag */
251*4882a593Smuzhiyun e->flags |= (MISC_FMT_CREDENTIALS |
252*4882a593Smuzhiyun MISC_FMT_OPEN_BINARY);
253*4882a593Smuzhiyun break;
254*4882a593Smuzhiyun case 'F':
255*4882a593Smuzhiyun pr_debug("register: flag: F: open interpreter file now\n");
256*4882a593Smuzhiyun p++;
257*4882a593Smuzhiyun e->flags |= MISC_FMT_OPEN_FILE;
258*4882a593Smuzhiyun break;
259*4882a593Smuzhiyun default:
260*4882a593Smuzhiyun cont = 0;
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun return p;
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun /*
268*4882a593Smuzhiyun * This registers a new binary format, it recognises the syntax
269*4882a593Smuzhiyun * ':name:type:offset:magic:mask:interpreter:flags'
270*4882a593Smuzhiyun * where the ':' is the IFS, that can be chosen with the first char
271*4882a593Smuzhiyun */
create_entry(const char __user * buffer,size_t count)272*4882a593Smuzhiyun static Node *create_entry(const char __user *buffer, size_t count)
273*4882a593Smuzhiyun {
274*4882a593Smuzhiyun Node *e;
275*4882a593Smuzhiyun int memsize, err;
276*4882a593Smuzhiyun char *buf, *p;
277*4882a593Smuzhiyun char del;
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun pr_debug("register: received %zu bytes\n", count);
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun /* some sanity checks */
282*4882a593Smuzhiyun err = -EINVAL;
283*4882a593Smuzhiyun if ((count < 11) || (count > MAX_REGISTER_LENGTH))
284*4882a593Smuzhiyun goto out;
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun err = -ENOMEM;
287*4882a593Smuzhiyun memsize = sizeof(Node) + count + 8;
288*4882a593Smuzhiyun e = kmalloc(memsize, GFP_KERNEL);
289*4882a593Smuzhiyun if (!e)
290*4882a593Smuzhiyun goto out;
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun p = buf = (char *)e + sizeof(Node);
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun memset(e, 0, sizeof(Node));
295*4882a593Smuzhiyun if (copy_from_user(buf, buffer, count))
296*4882a593Smuzhiyun goto efault;
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun del = *p++; /* delimeter */
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun pr_debug("register: delim: %#x {%c}\n", del, del);
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun /* Pad the buffer with the delim to simplify parsing below. */
303*4882a593Smuzhiyun memset(buf + count, del, 8);
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun /* Parse the 'name' field. */
306*4882a593Smuzhiyun e->name = p;
307*4882a593Smuzhiyun p = strchr(p, del);
308*4882a593Smuzhiyun if (!p)
309*4882a593Smuzhiyun goto einval;
310*4882a593Smuzhiyun *p++ = '\0';
311*4882a593Smuzhiyun if (!e->name[0] ||
312*4882a593Smuzhiyun !strcmp(e->name, ".") ||
313*4882a593Smuzhiyun !strcmp(e->name, "..") ||
314*4882a593Smuzhiyun strchr(e->name, '/'))
315*4882a593Smuzhiyun goto einval;
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun pr_debug("register: name: {%s}\n", e->name);
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun /* Parse the 'type' field. */
320*4882a593Smuzhiyun switch (*p++) {
321*4882a593Smuzhiyun case 'E':
322*4882a593Smuzhiyun pr_debug("register: type: E (extension)\n");
323*4882a593Smuzhiyun e->flags = 1 << Enabled;
324*4882a593Smuzhiyun break;
325*4882a593Smuzhiyun case 'M':
326*4882a593Smuzhiyun pr_debug("register: type: M (magic)\n");
327*4882a593Smuzhiyun e->flags = (1 << Enabled) | (1 << Magic);
328*4882a593Smuzhiyun break;
329*4882a593Smuzhiyun default:
330*4882a593Smuzhiyun goto einval;
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun if (*p++ != del)
333*4882a593Smuzhiyun goto einval;
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun if (test_bit(Magic, &e->flags)) {
336*4882a593Smuzhiyun /* Handle the 'M' (magic) format. */
337*4882a593Smuzhiyun char *s;
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun /* Parse the 'offset' field. */
340*4882a593Smuzhiyun s = strchr(p, del);
341*4882a593Smuzhiyun if (!s)
342*4882a593Smuzhiyun goto einval;
343*4882a593Smuzhiyun *s = '\0';
344*4882a593Smuzhiyun if (p != s) {
345*4882a593Smuzhiyun int r = kstrtoint(p, 10, &e->offset);
346*4882a593Smuzhiyun if (r != 0 || e->offset < 0)
347*4882a593Smuzhiyun goto einval;
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun p = s;
350*4882a593Smuzhiyun if (*p++)
351*4882a593Smuzhiyun goto einval;
352*4882a593Smuzhiyun pr_debug("register: offset: %#x\n", e->offset);
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun /* Parse the 'magic' field. */
355*4882a593Smuzhiyun e->magic = p;
356*4882a593Smuzhiyun p = scanarg(p, del);
357*4882a593Smuzhiyun if (!p)
358*4882a593Smuzhiyun goto einval;
359*4882a593Smuzhiyun if (!e->magic[0])
360*4882a593Smuzhiyun goto einval;
361*4882a593Smuzhiyun if (USE_DEBUG)
362*4882a593Smuzhiyun print_hex_dump_bytes(
363*4882a593Smuzhiyun KBUILD_MODNAME ": register: magic[raw]: ",
364*4882a593Smuzhiyun DUMP_PREFIX_NONE, e->magic, p - e->magic);
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun /* Parse the 'mask' field. */
367*4882a593Smuzhiyun e->mask = p;
368*4882a593Smuzhiyun p = scanarg(p, del);
369*4882a593Smuzhiyun if (!p)
370*4882a593Smuzhiyun goto einval;
371*4882a593Smuzhiyun if (!e->mask[0]) {
372*4882a593Smuzhiyun e->mask = NULL;
373*4882a593Smuzhiyun pr_debug("register: mask[raw]: none\n");
374*4882a593Smuzhiyun } else if (USE_DEBUG)
375*4882a593Smuzhiyun print_hex_dump_bytes(
376*4882a593Smuzhiyun KBUILD_MODNAME ": register: mask[raw]: ",
377*4882a593Smuzhiyun DUMP_PREFIX_NONE, e->mask, p - e->mask);
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun /*
380*4882a593Smuzhiyun * Decode the magic & mask fields.
381*4882a593Smuzhiyun * Note: while we might have accepted embedded NUL bytes from
382*4882a593Smuzhiyun * above, the unescape helpers here will stop at the first one
383*4882a593Smuzhiyun * it encounters.
384*4882a593Smuzhiyun */
385*4882a593Smuzhiyun e->size = string_unescape_inplace(e->magic, UNESCAPE_HEX);
386*4882a593Smuzhiyun if (e->mask &&
387*4882a593Smuzhiyun string_unescape_inplace(e->mask, UNESCAPE_HEX) != e->size)
388*4882a593Smuzhiyun goto einval;
389*4882a593Smuzhiyun if (e->size > BINPRM_BUF_SIZE ||
390*4882a593Smuzhiyun BINPRM_BUF_SIZE - e->size < e->offset)
391*4882a593Smuzhiyun goto einval;
392*4882a593Smuzhiyun pr_debug("register: magic/mask length: %i\n", e->size);
393*4882a593Smuzhiyun if (USE_DEBUG) {
394*4882a593Smuzhiyun print_hex_dump_bytes(
395*4882a593Smuzhiyun KBUILD_MODNAME ": register: magic[decoded]: ",
396*4882a593Smuzhiyun DUMP_PREFIX_NONE, e->magic, e->size);
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun if (e->mask) {
399*4882a593Smuzhiyun int i;
400*4882a593Smuzhiyun char *masked = kmalloc(e->size, GFP_KERNEL);
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun print_hex_dump_bytes(
403*4882a593Smuzhiyun KBUILD_MODNAME ": register: mask[decoded]: ",
404*4882a593Smuzhiyun DUMP_PREFIX_NONE, e->mask, e->size);
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun if (masked) {
407*4882a593Smuzhiyun for (i = 0; i < e->size; ++i)
408*4882a593Smuzhiyun masked[i] = e->magic[i] & e->mask[i];
409*4882a593Smuzhiyun print_hex_dump_bytes(
410*4882a593Smuzhiyun KBUILD_MODNAME ": register: magic[masked]: ",
411*4882a593Smuzhiyun DUMP_PREFIX_NONE, masked, e->size);
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun kfree(masked);
414*4882a593Smuzhiyun }
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun }
417*4882a593Smuzhiyun } else {
418*4882a593Smuzhiyun /* Handle the 'E' (extension) format. */
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun /* Skip the 'offset' field. */
421*4882a593Smuzhiyun p = strchr(p, del);
422*4882a593Smuzhiyun if (!p)
423*4882a593Smuzhiyun goto einval;
424*4882a593Smuzhiyun *p++ = '\0';
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun /* Parse the 'magic' field. */
427*4882a593Smuzhiyun e->magic = p;
428*4882a593Smuzhiyun p = strchr(p, del);
429*4882a593Smuzhiyun if (!p)
430*4882a593Smuzhiyun goto einval;
431*4882a593Smuzhiyun *p++ = '\0';
432*4882a593Smuzhiyun if (!e->magic[0] || strchr(e->magic, '/'))
433*4882a593Smuzhiyun goto einval;
434*4882a593Smuzhiyun pr_debug("register: extension: {%s}\n", e->magic);
435*4882a593Smuzhiyun
436*4882a593Smuzhiyun /* Skip the 'mask' field. */
437*4882a593Smuzhiyun p = strchr(p, del);
438*4882a593Smuzhiyun if (!p)
439*4882a593Smuzhiyun goto einval;
440*4882a593Smuzhiyun *p++ = '\0';
441*4882a593Smuzhiyun }
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun /* Parse the 'interpreter' field. */
444*4882a593Smuzhiyun e->interpreter = p;
445*4882a593Smuzhiyun p = strchr(p, del);
446*4882a593Smuzhiyun if (!p)
447*4882a593Smuzhiyun goto einval;
448*4882a593Smuzhiyun *p++ = '\0';
449*4882a593Smuzhiyun if (!e->interpreter[0])
450*4882a593Smuzhiyun goto einval;
451*4882a593Smuzhiyun pr_debug("register: interpreter: {%s}\n", e->interpreter);
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun /* Parse the 'flags' field. */
454*4882a593Smuzhiyun p = check_special_flags(p, e);
455*4882a593Smuzhiyun if (*p == '\n')
456*4882a593Smuzhiyun p++;
457*4882a593Smuzhiyun if (p != buf + count)
458*4882a593Smuzhiyun goto einval;
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun return e;
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun out:
463*4882a593Smuzhiyun return ERR_PTR(err);
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun efault:
466*4882a593Smuzhiyun kfree(e);
467*4882a593Smuzhiyun return ERR_PTR(-EFAULT);
468*4882a593Smuzhiyun einval:
469*4882a593Smuzhiyun kfree(e);
470*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
471*4882a593Smuzhiyun }
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun /*
474*4882a593Smuzhiyun * Set status of entry/binfmt_misc:
475*4882a593Smuzhiyun * '1' enables, '0' disables and '-1' clears entry/binfmt_misc
476*4882a593Smuzhiyun */
parse_command(const char __user * buffer,size_t count)477*4882a593Smuzhiyun static int parse_command(const char __user *buffer, size_t count)
478*4882a593Smuzhiyun {
479*4882a593Smuzhiyun char s[4];
480*4882a593Smuzhiyun
481*4882a593Smuzhiyun if (count > 3)
482*4882a593Smuzhiyun return -EINVAL;
483*4882a593Smuzhiyun if (copy_from_user(s, buffer, count))
484*4882a593Smuzhiyun return -EFAULT;
485*4882a593Smuzhiyun if (!count)
486*4882a593Smuzhiyun return 0;
487*4882a593Smuzhiyun if (s[count - 1] == '\n')
488*4882a593Smuzhiyun count--;
489*4882a593Smuzhiyun if (count == 1 && s[0] == '0')
490*4882a593Smuzhiyun return 1;
491*4882a593Smuzhiyun if (count == 1 && s[0] == '1')
492*4882a593Smuzhiyun return 2;
493*4882a593Smuzhiyun if (count == 2 && s[0] == '-' && s[1] == '1')
494*4882a593Smuzhiyun return 3;
495*4882a593Smuzhiyun return -EINVAL;
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun /* generic stuff */
499*4882a593Smuzhiyun
entry_status(Node * e,char * page)500*4882a593Smuzhiyun static void entry_status(Node *e, char *page)
501*4882a593Smuzhiyun {
502*4882a593Smuzhiyun char *dp = page;
503*4882a593Smuzhiyun const char *status = "disabled";
504*4882a593Smuzhiyun
505*4882a593Smuzhiyun if (test_bit(Enabled, &e->flags))
506*4882a593Smuzhiyun status = "enabled";
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun if (!VERBOSE_STATUS) {
509*4882a593Smuzhiyun sprintf(page, "%s\n", status);
510*4882a593Smuzhiyun return;
511*4882a593Smuzhiyun }
512*4882a593Smuzhiyun
513*4882a593Smuzhiyun dp += sprintf(dp, "%s\ninterpreter %s\n", status, e->interpreter);
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun /* print the special flags */
516*4882a593Smuzhiyun dp += sprintf(dp, "flags: ");
517*4882a593Smuzhiyun if (e->flags & MISC_FMT_PRESERVE_ARGV0)
518*4882a593Smuzhiyun *dp++ = 'P';
519*4882a593Smuzhiyun if (e->flags & MISC_FMT_OPEN_BINARY)
520*4882a593Smuzhiyun *dp++ = 'O';
521*4882a593Smuzhiyun if (e->flags & MISC_FMT_CREDENTIALS)
522*4882a593Smuzhiyun *dp++ = 'C';
523*4882a593Smuzhiyun if (e->flags & MISC_FMT_OPEN_FILE)
524*4882a593Smuzhiyun *dp++ = 'F';
525*4882a593Smuzhiyun *dp++ = '\n';
526*4882a593Smuzhiyun
527*4882a593Smuzhiyun if (!test_bit(Magic, &e->flags)) {
528*4882a593Smuzhiyun sprintf(dp, "extension .%s\n", e->magic);
529*4882a593Smuzhiyun } else {
530*4882a593Smuzhiyun dp += sprintf(dp, "offset %i\nmagic ", e->offset);
531*4882a593Smuzhiyun dp = bin2hex(dp, e->magic, e->size);
532*4882a593Smuzhiyun if (e->mask) {
533*4882a593Smuzhiyun dp += sprintf(dp, "\nmask ");
534*4882a593Smuzhiyun dp = bin2hex(dp, e->mask, e->size);
535*4882a593Smuzhiyun }
536*4882a593Smuzhiyun *dp++ = '\n';
537*4882a593Smuzhiyun *dp = '\0';
538*4882a593Smuzhiyun }
539*4882a593Smuzhiyun }
540*4882a593Smuzhiyun
bm_get_inode(struct super_block * sb,int mode)541*4882a593Smuzhiyun static struct inode *bm_get_inode(struct super_block *sb, int mode)
542*4882a593Smuzhiyun {
543*4882a593Smuzhiyun struct inode *inode = new_inode(sb);
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun if (inode) {
546*4882a593Smuzhiyun inode->i_ino = get_next_ino();
547*4882a593Smuzhiyun inode->i_mode = mode;
548*4882a593Smuzhiyun inode->i_atime = inode->i_mtime = inode->i_ctime =
549*4882a593Smuzhiyun current_time(inode);
550*4882a593Smuzhiyun }
551*4882a593Smuzhiyun return inode;
552*4882a593Smuzhiyun }
553*4882a593Smuzhiyun
bm_evict_inode(struct inode * inode)554*4882a593Smuzhiyun static void bm_evict_inode(struct inode *inode)
555*4882a593Smuzhiyun {
556*4882a593Smuzhiyun Node *e = inode->i_private;
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun if (e && e->flags & MISC_FMT_OPEN_FILE)
559*4882a593Smuzhiyun filp_close(e->interp_file, NULL);
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun clear_inode(inode);
562*4882a593Smuzhiyun kfree(e);
563*4882a593Smuzhiyun }
564*4882a593Smuzhiyun
kill_node(Node * e)565*4882a593Smuzhiyun static void kill_node(Node *e)
566*4882a593Smuzhiyun {
567*4882a593Smuzhiyun struct dentry *dentry;
568*4882a593Smuzhiyun
569*4882a593Smuzhiyun write_lock(&entries_lock);
570*4882a593Smuzhiyun list_del_init(&e->list);
571*4882a593Smuzhiyun write_unlock(&entries_lock);
572*4882a593Smuzhiyun
573*4882a593Smuzhiyun dentry = e->dentry;
574*4882a593Smuzhiyun drop_nlink(d_inode(dentry));
575*4882a593Smuzhiyun d_drop(dentry);
576*4882a593Smuzhiyun dput(dentry);
577*4882a593Smuzhiyun simple_release_fs(&bm_mnt, &entry_count);
578*4882a593Smuzhiyun }
579*4882a593Smuzhiyun
580*4882a593Smuzhiyun /* /<entry> */
581*4882a593Smuzhiyun
582*4882a593Smuzhiyun static ssize_t
bm_entry_read(struct file * file,char __user * buf,size_t nbytes,loff_t * ppos)583*4882a593Smuzhiyun bm_entry_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
584*4882a593Smuzhiyun {
585*4882a593Smuzhiyun Node *e = file_inode(file)->i_private;
586*4882a593Smuzhiyun ssize_t res;
587*4882a593Smuzhiyun char *page;
588*4882a593Smuzhiyun
589*4882a593Smuzhiyun page = (char *) __get_free_page(GFP_KERNEL);
590*4882a593Smuzhiyun if (!page)
591*4882a593Smuzhiyun return -ENOMEM;
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun entry_status(e, page);
594*4882a593Smuzhiyun
595*4882a593Smuzhiyun res = simple_read_from_buffer(buf, nbytes, ppos, page, strlen(page));
596*4882a593Smuzhiyun
597*4882a593Smuzhiyun free_page((unsigned long) page);
598*4882a593Smuzhiyun return res;
599*4882a593Smuzhiyun }
600*4882a593Smuzhiyun
bm_entry_write(struct file * file,const char __user * buffer,size_t count,loff_t * ppos)601*4882a593Smuzhiyun static ssize_t bm_entry_write(struct file *file, const char __user *buffer,
602*4882a593Smuzhiyun size_t count, loff_t *ppos)
603*4882a593Smuzhiyun {
604*4882a593Smuzhiyun struct dentry *root;
605*4882a593Smuzhiyun Node *e = file_inode(file)->i_private;
606*4882a593Smuzhiyun int res = parse_command(buffer, count);
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun switch (res) {
609*4882a593Smuzhiyun case 1:
610*4882a593Smuzhiyun /* Disable this handler. */
611*4882a593Smuzhiyun clear_bit(Enabled, &e->flags);
612*4882a593Smuzhiyun break;
613*4882a593Smuzhiyun case 2:
614*4882a593Smuzhiyun /* Enable this handler. */
615*4882a593Smuzhiyun set_bit(Enabled, &e->flags);
616*4882a593Smuzhiyun break;
617*4882a593Smuzhiyun case 3:
618*4882a593Smuzhiyun /* Delete this handler. */
619*4882a593Smuzhiyun root = file_inode(file)->i_sb->s_root;
620*4882a593Smuzhiyun inode_lock(d_inode(root));
621*4882a593Smuzhiyun
622*4882a593Smuzhiyun if (!list_empty(&e->list))
623*4882a593Smuzhiyun kill_node(e);
624*4882a593Smuzhiyun
625*4882a593Smuzhiyun inode_unlock(d_inode(root));
626*4882a593Smuzhiyun break;
627*4882a593Smuzhiyun default:
628*4882a593Smuzhiyun return res;
629*4882a593Smuzhiyun }
630*4882a593Smuzhiyun
631*4882a593Smuzhiyun return count;
632*4882a593Smuzhiyun }
633*4882a593Smuzhiyun
634*4882a593Smuzhiyun static const struct file_operations bm_entry_operations = {
635*4882a593Smuzhiyun .read = bm_entry_read,
636*4882a593Smuzhiyun .write = bm_entry_write,
637*4882a593Smuzhiyun .llseek = default_llseek,
638*4882a593Smuzhiyun };
639*4882a593Smuzhiyun
640*4882a593Smuzhiyun /* /register */
641*4882a593Smuzhiyun
bm_register_write(struct file * file,const char __user * buffer,size_t count,loff_t * ppos)642*4882a593Smuzhiyun static ssize_t bm_register_write(struct file *file, const char __user *buffer,
643*4882a593Smuzhiyun size_t count, loff_t *ppos)
644*4882a593Smuzhiyun {
645*4882a593Smuzhiyun Node *e;
646*4882a593Smuzhiyun struct inode *inode;
647*4882a593Smuzhiyun struct super_block *sb = file_inode(file)->i_sb;
648*4882a593Smuzhiyun struct dentry *root = sb->s_root, *dentry;
649*4882a593Smuzhiyun int err = 0;
650*4882a593Smuzhiyun struct file *f = NULL;
651*4882a593Smuzhiyun
652*4882a593Smuzhiyun e = create_entry(buffer, count);
653*4882a593Smuzhiyun
654*4882a593Smuzhiyun if (IS_ERR(e))
655*4882a593Smuzhiyun return PTR_ERR(e);
656*4882a593Smuzhiyun
657*4882a593Smuzhiyun if (e->flags & MISC_FMT_OPEN_FILE) {
658*4882a593Smuzhiyun f = open_exec(e->interpreter);
659*4882a593Smuzhiyun if (IS_ERR(f)) {
660*4882a593Smuzhiyun pr_notice("register: failed to install interpreter file %s\n",
661*4882a593Smuzhiyun e->interpreter);
662*4882a593Smuzhiyun kfree(e);
663*4882a593Smuzhiyun return PTR_ERR(f);
664*4882a593Smuzhiyun }
665*4882a593Smuzhiyun e->interp_file = f;
666*4882a593Smuzhiyun }
667*4882a593Smuzhiyun
668*4882a593Smuzhiyun inode_lock(d_inode(root));
669*4882a593Smuzhiyun dentry = lookup_one_len(e->name, root, strlen(e->name));
670*4882a593Smuzhiyun err = PTR_ERR(dentry);
671*4882a593Smuzhiyun if (IS_ERR(dentry))
672*4882a593Smuzhiyun goto out;
673*4882a593Smuzhiyun
674*4882a593Smuzhiyun err = -EEXIST;
675*4882a593Smuzhiyun if (d_really_is_positive(dentry))
676*4882a593Smuzhiyun goto out2;
677*4882a593Smuzhiyun
678*4882a593Smuzhiyun inode = bm_get_inode(sb, S_IFREG | 0644);
679*4882a593Smuzhiyun
680*4882a593Smuzhiyun err = -ENOMEM;
681*4882a593Smuzhiyun if (!inode)
682*4882a593Smuzhiyun goto out2;
683*4882a593Smuzhiyun
684*4882a593Smuzhiyun err = simple_pin_fs(&bm_fs_type, &bm_mnt, &entry_count);
685*4882a593Smuzhiyun if (err) {
686*4882a593Smuzhiyun iput(inode);
687*4882a593Smuzhiyun inode = NULL;
688*4882a593Smuzhiyun goto out2;
689*4882a593Smuzhiyun }
690*4882a593Smuzhiyun
691*4882a593Smuzhiyun e->dentry = dget(dentry);
692*4882a593Smuzhiyun inode->i_private = e;
693*4882a593Smuzhiyun inode->i_fop = &bm_entry_operations;
694*4882a593Smuzhiyun
695*4882a593Smuzhiyun d_instantiate(dentry, inode);
696*4882a593Smuzhiyun write_lock(&entries_lock);
697*4882a593Smuzhiyun list_add(&e->list, &entries);
698*4882a593Smuzhiyun write_unlock(&entries_lock);
699*4882a593Smuzhiyun
700*4882a593Smuzhiyun err = 0;
701*4882a593Smuzhiyun out2:
702*4882a593Smuzhiyun dput(dentry);
703*4882a593Smuzhiyun out:
704*4882a593Smuzhiyun inode_unlock(d_inode(root));
705*4882a593Smuzhiyun
706*4882a593Smuzhiyun if (err) {
707*4882a593Smuzhiyun if (f)
708*4882a593Smuzhiyun filp_close(f, NULL);
709*4882a593Smuzhiyun kfree(e);
710*4882a593Smuzhiyun return err;
711*4882a593Smuzhiyun }
712*4882a593Smuzhiyun return count;
713*4882a593Smuzhiyun }
714*4882a593Smuzhiyun
715*4882a593Smuzhiyun static const struct file_operations bm_register_operations = {
716*4882a593Smuzhiyun .write = bm_register_write,
717*4882a593Smuzhiyun .llseek = noop_llseek,
718*4882a593Smuzhiyun };
719*4882a593Smuzhiyun
720*4882a593Smuzhiyun /* /status */
721*4882a593Smuzhiyun
722*4882a593Smuzhiyun static ssize_t
bm_status_read(struct file * file,char __user * buf,size_t nbytes,loff_t * ppos)723*4882a593Smuzhiyun bm_status_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
724*4882a593Smuzhiyun {
725*4882a593Smuzhiyun char *s = enabled ? "enabled\n" : "disabled\n";
726*4882a593Smuzhiyun
727*4882a593Smuzhiyun return simple_read_from_buffer(buf, nbytes, ppos, s, strlen(s));
728*4882a593Smuzhiyun }
729*4882a593Smuzhiyun
bm_status_write(struct file * file,const char __user * buffer,size_t count,loff_t * ppos)730*4882a593Smuzhiyun static ssize_t bm_status_write(struct file *file, const char __user *buffer,
731*4882a593Smuzhiyun size_t count, loff_t *ppos)
732*4882a593Smuzhiyun {
733*4882a593Smuzhiyun int res = parse_command(buffer, count);
734*4882a593Smuzhiyun struct dentry *root;
735*4882a593Smuzhiyun
736*4882a593Smuzhiyun switch (res) {
737*4882a593Smuzhiyun case 1:
738*4882a593Smuzhiyun /* Disable all handlers. */
739*4882a593Smuzhiyun enabled = 0;
740*4882a593Smuzhiyun break;
741*4882a593Smuzhiyun case 2:
742*4882a593Smuzhiyun /* Enable all handlers. */
743*4882a593Smuzhiyun enabled = 1;
744*4882a593Smuzhiyun break;
745*4882a593Smuzhiyun case 3:
746*4882a593Smuzhiyun /* Delete all handlers. */
747*4882a593Smuzhiyun root = file_inode(file)->i_sb->s_root;
748*4882a593Smuzhiyun inode_lock(d_inode(root));
749*4882a593Smuzhiyun
750*4882a593Smuzhiyun while (!list_empty(&entries))
751*4882a593Smuzhiyun kill_node(list_first_entry(&entries, Node, list));
752*4882a593Smuzhiyun
753*4882a593Smuzhiyun inode_unlock(d_inode(root));
754*4882a593Smuzhiyun break;
755*4882a593Smuzhiyun default:
756*4882a593Smuzhiyun return res;
757*4882a593Smuzhiyun }
758*4882a593Smuzhiyun
759*4882a593Smuzhiyun return count;
760*4882a593Smuzhiyun }
761*4882a593Smuzhiyun
762*4882a593Smuzhiyun static const struct file_operations bm_status_operations = {
763*4882a593Smuzhiyun .read = bm_status_read,
764*4882a593Smuzhiyun .write = bm_status_write,
765*4882a593Smuzhiyun .llseek = default_llseek,
766*4882a593Smuzhiyun };
767*4882a593Smuzhiyun
768*4882a593Smuzhiyun /* Superblock handling */
769*4882a593Smuzhiyun
770*4882a593Smuzhiyun static const struct super_operations s_ops = {
771*4882a593Smuzhiyun .statfs = simple_statfs,
772*4882a593Smuzhiyun .evict_inode = bm_evict_inode,
773*4882a593Smuzhiyun };
774*4882a593Smuzhiyun
bm_fill_super(struct super_block * sb,struct fs_context * fc)775*4882a593Smuzhiyun static int bm_fill_super(struct super_block *sb, struct fs_context *fc)
776*4882a593Smuzhiyun {
777*4882a593Smuzhiyun int err;
778*4882a593Smuzhiyun static const struct tree_descr bm_files[] = {
779*4882a593Smuzhiyun [2] = {"status", &bm_status_operations, S_IWUSR|S_IRUGO},
780*4882a593Smuzhiyun [3] = {"register", &bm_register_operations, S_IWUSR},
781*4882a593Smuzhiyun /* last one */ {""}
782*4882a593Smuzhiyun };
783*4882a593Smuzhiyun
784*4882a593Smuzhiyun err = simple_fill_super(sb, BINFMTFS_MAGIC, bm_files);
785*4882a593Smuzhiyun if (!err)
786*4882a593Smuzhiyun sb->s_op = &s_ops;
787*4882a593Smuzhiyun return err;
788*4882a593Smuzhiyun }
789*4882a593Smuzhiyun
bm_get_tree(struct fs_context * fc)790*4882a593Smuzhiyun static int bm_get_tree(struct fs_context *fc)
791*4882a593Smuzhiyun {
792*4882a593Smuzhiyun return get_tree_single(fc, bm_fill_super);
793*4882a593Smuzhiyun }
794*4882a593Smuzhiyun
795*4882a593Smuzhiyun static const struct fs_context_operations bm_context_ops = {
796*4882a593Smuzhiyun .get_tree = bm_get_tree,
797*4882a593Smuzhiyun };
798*4882a593Smuzhiyun
bm_init_fs_context(struct fs_context * fc)799*4882a593Smuzhiyun static int bm_init_fs_context(struct fs_context *fc)
800*4882a593Smuzhiyun {
801*4882a593Smuzhiyun fc->ops = &bm_context_ops;
802*4882a593Smuzhiyun return 0;
803*4882a593Smuzhiyun }
804*4882a593Smuzhiyun
805*4882a593Smuzhiyun static struct linux_binfmt misc_format = {
806*4882a593Smuzhiyun .module = THIS_MODULE,
807*4882a593Smuzhiyun .load_binary = load_misc_binary,
808*4882a593Smuzhiyun };
809*4882a593Smuzhiyun
810*4882a593Smuzhiyun static struct file_system_type bm_fs_type = {
811*4882a593Smuzhiyun .owner = THIS_MODULE,
812*4882a593Smuzhiyun .name = "binfmt_misc",
813*4882a593Smuzhiyun .init_fs_context = bm_init_fs_context,
814*4882a593Smuzhiyun .kill_sb = kill_litter_super,
815*4882a593Smuzhiyun };
816*4882a593Smuzhiyun MODULE_ALIAS_FS("binfmt_misc");
817*4882a593Smuzhiyun
init_misc_binfmt(void)818*4882a593Smuzhiyun static int __init init_misc_binfmt(void)
819*4882a593Smuzhiyun {
820*4882a593Smuzhiyun int err = register_filesystem(&bm_fs_type);
821*4882a593Smuzhiyun if (!err)
822*4882a593Smuzhiyun insert_binfmt(&misc_format);
823*4882a593Smuzhiyun return err;
824*4882a593Smuzhiyun }
825*4882a593Smuzhiyun
exit_misc_binfmt(void)826*4882a593Smuzhiyun static void __exit exit_misc_binfmt(void)
827*4882a593Smuzhiyun {
828*4882a593Smuzhiyun unregister_binfmt(&misc_format);
829*4882a593Smuzhiyun unregister_filesystem(&bm_fs_type);
830*4882a593Smuzhiyun }
831*4882a593Smuzhiyun
832*4882a593Smuzhiyun core_initcall(init_misc_binfmt);
833*4882a593Smuzhiyun module_exit(exit_misc_binfmt);
834*4882a593Smuzhiyun MODULE_LICENSE("GPL");
835*4882a593Smuzhiyun MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY);
836