Exercise 3: A Reused Physical Frame Leaks Old Data — Possible Solution ==================================================================== THE TEST ------------------------------ mem = PhysicalMemoryFramed(num_frames=4) pt_a = PageTable(page_size=64) pfn = mem.alloc_frame() pt_a.map_page(vpn=0, pfn=pfn) secret_addr = pt_a.translate(0) mem.data[secret_addr:secret_addr+6] = b'SECRET' mem.free_frame(pfn) # process A 'exits' pt_b = PageTable(page_size=64) pfn_new = mem.alloc_frame() # process B gets a frame -- possibly the SAME one pt_b.map_page(vpn=0, pfn=pfn_new) new_addr = pt_b.translate(0) leftover = bytes(mem.data[new_addr:new_addr+6]) RESULT ------------------------------ process A's old frame: 0 process B's new frame: 0 process B reads its own freshly-mapped page BEFORE writing anything: b'SECRET' Process B's own newly-mapped page -- which it has never written a single byte to -- already contains 'SECRET', the exact data process A wrote before exiting. WHY THIS HAPPENS, HONESTLY ------------------------------ alloc_frame() returns min(self.free_frames) -- the lowest-numbered currently-free frame, for deterministic testing. Since process A's frame (0) was the only frame ever freed by the time process B requests one, process B is handed that exact same frame back. Nothing in free_frame() or alloc_frame() ever touches the CONTENTS of a frame -- both functions only ever add or remove a frame number from free_frames, a plain set of integers. The bytearray itself is never zeroed, cleared, or overwritten as part of freeing or reallocating a frame. WHY THIS IS A REAL FINDING, NOT SOMETHING TO PATCH QUIETLY ------------------------------ This is deliberately reported as an honest finding rather than silently fixed, because it's exactly the kind of real vulnerability that has affected actual operating systems: a new process reading memory a previous, unrelated process left behind -- potentially including passwords, cryptographic keys, or any other sensitive data that process never intended to share. Real kernels solve this by zeroing a frame's own contents before handing it to a new owner (or, more efficiently, using copy-on-write with a shared, permanently-zero page as the default), which this course could add but doesn't in this specific chapter -- the finding is the point, not a patched-over version of it. WHY THIS WORKS AS AN ANSWER ------------------------------ Deliberately writing recognizable data, freeing its frame, and then reading that same physical frame back through a completely different page table -- before writing anything new to it -- makes the leak concrete and undeniable rather than a theoretical possibility, demonstrating precisely why "just track which frames are free" is not the same guarantee as "a freed frame's own old data is gone."