Date: Thu, 27 Apr 2017 11:15:19 +0000 From: bugzilla-noreply@freebsd.org To: freebsd-bugs@FreeBSD.org Subject: [Bug 218911] [uma] Memory corruption with certain item sizes Message-ID: <bug-218911-8@https.bugs.freebsd.org/bugzilla/>
next in thread | raw e-mail | index | archive | help
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=3D218911 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: fk@fabiankeil.de Created attachment 182122 --> https://bugs.freebsd.org/bugzilla/attachment.cgi?id=3D182122&action= =3Dedit 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=3D1) at /usr/src/sys/kern/kern_shutdown.c:298 #2 0xffffffff80555465 in kern_reboot (howto=3D260) at /usr/src/sys/kern/kern_shutdown.c:366 #3 0xffffffff80555a40 in vpanic (fmt=3D<optimized out>, ap=3D0xfffffe0113d= 69980) at /usr/src/sys/kern/kern_shutdown.c:759 #4 0xffffffff80555876 in kassert_panic (fmt=3D0xffffffff808c521f "Assertio= n %s failed at %s:%d") at /usr/src/sys/kern/kern_shutdown.c:649 #5 0xffffffff807dd333 in keg_fetch_slab (keg=3D0xfffff80005b52480, zone=3D0xfffff80005b53700, flags=3D2) at /usr/src/sys/vm/uma_core.c:2343 #6 0xffffffff807dc9ae in zone_fetch_slab (zone=3D0xfffff80005b53700, keg=3D0xfffff80005b52480, flags=3D2) at /usr/src/sys/vm/uma_core.c:2368 #7 0xffffffff807dca40 in zone_import (zone=3D0xfffff80005b53700, bucket=3D0xfffff800d7eae9f8, max=3D1, flags=3D2) at /usr/src/sys/vm/uma_cor= e.c:2494 #8 0xffffffff807d9341 in zone_alloc_bucket (zone=3D0xfffff80005b53700, udata=3D0x0, flags=3D2) at /usr/src/sys/vm/uma_core.c:2524 #9 uma_zalloc_arg (zone=3D0xfffff80005b53700, udata=3D0x0, flags=3D<optimi= zed out>) at /usr/src/sys/vm/uma_core.c:2250 #10 0xffffffff8182329f in uma_zalloc (flags=3D2, zone=3D<optimized out>) at /usr/src/sys/vm/uma.h:336 #11 g_raid_init (mp=3D0xffffffff81856838 <g_raid_class>) at /usr/src/sys/modules/geom/geom_raid/../../../geom/raid/g_raid.c:2496 #12 0xffffffff804d1125 in g_load_class (arg=3D<optimized out>, flag=3D<opti= mized 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=3D0xffffffff804cfa60 <g_event_procbody>, arg=3D0x0, frame=3D0xfffffe0113d69c00) at /usr/src/sys/kern/kern_fork.c:1040 #16 <signal handler called> [...] (kgdb) f 5 #5 0xffffffff807dd333 in keg_fetch_slab (keg=3D0xfffff80005b52480, zone=3D0xfffff80005b53700, flags=3D2) at /usr/src/sys/vm/uma_core.c:2343 2343 MPASS(slab->us_keg =3D=3D keg); (kgdb) p slab->us_keg $1 =3D (uma_keg_t) 0xdeadc0dedeadc0de (kgdb) f 9 #9 uma_zalloc_arg (zone=3D0xfffff80005b53700, udata=3D0x0, flags=3D<optimi= zed out>) at /usr/src/sys/vm/uma_core.c:2250 2250 bucket =3D zone_alloc_bucket(zone, udata, flags); (kgdb) p zone $2 =3D (uma_zone_t) 0xfffff80005b53700 (kgdb) p *zone $3 =3D {uz_lock =3D {lock_object =3D {lo_name =3D 0xffffffff8184f85a "uma_t= est", lo_flags =3D 21168128, lo_data =3D 0, lo_witness =3D 0xfffffe0000a0cf80}, m= tx_lock =3D 4}, uz_lockptr =3D 0xfffff80005b52480, uz_name =3D 0xffffffff8184f85a "uma_test", uz_link =3D {le_next =3D 0x0, = le_prev =3D 0xfffff80005b52510}, uz_buckets =3D {lh_first =3D 0x0}, uz_kegs =3D {lh_fir= st =3D 0xfffff80005b537b0}, uz_klink =3D {kl_link =3D {le_next =3D 0x0, le_prev =3D 0xfffff80005b537a8}, kl_keg =3D 0xfffff80005b52480}, uz_s= lab =3D 0xffffffff807dc940 <zone_fetch_slab>, uz_ctor =3D 0xffffffff807dd730 <trash_ctor>, uz_dtor =3D 0xffffffff807dd780 <trash_dtor>, uz_init =3D 0x0, uz_fini =3D 0x0, uz_import =3D 0xffffffff807dc9f0 <zone_import>, uz_relea= se =3D 0xffffffff807dcc90 <zone_release>, uz_arg =3D 0xfffff80005b53700, uz_flags = =3D 0, uz_size =3D 129024, uz_allocs =3D 0, uz_fails =3D 0, uz_frees =3D 0, uz_sleeps =3D 0, uz_count =3D 1, uz_count_min =3D 1, uz_warning =3D 0x0, = uz_ratecheck =3D {tv_sec =3D 0, tv_usec =3D 0}, uz_maxaction =3D {ta_link =3D {stqe_next= =3D 0x0}, ta_pending =3D 0, ta_priority =3D 0, ta_func =3D 0x0, ta_context =3D 0x0}, 0x0}, uz_cpu =3D {{uc_freebucket =3D 0x0, uc_allocbucket =3D 0x0, uc_allocs =3D= 0, uc_frees =3D 0}}} (kgdb) f 11 #11 g_raid_init (mp=3D0xffffffff81856838 <g_raid_class>) at /usr/src/sys/modules/geom/geom_raid/../../../geom/raid/g_raid.c:2496 2496 p =3D uma_zalloc(uma_test_zone, M_WAITOK); (kgdb) p i $4 =3D 0 (kgdb) l - 2491 2492 uma_test_zone =3D uma_zcreate("uma_test", uma_test_zone_item_size, NULL, NULL, 2493 NULL, NULL, 0, 0); 2494 2495 for (i =3D 0; i <=3D uma_test_zone_item_size; i++) { 2496 p =3D uma_zalloc(uma_test_zone, M_WAITOK); 2497 memset(p, 0x10, i); 2498 G_RAID_DEBUG(1, "Freeing item after filling %d byte= s.", i); 2499 uma_zfree(uma_test_zone, p); 2500 } (kgdb) f 9 #9 uma_zalloc_arg (zone=3D0xfffff80005b53700, udata=3D0x0, flags=3D<optimi= zed out>) at /usr/src/sys/vm/uma_core.c:2250 2250 bucket =3D zone_alloc_bucket(zone, udata, flags); (kgdb) p zone->uz_kegs->lh_first->kl_keg $6 =3D (uma_keg_t) 0xfffff80005b52480 (kgdb) p *zone->uz_kegs->lh_first->kl_keg $7 =3D {uk_lock =3D {lock_object =3D {lo_name =3D 0xffffffff8184f85a "uma_t= est", lo_flags =3D 21168128, lo_data =3D 0, lo_witness =3D 0xfffffe0000a0cf80}, m= tx_lock =3D 18446735277663592448}, uk_hash =3D {uh_slab_hash =3D 0x0, uh_hashsize =3D 0, uh_hashmask =3D 0}, uk_zones =3D {lh_first =3D 0xfffff80005b53700}, uk_= part_slab =3D {lh_first =3D 0x0}, uk_free_slab =3D {lh_first =3D 0x0}, uk_full_slab = =3D {lh_first =3D 0x0}, uk_align =3D 0, uk_pages =3D 32, uk_free =3D 1, uk_reserve =3D 0, uk_size =3D 129024, uk_rsize =3D 129024, uk_maxpages =3D 0, uk_init =3D 0xffffffff807dd7b0 <trash_init>, uk_fini =3D 0xffffffff807dd7e0 <trash_fini= >, uk_allocf =3D 0xffffffff807db690 <page_alloc>, uk_freef =3D 0xffffffff807db770 <page_free>, uk_offset =3D 0, uk_kva =3D = 0, uk_slabzone =3D 0x0, uk_pgoff =3D 65424, uk_ppera =3D 32, uk_ipers =3D 1, u= k_flags =3D 0, uk_name =3D 0xffffffff8184f85a "uma_test", uk_link =3D { le_next =3D 0xfffff80005b52300, le_prev =3D 0xffffffff80f45d00 <uma_keg= s>}} (kgdb) p sizeof(struct uma_slab) $8 =3D 112 (kgdb) p zone->uz_kegs->lh_first->kl_keg->uk_ppera $9 =3D 32 (kgdb) p 4096 * zone->uz_kegs->lh_first->kl_keg->uk_ppera $10 =3D 131072 (kgdb) p 4096 * zone->uz_kegs->lh_first->kl_keg->uk_ppera - sizeof(struct uma_slab) $11 =3D 130960 (kgdb) p 4096 * zone->uz_kegs->lh_first->kl_keg->uk_ppera - sizeof(struct uma_slab) - 65536 $12 =3D 65424 (kgdb) p zone->uz_kegs->lh_first->kl_keg->uk_size $13 =3D 129024 (kgdb) p 4096 * zone->uz_kegs->lh_first->kl_keg->uk_ppera -=20 zone->uz_kegs->lh_first->kl_keg->uk_rsize $14 =3D 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 --=20 You are receiving this mail because: You are the assignee for the bug.=
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?bug-218911-8>