diff options
-rw-r--r-- | fs/binfmt_misc.c | 136 |
1 files changed, 121 insertions, 15 deletions
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index 1cc5377ba955..d87ddc7c4b14 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c | |||
@@ -16,6 +16,8 @@ | |||
16 | * 2001-02-28 AV: rewritten into something that resembles C. Original didn't. | 16 | * 2001-02-28 AV: rewritten into something that resembles C. Original didn't. |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
20 | |||
19 | #include <linux/module.h> | 21 | #include <linux/module.h> |
20 | #include <linux/init.h> | 22 | #include <linux/init.h> |
21 | #include <linux/sched.h> | 23 | #include <linux/sched.h> |
@@ -30,8 +32,13 @@ | |||
30 | #include <linux/mount.h> | 32 | #include <linux/mount.h> |
31 | #include <linux/syscalls.h> | 33 | #include <linux/syscalls.h> |
32 | #include <linux/fs.h> | 34 | #include <linux/fs.h> |
35 | #include <linux/uaccess.h> | ||
33 | 36 | ||
34 | #include <asm/uaccess.h> | 37 | #ifdef DEBUG |
38 | # define USE_DEBUG 1 | ||
39 | #else | ||
40 | # define USE_DEBUG 0 | ||
41 | #endif | ||
35 | 42 | ||
36 | enum { | 43 | enum { |
37 | VERBOSE_STATUS = 1 /* make it zero to save 400 bytes kernel memory */ | 44 | VERBOSE_STATUS = 1 /* make it zero to save 400 bytes kernel memory */ |
@@ -87,20 +94,24 @@ static Node *check_file(struct linux_binprm *bprm) | |||
87 | char *p = strrchr(bprm->interp, '.'); | 94 | char *p = strrchr(bprm->interp, '.'); |
88 | struct list_head *l; | 95 | struct list_head *l; |
89 | 96 | ||
97 | /* Walk all the registered handlers. */ | ||
90 | list_for_each(l, &entries) { | 98 | list_for_each(l, &entries) { |
91 | Node *e = list_entry(l, Node, list); | 99 | Node *e = list_entry(l, Node, list); |
92 | char *s; | 100 | char *s; |
93 | int j; | 101 | int j; |
94 | 102 | ||
103 | /* Make sure this one is currently enabled. */ | ||
95 | if (!test_bit(Enabled, &e->flags)) | 104 | if (!test_bit(Enabled, &e->flags)) |
96 | continue; | 105 | continue; |
97 | 106 | ||
107 | /* Do matching based on extension if applicable. */ | ||
98 | if (!test_bit(Magic, &e->flags)) { | 108 | if (!test_bit(Magic, &e->flags)) { |
99 | if (p && !strcmp(e->magic, p + 1)) | 109 | if (p && !strcmp(e->magic, p + 1)) |
100 | return e; | 110 | return e; |
101 | continue; | 111 | continue; |
102 | } | 112 | } |
103 | 113 | ||
114 | /* Do matching based on magic & mask. */ | ||
104 | s = bprm->buf + e->offset; | 115 | s = bprm->buf + e->offset; |
105 | if (e->mask) { | 116 | if (e->mask) { |
106 | for (j = 0; j < e->size; j++) | 117 | for (j = 0; j < e->size; j++) |
@@ -259,14 +270,17 @@ static char * check_special_flags (char * sfs, Node * e) | |||
259 | while (cont) { | 270 | while (cont) { |
260 | switch (*p) { | 271 | switch (*p) { |
261 | case 'P': | 272 | case 'P': |
273 | pr_debug("register: flag: P (preserve argv0)\n"); | ||
262 | p++; | 274 | p++; |
263 | e->flags |= MISC_FMT_PRESERVE_ARGV0; | 275 | e->flags |= MISC_FMT_PRESERVE_ARGV0; |
264 | break; | 276 | break; |
265 | case 'O': | 277 | case 'O': |
278 | pr_debug("register: flag: O (open binary)\n"); | ||
266 | p++; | 279 | p++; |
267 | e->flags |= MISC_FMT_OPEN_BINARY; | 280 | e->flags |= MISC_FMT_OPEN_BINARY; |
268 | break; | 281 | break; |
269 | case 'C': | 282 | case 'C': |
283 | pr_debug("register: flag: C (preserve creds)\n"); | ||
270 | p++; | 284 | p++; |
271 | /* this flags also implies the | 285 | /* this flags also implies the |
272 | open-binary flag */ | 286 | open-binary flag */ |
@@ -292,6 +306,8 @@ static Node *create_entry(const char __user *buffer, size_t count) | |||
292 | char *buf, *p; | 306 | char *buf, *p; |
293 | char del; | 307 | char del; |
294 | 308 | ||
309 | pr_debug("register: received %zu bytes\n", count); | ||
310 | |||
295 | /* some sanity checks */ | 311 | /* some sanity checks */ |
296 | err = -EINVAL; | 312 | err = -EINVAL; |
297 | if ((count < 11) || (count > MAX_REGISTER_LENGTH)) | 313 | if ((count < 11) || (count > MAX_REGISTER_LENGTH)) |
@@ -311,8 +327,12 @@ static Node *create_entry(const char __user *buffer, size_t count) | |||
311 | 327 | ||
312 | del = *p++; /* delimeter */ | 328 | del = *p++; /* delimeter */ |
313 | 329 | ||
330 | pr_debug("register: delim: %#x {%c}\n", del, del); | ||
331 | |||
332 | /* Pad the buffer with the delim to simplify parsing below. */ | ||
314 | memset(buf+count, del, 8); | 333 | memset(buf+count, del, 8); |
315 | 334 | ||
335 | /* Parse the 'name' field. */ | ||
316 | e->name = p; | 336 | e->name = p; |
317 | p = strchr(p, del); | 337 | p = strchr(p, del); |
318 | if (!p) | 338 | if (!p) |
@@ -323,46 +343,113 @@ static Node *create_entry(const char __user *buffer, size_t count) | |||
323 | !strcmp(e->name, "..") || | 343 | !strcmp(e->name, "..") || |
324 | strchr(e->name, '/')) | 344 | strchr(e->name, '/')) |
325 | goto Einval; | 345 | goto Einval; |
346 | |||
347 | pr_debug("register: name: {%s}\n", e->name); | ||
348 | |||
349 | /* Parse the 'type' field. */ | ||
326 | switch (*p++) { | 350 | switch (*p++) { |
327 | case 'E': e->flags = 1<<Enabled; break; | 351 | case 'E': |
328 | case 'M': e->flags = (1<<Enabled) | (1<<Magic); break; | 352 | pr_debug("register: type: E (extension)\n"); |
329 | default: goto Einval; | 353 | e->flags = 1 << Enabled; |
354 | break; | ||
355 | case 'M': | ||
356 | pr_debug("register: type: M (magic)\n"); | ||
357 | e->flags = (1 << Enabled) | (1 << Magic); | ||
358 | break; | ||
359 | default: | ||
360 | goto Einval; | ||
330 | } | 361 | } |
331 | if (*p++ != del) | 362 | if (*p++ != del) |
332 | goto Einval; | 363 | goto Einval; |
364 | |||
333 | if (test_bit(Magic, &e->flags)) { | 365 | if (test_bit(Magic, &e->flags)) { |
334 | char *s = strchr(p, del); | 366 | /* Handle the 'M' (magic) format. */ |
367 | char *s; | ||
368 | |||
369 | /* Parse the 'offset' field. */ | ||
370 | s = strchr(p, del); | ||
335 | if (!s) | 371 | if (!s) |
336 | goto Einval; | 372 | goto Einval; |
337 | *s++ = '\0'; | 373 | *s++ = '\0'; |
338 | e->offset = simple_strtoul(p, &p, 10); | 374 | e->offset = simple_strtoul(p, &p, 10); |
339 | if (*p++) | 375 | if (*p++) |
340 | goto Einval; | 376 | goto Einval; |
377 | pr_debug("register: offset: %#x\n", e->offset); | ||
378 | |||
379 | /* Parse the 'magic' field. */ | ||
341 | e->magic = p; | 380 | e->magic = p; |
342 | p = scanarg(p, del); | 381 | p = scanarg(p, del); |
343 | if (!p) | 382 | if (!p) |
344 | goto Einval; | 383 | goto Einval; |
345 | p[-1] = '\0'; | 384 | p[-1] = '\0'; |
346 | if (!e->magic[0]) | 385 | if (p == e->magic) |
347 | goto Einval; | 386 | goto Einval; |
387 | if (USE_DEBUG) | ||
388 | print_hex_dump_bytes( | ||
389 | KBUILD_MODNAME ": register: magic[raw]: ", | ||
390 | DUMP_PREFIX_NONE, e->magic, p - e->magic); | ||
391 | |||
392 | /* Parse the 'mask' field. */ | ||
348 | e->mask = p; | 393 | e->mask = p; |
349 | p = scanarg(p, del); | 394 | p = scanarg(p, del); |
350 | if (!p) | 395 | if (!p) |
351 | goto Einval; | 396 | goto Einval; |
352 | p[-1] = '\0'; | 397 | p[-1] = '\0'; |
353 | if (!e->mask[0]) | 398 | if (p == e->mask) { |
354 | e->mask = NULL; | 399 | e->mask = NULL; |
400 | pr_debug("register: mask[raw]: none\n"); | ||
401 | } else if (USE_DEBUG) | ||
402 | print_hex_dump_bytes( | ||
403 | KBUILD_MODNAME ": register: mask[raw]: ", | ||
404 | DUMP_PREFIX_NONE, e->mask, p - e->mask); | ||
405 | |||
406 | /* | ||
407 | * Decode the magic & mask fields. | ||
408 | * Note: while we might have accepted embedded NUL bytes from | ||
409 | * above, the unescape helpers here will stop at the first one | ||
410 | * it encounters. | ||
411 | */ | ||
355 | e->size = string_unescape_inplace(e->magic, UNESCAPE_HEX); | 412 | e->size = string_unescape_inplace(e->magic, UNESCAPE_HEX); |
356 | if (e->mask && | 413 | if (e->mask && |
357 | string_unescape_inplace(e->mask, UNESCAPE_HEX) != e->size) | 414 | string_unescape_inplace(e->mask, UNESCAPE_HEX) != e->size) |
358 | goto Einval; | 415 | goto Einval; |
359 | if (e->size + e->offset > BINPRM_BUF_SIZE) | 416 | if (e->size + e->offset > BINPRM_BUF_SIZE) |
360 | goto Einval; | 417 | goto Einval; |
418 | pr_debug("register: magic/mask length: %i\n", e->size); | ||
419 | if (USE_DEBUG) { | ||
420 | print_hex_dump_bytes( | ||
421 | KBUILD_MODNAME ": register: magic[decoded]: ", | ||
422 | DUMP_PREFIX_NONE, e->magic, e->size); | ||
423 | |||
424 | if (e->mask) { | ||
425 | int i; | ||
426 | char *masked = kmalloc(e->size, GFP_USER); | ||
427 | |||
428 | print_hex_dump_bytes( | ||
429 | KBUILD_MODNAME ": register: mask[decoded]: ", | ||
430 | DUMP_PREFIX_NONE, e->mask, e->size); | ||
431 | |||
432 | if (masked) { | ||
433 | for (i = 0; i < e->size; ++i) | ||
434 | masked[i] = e->magic[i] & e->mask[i]; | ||
435 | print_hex_dump_bytes( | ||
436 | KBUILD_MODNAME ": register: magic[masked]: ", | ||
437 | DUMP_PREFIX_NONE, masked, e->size); | ||
438 | |||
439 | kfree(masked); | ||
440 | } | ||
441 | } | ||
442 | } | ||
361 | } else { | 443 | } else { |
444 | /* Handle the 'E' (extension) format. */ | ||
445 | |||
446 | /* Skip the 'offset' field. */ | ||
362 | p = strchr(p, del); | 447 | p = strchr(p, del); |
363 | if (!p) | 448 | if (!p) |
364 | goto Einval; | 449 | goto Einval; |
365 | *p++ = '\0'; | 450 | *p++ = '\0'; |
451 | |||
452 | /* Parse the 'magic' field. */ | ||
366 | e->magic = p; | 453 | e->magic = p; |
367 | p = strchr(p, del); | 454 | p = strchr(p, del); |
368 | if (!p) | 455 | if (!p) |
@@ -370,11 +457,16 @@ static Node *create_entry(const char __user *buffer, size_t count) | |||
370 | *p++ = '\0'; | 457 | *p++ = '\0'; |
371 | if (!e->magic[0] || strchr(e->magic, '/')) | 458 | if (!e->magic[0] || strchr(e->magic, '/')) |
372 | goto Einval; | 459 | goto Einval; |
460 | pr_debug("register: extension: {%s}\n", e->magic); | ||
461 | |||
462 | /* Skip the 'mask' field. */ | ||
373 | p = strchr(p, del); | 463 | p = strchr(p, del); |
374 | if (!p) | 464 | if (!p) |
375 | goto Einval; | 465 | goto Einval; |
376 | *p++ = '\0'; | 466 | *p++ = '\0'; |
377 | } | 467 | } |
468 | |||
469 | /* Parse the 'interpreter' field. */ | ||
378 | e->interpreter = p; | 470 | e->interpreter = p; |
379 | p = strchr(p, del); | 471 | p = strchr(p, del); |
380 | if (!p) | 472 | if (!p) |
@@ -382,10 +474,10 @@ static Node *create_entry(const char __user *buffer, size_t count) | |||
382 | *p++ = '\0'; | 474 | *p++ = '\0'; |
383 | if (!e->interpreter[0]) | 475 | if (!e->interpreter[0]) |
384 | goto Einval; | 476 | goto Einval; |
477 | pr_debug("register: interpreter: {%s}\n", e->interpreter); | ||
385 | 478 | ||
386 | 479 | /* Parse the 'flags' field. */ | |
387 | p = check_special_flags (p, e); | 480 | p = check_special_flags (p, e); |
388 | |||
389 | if (*p == '\n') | 481 | if (*p == '\n') |
390 | p++; | 482 | p++; |
391 | if (p != buf + count) | 483 | if (p != buf + count) |
@@ -553,11 +645,17 @@ static ssize_t bm_entry_write(struct file *file, const char __user *buffer, | |||
553 | int res = parse_command(buffer, count); | 645 | int res = parse_command(buffer, count); |
554 | 646 | ||
555 | switch (res) { | 647 | switch (res) { |
556 | case 1: clear_bit(Enabled, &e->flags); | 648 | case 1: |
649 | /* Disable this handler. */ | ||
650 | clear_bit(Enabled, &e->flags); | ||
557 | break; | 651 | break; |
558 | case 2: set_bit(Enabled, &e->flags); | 652 | case 2: |
653 | /* Enable this handler. */ | ||
654 | set_bit(Enabled, &e->flags); | ||
559 | break; | 655 | break; |
560 | case 3: root = dget(file->f_path.dentry->d_sb->s_root); | 656 | case 3: |
657 | /* Delete this handler. */ | ||
658 | root = dget(file->f_path.dentry->d_sb->s_root); | ||
561 | mutex_lock(&root->d_inode->i_mutex); | 659 | mutex_lock(&root->d_inode->i_mutex); |
562 | 660 | ||
563 | kill_node(e); | 661 | kill_node(e); |
@@ -661,9 +759,17 @@ static ssize_t bm_status_write(struct file * file, const char __user * buffer, | |||
661 | struct dentry *root; | 759 | struct dentry *root; |
662 | 760 | ||
663 | switch (res) { | 761 | switch (res) { |
664 | case 1: enabled = 0; break; | 762 | case 1: |
665 | case 2: enabled = 1; break; | 763 | /* Disable all handlers. */ |
666 | case 3: root = dget(file->f_path.dentry->d_sb->s_root); | 764 | enabled = 0; |
765 | break; | ||
766 | case 2: | ||
767 | /* Enable all handlers. */ | ||
768 | enabled = 1; | ||
769 | break; | ||
770 | case 3: | ||
771 | /* Delete all handlers. */ | ||
772 | root = dget(file->f_path.dentry->d_sb->s_root); | ||
667 | mutex_lock(&root->d_inode->i_mutex); | 773 | mutex_lock(&root->d_inode->i_mutex); |
668 | 774 | ||
669 | while (!list_empty(&entries)) | 775 | while (!list_empty(&entries)) |