https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=218911
Bug ID: 218911 Summary: [uma] Memory corruption with certain item sizes Product: Base System Version: 11.0-STABLE Hardware: Any OS: Any Status: New Keywords: patch Severity: Affects Some People Priority: --- Component: kern Assignee: freebsd-bugs@FreeBSD.org Reporter: f...@fabiankeil.de Created attachment 182122 --> https://bugs.freebsd.org/bugzilla/attachment.cgi?id=182122&action=edit sys/vm: Set UMA_ZONE_OFFPAGE if the offset would be too large to fit into keg->uk_pgoff When creating an uma zone without specifying the UMA_ZONE_OFFPAGE flag uma may use the slab itself for its book-keeping purposes if it contains enough unused space. keg->uk_pgoff is an uint16_t. It can overflow in which case valid writes to correctly allocated items corrupt uma's book-keeping data. With INVARIANTS enabled, this results in a panic in uma_dbg_free(), without INVARIANTS the effect is less obvious. Here's a backtrace from a panic with INVARIANTS enabled using a test zone with item size 129024 which is one of the sizes that trigger the problem: (kgdb) where #0 __curthread () at ./machine/pcpu.h:222 #1 doadump (textdump=1) at /usr/src/sys/kern/kern_shutdown.c:298 #2 0xffffffff80555465 in kern_reboot (howto=260) at /usr/src/sys/kern/kern_shutdown.c:366 #3 0xffffffff80555a40 in vpanic (fmt=<optimized out>, ap=0xfffffe0113d69980) at /usr/src/sys/kern/kern_shutdown.c:759 #4 0xffffffff80555876 in kassert_panic (fmt=0xffffffff808c521f "Assertion %s failed at %s:%d") at /usr/src/sys/kern/kern_shutdown.c:649 #5 0xffffffff807dd333 in keg_fetch_slab (keg=0xfffff80005b52480, zone=0xfffff80005b53700, flags=2) at /usr/src/sys/vm/uma_core.c:2343 #6 0xffffffff807dc9ae in zone_fetch_slab (zone=0xfffff80005b53700, keg=0xfffff80005b52480, flags=2) at /usr/src/sys/vm/uma_core.c:2368 #7 0xffffffff807dca40 in zone_import (zone=0xfffff80005b53700, bucket=0xfffff800d7eae9f8, max=1, flags=2) at /usr/src/sys/vm/uma_core.c:2494 #8 0xffffffff807d9341 in zone_alloc_bucket (zone=0xfffff80005b53700, udata=0x0, flags=2) at /usr/src/sys/vm/uma_core.c:2524 #9 uma_zalloc_arg (zone=0xfffff80005b53700, udata=0x0, flags=<optimized out>) at /usr/src/sys/vm/uma_core.c:2250 #10 0xffffffff8182329f in uma_zalloc (flags=2, zone=<optimized out>) at /usr/src/sys/vm/uma.h:336 #11 g_raid_init (mp=0xffffffff81856838 <g_raid_class>) at /usr/src/sys/modules/geom/geom_raid/../../../geom/raid/g_raid.c:2496 #12 0xffffffff804d1125 in g_load_class (arg=<optimized out>, flag=<optimized out>) at /usr/src/sys/geom/geom_subr.c:124 #13 0xffffffff804cd7c7 in one_event () at /usr/src/sys/geom/geom_event.c:264 #14 g_run_events () at /usr/src/sys/geom/geom_event.c:286 #15 0xffffffff80517e64 in fork_exit (callout=0xffffffff804cfa60 <g_event_procbody>, arg=0x0, frame=0xfffffe0113d69c00) at /usr/src/sys/kern/kern_fork.c:1040 #16 <signal handler called> [...] (kgdb) f 5 #5 0xffffffff807dd333 in keg_fetch_slab (keg=0xfffff80005b52480, zone=0xfffff80005b53700, flags=2) at /usr/src/sys/vm/uma_core.c:2343 2343 MPASS(slab->us_keg == keg); (kgdb) p slab->us_keg $1 = (uma_keg_t) 0xdeadc0dedeadc0de (kgdb) f 9 #9 uma_zalloc_arg (zone=0xfffff80005b53700, udata=0x0, flags=<optimized out>) at /usr/src/sys/vm/uma_core.c:2250 2250 bucket = zone_alloc_bucket(zone, udata, flags); (kgdb) p zone $2 = (uma_zone_t) 0xfffff80005b53700 (kgdb) p *zone $3 = {uz_lock = {lock_object = {lo_name = 0xffffffff8184f85a "uma_test", lo_flags = 21168128, lo_data = 0, lo_witness = 0xfffffe0000a0cf80}, mtx_lock = 4}, uz_lockptr = 0xfffff80005b52480, uz_name = 0xffffffff8184f85a "uma_test", uz_link = {le_next = 0x0, le_prev = 0xfffff80005b52510}, uz_buckets = {lh_first = 0x0}, uz_kegs = {lh_first = 0xfffff80005b537b0}, uz_klink = {kl_link = {le_next = 0x0, le_prev = 0xfffff80005b537a8}, kl_keg = 0xfffff80005b52480}, uz_slab = 0xffffffff807dc940 <zone_fetch_slab>, uz_ctor = 0xffffffff807dd730 <trash_ctor>, uz_dtor = 0xffffffff807dd780 <trash_dtor>, uz_init = 0x0, uz_fini = 0x0, uz_import = 0xffffffff807dc9f0 <zone_import>, uz_release = 0xffffffff807dcc90 <zone_release>, uz_arg = 0xfffff80005b53700, uz_flags = 0, uz_size = 129024, uz_allocs = 0, uz_fails = 0, uz_frees = 0, uz_sleeps = 0, uz_count = 1, uz_count_min = 1, uz_warning = 0x0, uz_ratecheck = {tv_sec = 0, tv_usec = 0}, uz_maxaction = {ta_link = {stqe_next = 0x0}, ta_pending = 0, ta_priority = 0, ta_func = 0x0, ta_context = 0x0}, 0x0}, uz_cpu = {{uc_freebucket = 0x0, uc_allocbucket = 0x0, uc_allocs = 0, uc_frees = 0}}} (kgdb) f 11 #11 g_raid_init (mp=0xffffffff81856838 <g_raid_class>) at /usr/src/sys/modules/geom/geom_raid/../../../geom/raid/g_raid.c:2496 2496 p = uma_zalloc(uma_test_zone, M_WAITOK); (kgdb) p i $4 = 0 (kgdb) l - 2491 2492 uma_test_zone = uma_zcreate("uma_test", uma_test_zone_item_size, NULL, NULL, 2493 NULL, NULL, 0, 0); 2494 2495 for (i = 0; i <= uma_test_zone_item_size; i++) { 2496 p = uma_zalloc(uma_test_zone, M_WAITOK); 2497 memset(p, 0x10, i); 2498 G_RAID_DEBUG(1, "Freeing item after filling %d bytes.", i); 2499 uma_zfree(uma_test_zone, p); 2500 } (kgdb) f 9 #9 uma_zalloc_arg (zone=0xfffff80005b53700, udata=0x0, flags=<optimized out>) at /usr/src/sys/vm/uma_core.c:2250 2250 bucket = zone_alloc_bucket(zone, udata, flags); (kgdb) p zone->uz_kegs->lh_first->kl_keg $6 = (uma_keg_t) 0xfffff80005b52480 (kgdb) p *zone->uz_kegs->lh_first->kl_keg $7 = {uk_lock = {lock_object = {lo_name = 0xffffffff8184f85a "uma_test", lo_flags = 21168128, lo_data = 0, lo_witness = 0xfffffe0000a0cf80}, mtx_lock = 18446735277663592448}, uk_hash = {uh_slab_hash = 0x0, uh_hashsize = 0, uh_hashmask = 0}, uk_zones = {lh_first = 0xfffff80005b53700}, uk_part_slab = {lh_first = 0x0}, uk_free_slab = {lh_first = 0x0}, uk_full_slab = {lh_first = 0x0}, uk_align = 0, uk_pages = 32, uk_free = 1, uk_reserve = 0, uk_size = 129024, uk_rsize = 129024, uk_maxpages = 0, uk_init = 0xffffffff807dd7b0 <trash_init>, uk_fini = 0xffffffff807dd7e0 <trash_fini>, uk_allocf = 0xffffffff807db690 <page_alloc>, uk_freef = 0xffffffff807db770 <page_free>, uk_offset = 0, uk_kva = 0, uk_slabzone = 0x0, uk_pgoff = 65424, uk_ppera = 32, uk_ipers = 1, uk_flags = 0, uk_name = 0xffffffff8184f85a "uma_test", uk_link = { le_next = 0xfffff80005b52300, le_prev = 0xffffffff80f45d00 <uma_kegs>}} (kgdb) p sizeof(struct uma_slab) $8 = 112 (kgdb) p zone->uz_kegs->lh_first->kl_keg->uk_ppera $9 = 32 (kgdb) p 4096 * zone->uz_kegs->lh_first->kl_keg->uk_ppera $10 = 131072 (kgdb) p 4096 * zone->uz_kegs->lh_first->kl_keg->uk_ppera - sizeof(struct uma_slab) $11 = 130960 (kgdb) p 4096 * zone->uz_kegs->lh_first->kl_keg->uk_ppera - sizeof(struct uma_slab) - 65536 $12 = 65424 (kgdb) p zone->uz_kegs->lh_first->kl_keg->uk_size $13 = 129024 (kgdb) p 4096 * zone->uz_kegs->lh_first->kl_keg->uk_ppera - zone->uz_kegs->lh_first->kl_keg->uk_rsize $14 = 2048 The attached patch lets uma set the UMA_ZONE_OFFPAGE if keg->uk_pgoff would otherwise be used but is too small to hold the correct offset. Changing keg->uk_pgoff's type should work as well but I haven't tested it. Obtained from: ElectroBSD -- You are receiving this mail because: You are the assignee for the bug. _______________________________________________ freebsd-bugs@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/freebsd-bugs To unsubscribe, send any mail to "freebsd-bugs-unsubscr...@freebsd.org"