xref: /openbmc/linux/fs/binfmt_misc.c (revision 2276e5ba)
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