Bug 263971 - ffs: malicious superblock can cause buffer overflow during tasting: panic: vm_fault_lookup: fault on nofault entry, addr: 0xffffffc07cb67000
Summary: ffs: malicious superblock can cause buffer overflow during tasting: panic: vm...
Status: In Progress
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: Unspecified
Hardware: Any Any
: --- Affects Some People
Assignee: freebsd-fs (Nobody)
URL:
Keywords: crash, needs-qa
Depends on:
Blocks: 263979
  Show dependency treegraph
 
Reported: 2022-05-14 13:30 UTC by Robert Morris
Modified: 2022-05-22 19:18 UTC (History)
6 users (show)

See Also:
koobs: maintainer-feedback? (mckusick)
koobs: maintainer-feedback? (secteam)
koobs: mfc-stable13?
koobs: mfc-stable12?


Attachments
disk image with malicious superblock fields that cause buffer overflow during tasting (8.00 KB, application/octet-stream)
2022-05-14 13:30 UTC, Robert Morris
no flags Details
disk image that causes size calculation in ffs_sbget() to wrap around (16.00 KB, application/octet-stream)
2022-05-16 21:29 UTC, Robert Morris
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Robert Morris 2022-05-14 13:30:38 UTC
Created attachment 233909 [details]
disk image with malicious superblock fields that cause buffer overflow during tasting

ffs_sbget() allocates some memory into which it reads file system
information, using fields from the superblock to choose a size:

    size = fs->fs_cssize;
    if (fs->fs_contigsumsize > 0)
        size += fs->fs_ncg * sizeof(int32_t);
    size += fs->fs_ncg * sizeof(u_int8_t);
    ...;
    if ((space = UFS_MALLOC(size, filltype, M_WAITOK)) == NULL) {

An attacker can choose values that cause size to be too small, causing
subsequent code to write beyond the end of space.

The attached disk image has a superblock with

  fs_cssize -1434999068
  fs_contigsumsize 2147483647
  fs_ncg 287173615
  
The calculated size is 869007.

Later on:

    if (fs->fs_contigsumsize > 0) {
        fs->fs_maxcluster = lp = (int32_t *)space;
        for (i = 0; i < fs->fs_ncg; i++)
            *lp++ = fs->fs_contigsumsize;

Since fs_ncg > size, this loop writes the attacker-chosen
fs_contigsumsize beyond the allocated space.

What I see when the attached disk image is tasted:

# uname -a
FreeBSD  14.0-CURRENT FreeBSD 14.0-CURRENT #267 main-n250920-74195f0a7a6c-dirty: Sat May 14 09:04:48 EDT 2022     rtm@xxx:/usr/obj/usr/rtm/symbsd/src/riscv.riscv64/sys/RTM  riscv
# mdconfig -f taste7a.img
panic: vm_fault_lookup: fault on nofault entry, addr: 0xffffffc07cb67000
cpuid = 0
time = 1652523702
KDB: stack backtrace:
db_trace_self() at db_trace_self
db_trace_self_wrapper() at db_trace_self_wrapper+0x38
kdb_backtrace() at kdb_backtrace+0x2c
vpanic() at vpanic+0x16e
panic() at panic+0x2a
vm_fault_lookup() at vm_fault_lookup+0x1bc
vm_fault() at vm_fault+0x9e
vm_fault_trap() at vm_fault_trap+0x68
page_fault_handler() at page_fault_handler+0x13c
do_trap_supervisor() at do_trap_supervisor+0x76
cpu_exception_handler_supervisor() at cpu_exception_handler_supervisor+0x70
--- exception 15, tval = 0xffffffc07cb67000
ffs_sbget() at ffs_sbget+0x2b0
g_label_ufs_taste_common() at g_label_ufs_taste_common+0x6c
g_label_ufs_id_taste() at g_label_ufs_id_taste+0xe
g_label_taste() at g_label_taste+0x198
g_new_provider_event() at g_new_provider_event+0xb8
one_event() at one_event+0x106
g_run_events() at g_run_events+0x8a
g_event_procbody() at g_event_procbody+0x56
fork_exit() at fork_exit+0x80
fork_trampoline() at fork_trampoline+0xa
KDB: enter: panic
[ thread pid 13 tid 100017 ]
Stopped at      breakpoint+0xa: c.ldsp  s0,0(sp)
db>
Comment 1 Kirk McKusick freebsd_committer 2022-05-16 00:18:59 UTC
Please check to see if my proposed change in https://reviews.freebsd.org/D35219 resolves this bug.
Comment 2 Robert Morris 2022-05-16 21:29:06 UTC
Created attachment 233973 [details]
disk image that causes size calculation in ffs_sbget() to wrap around
Comment 3 Robert Morris 2022-05-16 21:34:06 UTC
(In reply to Kirk McKusick from comment #1)
Even with validate_sblock(), the int32 size in ffs_sbget() can
be made to wrap around. I've attached a disk image taste9f.img with

  fs_cssize 2021359616
  fs_contigsumsize -1
  ncg 126334728

so that this in ffs_sbget()

        size = fs->fs_cssize;
        size += fs->fs_ncg * sizeof(u_int8_t);

yields size = -2147272952 when I run mdconfig -f taste9f.img
Then the process hangs in UFS_MALLOC(size).
Comment 4 Kirk McKusick freebsd_committer 2022-05-17 07:05:14 UTC
(In reply to Robert Morris from comment #3)
I have tried to further restrict the values that I accept for fs_cssize,
fs_ncg, and fs_contigsumsize. And also put a limit on the size of the filesystem that can be mounted based on kernel memory limits.
Comment 5 Kirk McKusick freebsd_committer 2022-05-21 23:28:50 UTC
(In reply to Kirk McKusick from comment #4)
Can you verify that my patch of May 21 fixes this problem?
Comment 6 Robert Morris 2022-05-22 19:18:16 UTC
(In reply to Kirk McKusick from comment #5)
Yes -- your patch of May 21 makes this problem go away for me.