| From 5cc41e099504b77014358b58567c5ea6293dd220 Mon Sep 17 00:00:00 2001 |
| From: Thadeu Lima de Souza Cascardo <cascardo@canonical.com> |
| Date: Thu, 7 Jun 2018 17:11:01 -0700 |
| Subject: fs/binfmt_misc.c: do not allow offset overflow |
| |
| From: Thadeu Lima de Souza Cascardo <cascardo@canonical.com> |
| |
| commit 5cc41e099504b77014358b58567c5ea6293dd220 upstream. |
| |
| WHen registering a new binfmt_misc handler, it is possible to overflow |
| the offset to get a negative value, which might crash the system, or |
| possibly leak kernel data. |
| |
| Here is a crash log when 2500000000 was used as an offset: |
| |
| BUG: unable to handle kernel paging request at ffff989cfd6edca0 |
| IP: load_misc_binary+0x22b/0x470 [binfmt_misc] |
| PGD 1ef3e067 P4D 1ef3e067 PUD 0 |
| Oops: 0000 [#1] SMP NOPTI |
| Modules linked in: binfmt_misc kvm_intel ppdev kvm irqbypass joydev input_leds serio_raw mac_hid parport_pc qemu_fw_cfg parpy |
| CPU: 0 PID: 2499 Comm: bash Not tainted 4.15.0-22-generic #24-Ubuntu |
| Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.11.1-1 04/01/2014 |
| RIP: 0010:load_misc_binary+0x22b/0x470 [binfmt_misc] |
| Call Trace: |
| search_binary_handler+0x97/0x1d0 |
| do_execveat_common.isra.34+0x667/0x810 |
| SyS_execve+0x31/0x40 |
| do_syscall_64+0x73/0x130 |
| entry_SYSCALL_64_after_hwframe+0x3d/0xa2 |
| |
| Use kstrtoint instead of simple_strtoul. It will work as the code |
| already set the delimiter byte to '\0' and we only do it when the field |
| is not empty. |
| |
| Tested with offsets -1, 2500000000, UINT_MAX and INT_MAX. Also tested |
| with examples documented at Documentation/admin-guide/binfmt-misc.rst |
| and other registrations from packages on Ubuntu. |
| |
| Link: http://lkml.kernel.org/r/20180529135648.14254-1-cascardo@canonical.com |
| Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") |
| Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com> |
| Reviewed-by: Andrew Morton <akpm@linux-foundation.org> |
| Cc: Alexander Viro <viro@zeniv.linux.org.uk> |
| Cc: <stable@vger.kernel.org> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/binfmt_misc.c | 12 +++++++++--- |
| 1 file changed, 9 insertions(+), 3 deletions(-) |
| |
| --- a/fs/binfmt_misc.c |
| +++ b/fs/binfmt_misc.c |
| @@ -334,8 +334,13 @@ static Node *create_entry(const char __u |
| char *s = strchr(p, del); |
| if (!s) |
| goto Einval; |
| - *s++ = '\0'; |
| - e->offset = simple_strtoul(p, &p, 10); |
| + *s = '\0'; |
| + if (p != s) { |
| + int r = kstrtoint(p, 10, &e->offset); |
| + if (r != 0 || e->offset < 0) |
| + goto Einval; |
| + } |
| + p = s; |
| if (*p++) |
| goto Einval; |
| e->magic = p; |
| @@ -356,7 +361,8 @@ static Node *create_entry(const char __u |
| if (e->mask && |
| string_unescape_inplace(e->mask, UNESCAPE_HEX) != e->size) |
| goto Einval; |
| - if (e->size + e->offset > BINPRM_BUF_SIZE) |
| + if (e->size > BINPRM_BUF_SIZE || |
| + BINPRM_BUF_SIZE - e->size < e->offset) |
| goto Einval; |
| } else { |
| p = strchr(p, del); |