aboutsummaryrefslogtreecommitdiffstats
path: root/fs/binfmt_misc.c
diff options
context:
space:
mode:
authorMike Frysinger <vapier@gentoo.org>2014-12-10 18:52:08 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2014-12-10 20:41:12 -0500
commit6b899c4e9a049dfca759d990bd53b14f81c3626c (patch)
treef2321ebef1293c81a1bac05e2361d075b977f5d0 /fs/binfmt_misc.c
parent5e4f6ba5eb7facb0dbf2734f5a12033c70f8eb53 (diff)
binfmt_misc: add comments & debug logs
When trying to develop a custom format handler, the errors returned all effectively get bucketed as EINVAL with no kernel messages. The other errors (ENOMEM/EFAULT) are internal/obvious and basic. Thus any time a bad handler is rejected, the developer has to walk the dense code and try to guess where it went wrong. Needing to dive into kernel code is itself a fairly high barrier for a lot of people. To improve this situation, let's deploy extensive pr_debug markers at logical parse points, and add comments to the dense parsing logic. It let's you see exactly where the parsing aborts, the string the kernel received (useful when dealing with shell code), how it translated the buffers to binary data, and how it will apply the mask at runtime. Some example output: $ echo ':qemu-foo:M::\x7fELF\xAD\xAD\x01\x00:\xff\xff\xff\xff\xff\x00\xff\x00:/usr/bin/qemu-foo:POC' > register $ dmesg binfmt_misc: register: received 92 bytes binfmt_misc: register: delim: 0x3a {:} binfmt_misc: register: name: {qemu-foo} binfmt_misc: register: type: M (magic) binfmt_misc: register: offset: 0x0 binfmt_misc: register: magic[raw]: 5c 78 37 66 45 4c 46 5c 78 41 44 5c 78 41 44 5c \x7fELF\xAD\xAD\ binfmt_misc: register: magic[raw]: 78 30 31 5c 78 30 30 00 x01\x00. binfmt_misc: register: mask[raw]: 5c 78 66 66 5c 78 66 66 5c 78 66 66 5c 78 66 66 \xff\xff\xff\xff binfmt_misc: register: mask[raw]: 5c 78 66 66 5c 78 30 30 5c 78 66 66 5c 78 30 30 \xff\x00\xff\x00 binfmt_misc: register: mask[raw]: 00 . binfmt_misc: register: magic/mask length: 8 binfmt_misc: register: magic[decoded]: 7f 45 4c 46 ad ad 01 00 .ELF.... binfmt_misc: register: mask[decoded]: ff ff ff ff ff 00 ff 00 ........ binfmt_misc: register: magic[masked]: 7f 45 4c 46 ad 00 01 00 .ELF.... binfmt_misc: register: interpreter: {/usr/bin/qemu-foo} binfmt_misc: register: flag: P (preserve argv0) binfmt_misc: register: flag: O (open binary) binfmt_misc: register: flag: C (preserve creds) The [raw] lines show us exactly what was received from userspace. The lines after that show us how the kernel has decoded things. Signed-off-by: Mike Frysinger <vapier@gentoo.org> Cc: Al Viro <viro@zeniv.linux.org.uk> Cc: Joe Perches <joe@perches.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/binfmt_misc.c')
-rw-r--r--fs/binfmt_misc.c136
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
36enum { 43enum {
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])