Branch data Line data Source code
1 : : /*
2 : : * binfmt_misc.c
3 : : *
4 : : * Copyright (C) 1997 Richard Günther
5 : : *
6 : : * binfmt_misc detects binaries via a magic or filename extension and invokes
7 : : * a specified wrapper. This should obsolete binfmt_java, binfmt_em86 and
8 : : * binfmt_mz.
9 : : *
10 : : * 1997-04-25 first version
11 : : * [...]
12 : : * 1997-05-19 cleanup
13 : : * 1997-06-26 hpa: pass the real filename rather than argv[0]
14 : : * 1997-06-30 minor cleanup
15 : : * 1997-08-09 removed extension stripping, locking cleanup
16 : : * 2001-02-28 AV: rewritten into something that resembles C. Original didn't.
17 : : */
18 : :
19 : : #include <linux/module.h>
20 : : #include <linux/init.h>
21 : : #include <linux/sched.h>
22 : : #include <linux/magic.h>
23 : : #include <linux/binfmts.h>
24 : : #include <linux/slab.h>
25 : : #include <linux/ctype.h>
26 : : #include <linux/string_helpers.h>
27 : : #include <linux/file.h>
28 : : #include <linux/pagemap.h>
29 : : #include <linux/namei.h>
30 : : #include <linux/mount.h>
31 : : #include <linux/syscalls.h>
32 : : #include <linux/fs.h>
33 : :
34 : : #include <asm/uaccess.h>
35 : :
36 : : enum {
37 : : VERBOSE_STATUS = 1 /* make it zero to save 400 bytes kernel memory */
38 : : };
39 : :
40 : : static LIST_HEAD(entries);
41 : : static int enabled = 1;
42 : :
43 : : enum {Enabled, Magic};
44 : : #define MISC_FMT_PRESERVE_ARGV0 (1<<31)
45 : : #define MISC_FMT_OPEN_BINARY (1<<30)
46 : : #define MISC_FMT_CREDENTIALS (1<<29)
47 : :
48 : : typedef struct {
49 : : struct list_head list;
50 : : unsigned long flags; /* type, status, etc. */
51 : : int offset; /* offset of magic */
52 : : int size; /* size of magic/mask */
53 : : char *magic; /* magic or filename extension */
54 : : char *mask; /* mask, NULL for exact match */
55 : : char *interpreter; /* filename of interpreter */
56 : : char *name;
57 : : struct dentry *dentry;
58 : : } Node;
59 : :
60 : : static DEFINE_RWLOCK(entries_lock);
61 : : static struct file_system_type bm_fs_type;
62 : : static struct vfsmount *bm_mnt;
63 : : static int entry_count;
64 : :
65 : : /*
66 : : * Check if we support the binfmt
67 : : * if we do, return the node, else NULL
68 : : * locking is done in load_misc_binary
69 : : */
70 : 0 : static Node *check_file(struct linux_binprm *bprm)
71 : : {
72 : 60177 : char *p = strrchr(bprm->interp, '.');
73 : : struct list_head *l;
74 : :
75 [ - + ]: 60177 : list_for_each(l, &entries) {
76 : : Node *e = list_entry(l, Node, list);
77 : : char *s;
78 : : int j;
79 : :
80 [ # # ]: 0 : if (!test_bit(Enabled, &e->flags))
81 : 0 : continue;
82 : :
83 [ # # ]: 0 : if (!test_bit(Magic, &e->flags)) {
84 [ # # ][ # # ]: 0 : if (p && !strcmp(e->magic, p + 1))
85 : : return e;
86 : 0 : continue;
87 : : }
88 : :
89 : 0 : s = bprm->buf + e->offset;
90 [ # # ]: 0 : if (e->mask) {
91 [ # # ]: 0 : for (j = 0; j < e->size; j++)
92 [ # # ]: 0 : if ((*s++ ^ e->magic[j]) & e->mask[j])
93 : : break;
94 : : } else {
95 [ # # ]: 0 : for (j = 0; j < e->size; j++)
96 [ # # ]: 0 : if ((*s++ ^ e->magic[j]))
97 : : break;
98 : : }
99 [ # # ]: 0 : if (j == e->size)
100 : : return e;
101 : : }
102 : : return NULL;
103 : : }
104 : :
105 : : /*
106 : : * the loader itself
107 : : */
108 : 0 : static int load_misc_binary(struct linux_binprm *bprm)
109 : : {
110 : : Node *fmt;
111 : : struct file * interp_file = NULL;
112 : : char iname[BINPRM_BUF_SIZE];
113 : 60171 : const char *iname_addr = iname;
114 : : int retval;
115 : : int fd_binary = -1;
116 : :
117 : : retval = -ENOEXEC;
118 [ + ]: 60171 : if (!enabled)
119 : : goto _ret;
120 : :
121 : : /* to keep locking time low, we copy the interpreter string */
122 : 60176 : read_lock(&entries_lock);
123 : 60152 : fmt = check_file(bprm);
124 [ - + ]: 60177 : if (fmt)
125 : 0 : strlcpy(iname, fmt->interpreter, BINPRM_BUF_SIZE);
126 : : read_unlock(&entries_lock);
127 [ - + ]: 60177 : if (!fmt)
128 : : goto _ret;
129 : :
130 [ # # ]: 0 : if (!(fmt->flags & MISC_FMT_PRESERVE_ARGV0)) {
131 : 0 : retval = remove_arg_zero(bprm);
132 [ # # ]: 0 : if (retval)
133 : : goto _ret;
134 : : }
135 : :
136 [ # # ]: 0 : if (fmt->flags & MISC_FMT_OPEN_BINARY) {
137 : :
138 : : /* if the binary should be opened on behalf of the
139 : : * interpreter than keep it open and assign descriptor
140 : : * to it */
141 : 0 : fd_binary = get_unused_fd();
142 [ # # ]: 0 : if (fd_binary < 0) {
143 : : retval = fd_binary;
144 : : goto _ret;
145 : : }
146 : 0 : fd_install(fd_binary, bprm->file);
147 : :
148 : : /* if the binary is not readable than enforce mm->dumpable=0
149 : : regardless of the interpreter's permissions */
150 : 0 : would_dump(bprm, bprm->file);
151 : :
152 : 0 : allow_write_access(bprm->file);
153 : 0 : bprm->file = NULL;
154 : :
155 : : /* mark the bprm that fd should be passed to interp */
156 : 0 : bprm->interp_flags |= BINPRM_FLAGS_EXECFD;
157 : 0 : bprm->interp_data = fd_binary;
158 : :
159 : : } else {
160 : 0 : allow_write_access(bprm->file);
161 : 0 : fput(bprm->file);
162 : 0 : bprm->file = NULL;
163 : : }
164 : : /* make argv[1] be the path to the binary */
165 : 0 : retval = copy_strings_kernel (1, &bprm->interp, bprm);
166 [ # # ]: 0 : if (retval < 0)
167 : : goto _error;
168 : 0 : bprm->argc++;
169 : :
170 : : /* add the interp as argv[0] */
171 : 0 : retval = copy_strings_kernel (1, &iname_addr, bprm);
172 [ # # ]: 0 : if (retval < 0)
173 : : goto _error;
174 : 0 : bprm->argc ++;
175 : :
176 : : /* Update interp in case binfmt_script needs it. */
177 : 0 : retval = bprm_change_interp(iname, bprm);
178 [ # # ]: 0 : if (retval < 0)
179 : : goto _error;
180 : :
181 : 0 : interp_file = open_exec (iname);
182 : : retval = PTR_ERR (interp_file);
183 [ # # ]: 0 : if (IS_ERR (interp_file))
184 : : goto _error;
185 : :
186 : 0 : bprm->file = interp_file;
187 [ # # ]: 0 : if (fmt->flags & MISC_FMT_CREDENTIALS) {
188 : : /*
189 : : * No need to call prepare_binprm(), it's already been
190 : : * done. bprm->buf is stale, update from interp_file.
191 : : */
192 : 0 : memset(bprm->buf, 0, BINPRM_BUF_SIZE);
193 : 0 : retval = kernel_read(bprm->file, 0, bprm->buf, BINPRM_BUF_SIZE);
194 : : } else
195 : 0 : retval = prepare_binprm (bprm);
196 : :
197 [ # # ]: 60171 : if (retval < 0)
198 : : goto _error;
199 : :
200 : 0 : retval = search_binary_handler(bprm);
201 [ # # ]: 0 : if (retval < 0)
202 : : goto _error;
203 : :
204 : : _ret:
205 : 60172 : return retval;
206 : : _error:
207 [ # # ]: 0 : if (fd_binary > 0)
208 : 0 : sys_close(fd_binary);
209 : 0 : bprm->interp_flags = 0;
210 : 0 : bprm->interp_data = 0;
211 : 0 : goto _ret;
212 : : }
213 : :
214 : : /* Command parsers */
215 : :
216 : : /*
217 : : * parses and copies one argument enclosed in del from *sp to *dp,
218 : : * recognising the \x special.
219 : : * returns pointer to the copied argument or NULL in case of an
220 : : * error (and sets err) or null argument length.
221 : : */
222 : 0 : static char *scanarg(char *s, char del)
223 : : {
224 : : char c;
225 : :
226 [ # # ]: 0 : while ((c = *s++) != del) {
227 [ # # ][ # # ]: 0 : if (c == '\\' && *s == 'x') {
228 : : s++;
229 [ # # ]: 0 : if (!isxdigit(*s++))
230 : : return NULL;
231 [ # # ]: 0 : if (!isxdigit(*s++))
232 : : return NULL;
233 : : }
234 : : }
235 : : return s;
236 : : }
237 : :
238 : 0 : static char * check_special_flags (char * sfs, Node * e)
239 : : {
240 : : char * p = sfs;
241 : : int cont = 1;
242 : :
243 : : /* special flags */
244 [ # # ]: 0 : while (cont) {
245 [ # # # # ]: 0 : switch (*p) {
246 : : case 'P':
247 : 0 : p++;
248 : 0 : e->flags |= MISC_FMT_PRESERVE_ARGV0;
249 : : break;
250 : : case 'O':
251 : 0 : p++;
252 : 0 : e->flags |= MISC_FMT_OPEN_BINARY;
253 : : break;
254 : : case 'C':
255 : 0 : p++;
256 : : /* this flags also implies the
257 : : open-binary flag */
258 : 0 : e->flags |= (MISC_FMT_CREDENTIALS |
259 : : MISC_FMT_OPEN_BINARY);
260 : : break;
261 : : default:
262 : : cont = 0;
263 : : }
264 : : }
265 : :
266 : 0 : return p;
267 : : }
268 : : /*
269 : : * This registers a new binary format, it recognises the syntax
270 : : * ':name:type:offset:magic:mask:interpreter:flags'
271 : : * where the ':' is the IFS, that can be chosen with the first char
272 : : */
273 : 0 : static Node *create_entry(const char __user *buffer, size_t count)
274 : : {
275 : : Node *e;
276 : : int memsize, err;
277 : : char *buf, *p;
278 : : char del;
279 : :
280 : : /* some sanity checks */
281 : : err = -EINVAL;
282 [ # # ]: 0 : if ((count < 11) || (count > 256))
283 : : goto out;
284 : :
285 : : err = -ENOMEM;
286 : 0 : memsize = sizeof(Node) + count + 8;
287 : : e = kmalloc(memsize, GFP_USER);
288 [ # # ]: 0 : if (!e)
289 : : goto out;
290 : :
291 : 0 : p = buf = (char *)e + sizeof(Node);
292 : :
293 : 0 : memset(e, 0, sizeof(Node));
294 [ # # ]: 0 : if (copy_from_user(buf, buffer, count))
295 : : goto Efault;
296 : :
297 : 0 : del = *p++; /* delimeter */
298 : :
299 [ # # ][ # # ]: 0 : memset(buf+count, del, 8);
300 : :
301 : 0 : e->name = p;
302 : 0 : p = strchr(p, del);
303 [ # # ]: 0 : if (!p)
304 : : goto Einval;
305 : 0 : *p++ = '\0';
306 [ # # ][ # # ]: 0 : if (!e->name[0] ||
307 [ # # ]: 0 : !strcmp(e->name, ".") ||
308 [ # # ]: 0 : !strcmp(e->name, "..") ||
309 : 0 : strchr(e->name, '/'))
310 : : goto Einval;
311 [ # # # ]: 0 : switch (*p++) {
312 : 0 : case 'E': e->flags = 1<<Enabled; break;
313 : 0 : case 'M': e->flags = (1<<Enabled) | (1<<Magic); break;
314 : : default: goto Einval;
315 : : }
316 [ # # ]: 0 : if (*p++ != del)
317 : : goto Einval;
318 [ # # ]: 0 : if (test_bit(Magic, &e->flags)) {
319 : 0 : char *s = strchr(p, del);
320 [ # # ]: 0 : if (!s)
321 : : goto Einval;
322 : 0 : *s++ = '\0';
323 : 0 : e->offset = simple_strtoul(p, &p, 10);
324 [ # # ]: 0 : if (*p++)
325 : : goto Einval;
326 : 0 : e->magic = p;
327 : 0 : p = scanarg(p, del);
328 [ # # ]: 0 : if (!p)
329 : : goto Einval;
330 : 0 : p[-1] = '\0';
331 [ # # ]: 0 : if (!e->magic[0])
332 : : goto Einval;
333 : 0 : e->mask = p;
334 : 0 : p = scanarg(p, del);
335 [ # # ]: 0 : if (!p)
336 : : goto Einval;
337 : 0 : p[-1] = '\0';
338 [ # # ]: 0 : if (!e->mask[0])
339 : 0 : e->mask = NULL;
340 : 0 : e->size = string_unescape_inplace(e->magic, UNESCAPE_HEX);
341 [ # # # # ]: 0 : if (e->mask &&
342 : 0 : string_unescape_inplace(e->mask, UNESCAPE_HEX) != e->size)
343 : : goto Einval;
344 [ # # ]: 0 : if (e->size + e->offset > BINPRM_BUF_SIZE)
345 : : goto Einval;
346 : : } else {
347 : 0 : p = strchr(p, del);
348 [ # # ]: 0 : if (!p)
349 : : goto Einval;
350 : 0 : *p++ = '\0';
351 : 0 : e->magic = p;
352 : 0 : p = strchr(p, del);
353 [ # # ]: 0 : if (!p)
354 : : goto Einval;
355 : 0 : *p++ = '\0';
356 [ # # ][ # # ]: 0 : if (!e->magic[0] || strchr(e->magic, '/'))
357 : : goto Einval;
358 : 0 : p = strchr(p, del);
359 [ # # ]: 0 : if (!p)
360 : : goto Einval;
361 : 0 : *p++ = '\0';
362 : : }
363 : 0 : e->interpreter = p;
364 : 0 : p = strchr(p, del);
365 [ # # ]: 0 : if (!p)
366 : : goto Einval;
367 : 0 : *p++ = '\0';
368 [ # # ]: 0 : if (!e->interpreter[0])
369 : : goto Einval;
370 : :
371 : :
372 : 0 : p = check_special_flags (p, e);
373 : :
374 [ # # ]: 0 : if (*p == '\n')
375 : 0 : p++;
376 [ # # ]: 0 : if (p != buf + count)
377 : : goto Einval;
378 : : return e;
379 : :
380 : : out:
381 : 0 : return ERR_PTR(err);
382 : :
383 : : Efault:
384 : 0 : kfree(e);
385 : 0 : return ERR_PTR(-EFAULT);
386 : : Einval:
387 : 0 : kfree(e);
388 : 0 : return ERR_PTR(-EINVAL);
389 : : }
390 : :
391 : : /*
392 : : * Set status of entry/binfmt_misc:
393 : : * '1' enables, '0' disables and '-1' clears entry/binfmt_misc
394 : : */
395 : 0 : static int parse_command(const char __user *buffer, size_t count)
396 : : {
397 : : char s[4];
398 : :
399 [ # # ]: 0 : if (!count)
400 : : return 0;
401 [ # # ]: 0 : if (count > 3)
402 : : return -EINVAL;
403 [ # # ]: 0 : if (copy_from_user(s, buffer, count))
404 : : return -EFAULT;
405 [ # # ]: 0 : if (s[count-1] == '\n')
406 : : count--;
407 [ # # ][ # # ]: 0 : if (count == 1 && s[0] == '0')
408 : : return 1;
409 [ # # ][ # # ]: 0 : if (count == 1 && s[0] == '1')
410 : : return 2;
411 [ # # ][ # # ]: 0 : if (count == 2 && s[0] == '-' && s[1] == '1')
[ # # ]
412 : : return 3;
413 : 0 : return -EINVAL;
414 : : }
415 : :
416 : : /* generic stuff */
417 : :
418 : 0 : static void entry_status(Node *e, char *page)
419 : : {
420 : : char *dp;
421 : : char *status = "disabled";
422 : : const char * flags = "flags: ";
423 : :
424 [ # # ]: 0 : if (test_bit(Enabled, &e->flags))
425 : : status = "enabled";
426 : :
427 : : if (!VERBOSE_STATUS) {
428 : : sprintf(page, "%s\n", status);
429 : 0 : return;
430 : : }
431 : :
432 : 0 : sprintf(page, "%s\ninterpreter %s\n", status, e->interpreter);
433 : 0 : dp = page + strlen(page);
434 : :
435 : : /* print the special flags */
436 : 0 : sprintf (dp, "%s", flags);
437 : 0 : dp += strlen (flags);
438 [ # # ]: 0 : if (e->flags & MISC_FMT_PRESERVE_ARGV0) {
439 : 0 : *dp ++ = 'P';
440 : : }
441 [ # # ]: 0 : if (e->flags & MISC_FMT_OPEN_BINARY) {
442 : 0 : *dp ++ = 'O';
443 : : }
444 [ # # ]: 0 : if (e->flags & MISC_FMT_CREDENTIALS) {
445 : 0 : *dp ++ = 'C';
446 : : }
447 : 0 : *dp ++ = '\n';
448 : :
449 : :
450 [ # # ]: 0 : if (!test_bit(Magic, &e->flags)) {
451 : 0 : sprintf(dp, "extension .%s\n", e->magic);
452 : : } else {
453 : : int i;
454 : :
455 : 0 : sprintf(dp, "offset %i\nmagic ", e->offset);
456 : 0 : dp = page + strlen(page);
457 [ # # ]: 0 : for (i = 0; i < e->size; i++) {
458 : 0 : sprintf(dp, "%02x", 0xff & (int) (e->magic[i]));
459 : 0 : dp += 2;
460 : : }
461 [ # # ]: 0 : if (e->mask) {
462 : 0 : sprintf(dp, "\nmask ");
463 : 0 : dp += 6;
464 [ # # ]: 0 : for (i = 0; i < e->size; i++) {
465 : 0 : sprintf(dp, "%02x", 0xff & (int) (e->mask[i]));
466 : 0 : dp += 2;
467 : : }
468 : : }
469 : 0 : *dp++ = '\n';
470 : 0 : *dp = '\0';
471 : : }
472 : : }
473 : :
474 : 0 : static struct inode *bm_get_inode(struct super_block *sb, int mode)
475 : : {
476 : 0 : struct inode * inode = new_inode(sb);
477 : :
478 [ # # ]: 0 : if (inode) {
479 : 0 : inode->i_ino = get_next_ino();
480 : 0 : inode->i_mode = mode;
481 : 0 : inode->i_atime = inode->i_mtime = inode->i_ctime =
482 : 0 : current_fs_time(inode->i_sb);
483 : : }
484 : 0 : return inode;
485 : : }
486 : :
487 : 0 : static void bm_evict_inode(struct inode *inode)
488 : : {
489 : 0 : clear_inode(inode);
490 : 0 : kfree(inode->i_private);
491 : 0 : }
492 : :
493 : 0 : static void kill_node(Node *e)
494 : : {
495 : : struct dentry *dentry;
496 : :
497 : 0 : write_lock(&entries_lock);
498 : 0 : dentry = e->dentry;
499 [ # # ]: 0 : if (dentry) {
500 : 0 : list_del_init(&e->list);
501 : 0 : e->dentry = NULL;
502 : : }
503 : : write_unlock(&entries_lock);
504 : :
505 [ # # ]: 0 : if (dentry) {
506 : 0 : drop_nlink(dentry->d_inode);
507 : 0 : d_drop(dentry);
508 : 0 : dput(dentry);
509 : 0 : simple_release_fs(&bm_mnt, &entry_count);
510 : : }
511 : 0 : }
512 : :
513 : : /* /<entry> */
514 : :
515 : : static ssize_t
516 : 0 : bm_entry_read(struct file * file, char __user * buf, size_t nbytes, loff_t *ppos)
517 : : {
518 : 0 : Node *e = file_inode(file)->i_private;
519 : : ssize_t res;
520 : : char *page;
521 : :
522 [ # # ]: 0 : if (!(page = (char*) __get_free_page(GFP_KERNEL)))
523 : : return -ENOMEM;
524 : :
525 : 0 : entry_status(e, page);
526 : :
527 : 0 : res = simple_read_from_buffer(buf, nbytes, ppos, page, strlen(page));
528 : :
529 : 0 : free_page((unsigned long) page);
530 : 0 : return res;
531 : : }
532 : :
533 : 0 : static ssize_t bm_entry_write(struct file *file, const char __user *buffer,
534 : : size_t count, loff_t *ppos)
535 : : {
536 : : struct dentry *root;
537 : 0 : Node *e = file_inode(file)->i_private;
538 : 0 : int res = parse_command(buffer, count);
539 : :
540 [ # # # # ]: 0 : switch (res) {
541 : 0 : case 1: clear_bit(Enabled, &e->flags);
542 : 0 : break;
543 : 0 : case 2: set_bit(Enabled, &e->flags);
544 : 0 : break;
545 : 0 : case 3: root = dget(file->f_path.dentry->d_sb->s_root);
546 : 0 : mutex_lock(&root->d_inode->i_mutex);
547 : :
548 : 0 : kill_node(e);
549 : :
550 : 0 : mutex_unlock(&root->d_inode->i_mutex);
551 : 0 : dput(root);
552 : 0 : break;
553 : : default: return res;
554 : : }
555 : 0 : return count;
556 : : }
557 : :
558 : : static const struct file_operations bm_entry_operations = {
559 : : .read = bm_entry_read,
560 : : .write = bm_entry_write,
561 : : .llseek = default_llseek,
562 : : };
563 : :
564 : : /* /register */
565 : :
566 : 0 : static ssize_t bm_register_write(struct file *file, const char __user *buffer,
567 : : size_t count, loff_t *ppos)
568 : : {
569 : : Node *e;
570 : : struct inode *inode;
571 : : struct dentry *root, *dentry;
572 : 0 : struct super_block *sb = file->f_path.dentry->d_sb;
573 : : int err = 0;
574 : :
575 : 0 : e = create_entry(buffer, count);
576 : :
577 [ # # ]: 0 : if (IS_ERR(e))
578 : 0 : return PTR_ERR(e);
579 : :
580 : 0 : root = dget(sb->s_root);
581 : 0 : mutex_lock(&root->d_inode->i_mutex);
582 : 0 : dentry = lookup_one_len(e->name, root, strlen(e->name));
583 : : err = PTR_ERR(dentry);
584 [ # # ]: 0 : if (IS_ERR(dentry))
585 : : goto out;
586 : :
587 : : err = -EEXIST;
588 [ # # ]: 0 : if (dentry->d_inode)
589 : : goto out2;
590 : :
591 : 0 : inode = bm_get_inode(sb, S_IFREG | 0644);
592 : :
593 : : err = -ENOMEM;
594 [ # # ]: 0 : if (!inode)
595 : : goto out2;
596 : :
597 : 0 : err = simple_pin_fs(&bm_fs_type, &bm_mnt, &entry_count);
598 [ # # ]: 0 : if (err) {
599 : 0 : iput(inode);
600 : : inode = NULL;
601 : 0 : goto out2;
602 : : }
603 : :
604 : 0 : e->dentry = dget(dentry);
605 : 0 : inode->i_private = e;
606 : 0 : inode->i_fop = &bm_entry_operations;
607 : :
608 : 0 : d_instantiate(dentry, inode);
609 : 0 : write_lock(&entries_lock);
610 : 0 : list_add(&e->list, &entries);
611 : : write_unlock(&entries_lock);
612 : :
613 : : err = 0;
614 : : out2:
615 : 0 : dput(dentry);
616 : : out:
617 : 0 : mutex_unlock(&root->d_inode->i_mutex);
618 : 0 : dput(root);
619 : :
620 [ # # ]: 0 : if (err) {
621 : 0 : kfree(e);
622 : 0 : return -EINVAL;
623 : : }
624 : 0 : return count;
625 : : }
626 : :
627 : : static const struct file_operations bm_register_operations = {
628 : : .write = bm_register_write,
629 : : .llseek = noop_llseek,
630 : : };
631 : :
632 : : /* /status */
633 : :
634 : : static ssize_t
635 : 0 : bm_status_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
636 : : {
637 [ - + ]: 2 : char *s = enabled ? "enabled\n" : "disabled\n";
638 : :
639 : 2 : return simple_read_from_buffer(buf, nbytes, ppos, s, strlen(s));
640 : : }
641 : :
642 : 0 : static ssize_t bm_status_write(struct file * file, const char __user * buffer,
643 : : size_t count, loff_t *ppos)
644 : : {
645 : 0 : int res = parse_command(buffer, count);
646 : : struct dentry *root;
647 : :
648 [ # # # # ]: 0 : switch (res) {
649 : 0 : case 1: enabled = 0; break;
650 : 0 : case 2: enabled = 1; break;
651 : 0 : case 3: root = dget(file->f_path.dentry->d_sb->s_root);
652 : 0 : mutex_lock(&root->d_inode->i_mutex);
653 : :
654 [ # # ]: 0 : while (!list_empty(&entries))
655 : 0 : kill_node(list_entry(entries.next, Node, list));
656 : :
657 : 0 : mutex_unlock(&root->d_inode->i_mutex);
658 : 0 : dput(root);
659 : 0 : default: return res;
660 : : }
661 : 0 : return count;
662 : : }
663 : :
664 : : static const struct file_operations bm_status_operations = {
665 : : .read = bm_status_read,
666 : : .write = bm_status_write,
667 : : .llseek = default_llseek,
668 : : };
669 : :
670 : : /* Superblock handling */
671 : :
672 : : static const struct super_operations s_ops = {
673 : : .statfs = simple_statfs,
674 : : .evict_inode = bm_evict_inode,
675 : : };
676 : :
677 : 0 : static int bm_fill_super(struct super_block * sb, void * data, int silent)
678 : : {
679 : : static struct tree_descr bm_files[] = {
680 : : [2] = {"status", &bm_status_operations, S_IWUSR|S_IRUGO},
681 : : [3] = {"register", &bm_register_operations, S_IWUSR},
682 : : /* last one */ {""}
683 : : };
684 : 0 : int err = simple_fill_super(sb, BINFMTFS_MAGIC, bm_files);
685 [ # # ]: 0 : if (!err)
686 : 0 : sb->s_op = &s_ops;
687 : 0 : return err;
688 : : }
689 : :
690 : 0 : static struct dentry *bm_mount(struct file_system_type *fs_type,
691 : : int flags, const char *dev_name, void *data)
692 : : {
693 : 0 : return mount_single(fs_type, flags, data, bm_fill_super);
694 : : }
695 : :
696 : : static struct linux_binfmt misc_format = {
697 : : .module = THIS_MODULE,
698 : : .load_binary = load_misc_binary,
699 : : };
700 : :
701 : : static struct file_system_type bm_fs_type = {
702 : : .owner = THIS_MODULE,
703 : : .name = "binfmt_misc",
704 : : .mount = bm_mount,
705 : : .kill_sb = kill_litter_super,
706 : : };
707 : : MODULE_ALIAS_FS("binfmt_misc");
708 : :
709 : 0 : static int __init init_misc_binfmt(void)
710 : : {
711 : 0 : int err = register_filesystem(&bm_fs_type);
712 [ # # ]: 0 : if (!err)
713 : : insert_binfmt(&misc_format);
714 : 0 : return err;
715 : : }
716 : :
717 : 0 : static void __exit exit_misc_binfmt(void)
718 : : {
719 : 0 : unregister_binfmt(&misc_format);
720 : 0 : unregister_filesystem(&bm_fs_type);
721 : 0 : }
722 : :
723 : : core_initcall(init_misc_binfmt);
724 : : module_exit(exit_misc_binfmt);
725 : : MODULE_LICENSE("GPL");
|