Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset 81d3612 in mainline


Ignore:
Timestamp:
2021-09-03T17:44:29Z (3 months ago)
Author:
Martin Decky <martin@…>
Branches:
master
Children:
3c3657c
Parents:
400a16d
Message:

Fix memory corruption caused by merging zones

Originally, the frames in the gap between the two merged zones has not
been marked as unavailable. This caused allocation requests to
potentially land in this gap and thus to memory corruption. Now the
frames in the gap are properly marked.

Use a dedicated function zone_mark_available() to mark old
configuration frames after merging as available. Since the
configuration frames are either marked using zone_mark_unavailable()
(for the original zones created according to the physical memory map)
or the busy count of the configuration frames is explicitly extracted
during the merging, the use of zone_frame_free() caused underflow of
the busy counter.

Add a few useful assertions.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/src/mm/frame.c

    r400a16d r81d3612  
    370370{
    371371        assert(zone->flags & ZONE_AVAILABLE);
     372        assert(zone->free_count >= count);
    372373
    373374        /* Allocate frames from zone */
     
    410411
    411412        frame_t *frame = zone_get_frame(zone, index);
    412 
    413413        assert(frame->refcount > 0);
    414414
    415415        if (!--frame->refcount) {
     416                assert(zone->busy_count > 0);
     417
    416418                bitmap_set(&zone->bitmap, index, 0);
    417419
     
    432434
    433435        frame_t *frame = zone_get_frame(zone, index);
     436        assert(frame->refcount <= 1);
     437
    434438        if (frame->refcount > 0)
    435439                return;
    436440
     441        assert(zone->free_count > 0);
     442
    437443        frame->refcount = 1;
    438444        bitmap_set_range(&zone->bitmap, index, 1);
     
    440446        zone->free_count--;
    441447        reserve_force_alloc(1);
     448}
     449
     450/** Mark frame in zone available to allocation. */
     451_NO_TRACE static void zone_mark_available(zone_t *zone, size_t index)
     452{
     453        assert(zone->flags & ZONE_AVAILABLE);
     454
     455        frame_t *frame = zone_get_frame(zone, index);
     456        assert(frame->refcount == 1);
     457
     458        frame->refcount = 0;
     459        bitmap_set_range(&zone->bitmap, index, 0);
     460
     461        zone->free_count++;
    442462}
    443463
     
    465485        /* Difference between zone bases */
    466486        pfn_t base_diff = zones.info[z2].base - zones.info[z1].base;
     487        pfn_t gap = base_diff - zones.info[z1].count;
    467488
    468489        zones.info[z1].count = base_diff + zones.info[z2].count;
     
    492513                    zones.info[z2].frames[i];
    493514        }
     515
     516        /*
     517         * Mark the gap between the original zones as unavailable.
     518         */
     519
     520        for (size_t i = 0; i < gap; i++) {
     521                zone_mark_unavailable(&zones.info[z1], old_z1->count + i);
     522        }
    494523}
    495524
     
    518547
    519548        for (size_t i = 0; i < cframes; i++)
    520                 (void) zone_frame_free(&zones.info[znum],
     549                zone_mark_available(&zones.info[znum],
    521550                    pfn - zones.info[znum].base + i);
    522551}
Note: See TracChangeset for help on using the changeset viewer.