Page 1 of 1

"Key"-based memory protection

Posted: Tue Sep 01, 2009 10:21 pm
by Troy Martin
Hey all,

I was browsing wikipedia and stumbled upon this interesting thing about a special type of memory protection. It uses, from what I can tell, a chunk of memory is given a unique identification key to be used in conjunction with an application's assigned key. I'm guessing applications are given a key based on which blocks are free (probably size as well) which restricts the blocks of memory it can access.

So here's my question: how feasible would it be to implement "key protection", as I like to call it, in software? I would assume that under the x86, one could use the debug registers to restrict access, but there's a problem with that. The debug registers can either fire a breakpoint on the access of one, two, or four bytes only. No more. Damn.

So how else would it be done? How portable would it be? Is it worth to use instead of segmentation or (ye-eech) paging? Would it be anything else than just a "cool idea"?

I'd love to hear your thoughts on this.

Cheers,
--Troy

Re: "Key"-based memory protection

Posted: Tue Sep 01, 2009 10:48 pm
by NickJohnson
It seems like just another way to implement paging (protection wise, not flexibility wise), except with one master table for all physical memory instead of separate tables for virtual address spaces. Why wouldn't you use paging, which has hardware acceleration (probably thousands of times faster than breakpoint interrupting on *every memory access*) and gives a great virtual address space abstraction that removes the need for any relocation? You would really need hardware support to make it practical. Nobody implements a MMU in software for a reason.

Paging is not that hard, if that's what you're trying to avoid - I've got my entire memory manager in about 150 lines of C. The trick is using recursive mapping for everything and avoiding the kernel heap entirely.

Re: "Key"-based memory protection

Posted: Wed Sep 02, 2009 3:11 am
by jal
Troy Martin wrote:So here's my question: how feasible would it be to implement "key protection", as I like to call it, in software?
You can't unless you have managed code. And that goes for all types of memory protection: if it is not supported in hardware, you cannot enforce it by using software(1).

(1) Tricks like using debug registers or the like I also call "supported by hardware", although it is a bit of a grey area, as it is not hardware support for memory protection per se.


JAL

Re: "Key"-based memory protection

Posted: Wed Sep 02, 2009 7:52 am
by torshie
NickJohnson wrote: The trick is using recursive mapping for everything and avoiding the kernel heap entirely.
Hi,
What is recursive mapping, would you mind give more details on that?

Cheers
torshie

Re: "Key"-based memory protection

Posted: Wed Sep 02, 2009 11:15 am
by NickJohnson
torshie wrote:
NickJohnson wrote: The trick is using recursive mapping for everything and avoiding the kernel heap entirely.
Hi,
What is recursive mapping, would you mind give more details on that?

Cheers
torshie
The idea is to leverage the two-tiered page directory/table setup and the fact that a page directory is also a valid page table. Normally, you would have a page directory with a bunch of page tables in it. With recursive mapping, one of the page table positions points to the current page directory, so that the page directory is used both as a page directory *and* a page table that maps all of the currently used tables into a 4MB chunk of virtual memory.

Here's an example. Let's say you have a page directory at physical address 0x1000, and you also have a page table at physical address 0x2000 that has some mappings in it at the second-to-last position in the page directory. You map the page directory recursively in the last position within itself. The page directory would look like this (in nasm syntax):

Code: Select all

times 1022 dd 0x00000000
dd 0x00002003
dd 0x00001003
At address 0xFF800000, you will find the things mapped by the page table. Additionally, at 0xFFC00000, you will find all of the contents of the page tables pointed to in the page directory, if they exist: at 0xFFFFE000, you will find the contents of the page table, and at 0xFFFFF000, you will find the page directory itself.

This allows you to quickly find the contents of page tables, because they are in fixed positions and are addressed continguously, and appear when the page directory changes. It also means you don't have to keep track of anything but the physical address of the page direcotory, or even keep anything extra in the address space, and still perform all paging actions. That eliminates a lot of address space usage and the need for a virtual memory allocator entirely. You can also map other page directories in the current one, and access their tables' contents contiguously as well.

Here's a piece of my memory manager (all of the general page manipulation) that should give a good explanation as well, at least of the non-initialization part:

Code: Select all

ptbl_t *cmap = (void*) (PGE_MAP + 0x3FF000);
page_t *ctbl = (void*) PGE_MAP;

void page_touch(uint32_t page) {
	page &= ~0x3FFFFF;
	if (cmap[page >> 22] & PF_PRES) return;
	cmap[page >> 22] = frame_new() | (PF_PRES | PF_RW | PF_USER);
	pgclr(&ctbl[page >> 12]);
}

void page_set(uint32_t page, page_t value) {
	page &= ~0xFFF;
	if ((cmap[page >> 22] & PF_PRES) == 0) page_touch(page);
	ctbl[page >> 12] = value;
	asm volatile ("invlpg %0" :: "m" (page));
}

page_t page_get(uint32_t page) {
	return (cmap[page >> 22] & PF_PRES) ? ctbl[page >> 12] : 0;
}
PGE_MAP is a macro that is the base address of the recursive mapping in virtual memory (0xFFC00000 in my case). frame_new() gives the physical address of a new frame, and pgclr(x) is like memset(x, 0, 0x1000). PF_* are paging flags.