protecting the memory

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
Poseidon

protecting the memory

Post by Poseidon »

what is the best way to prevent my user tasks from accessing my kernel code? my kernelstuff runs above 0xC000000, below that is userland ;)

thanks :)
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:protecting the memory

Post by Pype.Clicker »

- you may program the 'directory entries' for your kernel so that they have the U bit cleared.
- you should have all page entries in kernel space with U bit cleared, btw
- you may (or may not) like to have user-level code and data segment limitted so that they cannot reach whatever beyond 0xC0000000 anyway.
User avatar
Colonel Kernel
Member
Member
Posts: 1437
Joined: Tue Oct 17, 2006 6:06 pm
Location: Vancouver, BC, Canada
Contact:

Re:protecting the memory

Post by Colonel Kernel »

Mark your kernel pages as "supervisor" by clearing the U/S bit (bit 2) in all the necessary page table entries and/or page directory entries (I think if you clear the bit in a page directory entry you can effectively protect an entire page table's worth of pages at once).

If you have Volume 3 of the Intel manuals, read section 4.11 on "Page-Level Protection".
Top three reasons why my OS project died:
  1. Too much overtime at work
  2. Got married
  3. My brain got stuck in an infinite loop while trying to design the memory manager
Don't let this happen to you!
DruG5t0r3

Re:protecting the memory

Post by DruG5t0r3 »

Protection can also be done through segmentation if used in your kernel.
Poseidon

Re:protecting the memory

Post by Poseidon »

I've now two GDTs, one for my kernel and one for userland. That one for userland has a limit with stops at the end of the userspace. It crashes fine when it tries to call to the kernel ;D


Thanks guys :)
mrd

Re:protecting the memory

Post by mrd »

You may use callgates to modify the segment selector (and hence activate the appropriate segment) before the call is actually made. Callgates were introduced with IA-32 just for this purpose. They take some more time than a normal call (iirc something like 30 clocks instead of 1.)
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:protecting the memory

Post by Pype.Clicker »

Poseidon wrote: I've now two GDTs, one for my kernel and one for userland.
Two GDTs ?? ?? kinda weird idea ... You can simply have DPL3 segments and DPL0 segments in the _Same_ GDT and restrict the limit of those DPL3 segments.
Poseidon

Re:protecting the memory

Post by Poseidon »

How can i do that?
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re:protecting the memory

Post by Brendan »

Hi,
Poseidon wrote: I've now two GDTs, one for my kernel and one for userland. That one for userland has a limit with stops at the end of the userspace. It crashes fine when it tries to call to the kernel ;D
I think you mean you've got 2 GDT entries (or 2 seperate segments), not 2 seperate GDTs :).


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
DruG5t0r3

Re:protecting the memory

Post by DruG5t0r3 »

You guys got me confused here...

I think you actually mean you have two GDTRs not GDT pointing to 2 different GDTs (one for kernel, one for user land).

And that isn't necessary since you can do it easily by setting the kernel segment descriptors to CPL 0 and user land to CPL > 0
Poseidon

Re:protecting the memory

Post by Poseidon »

I have two GDTs, when I go to userland, I load the second limited one. When I go back to my kernel, I load the kernel GDT, which has full memory access.
mrd

Re:protecting the memory

Post by mrd »

You only need one GDT. The GDT holds descriptors. Your segment registers (DS,ES,SS,..) point to them. If you want to change what segment is loaded, just point to another descriptor. The DPL (Descriptor Privilege Level) setting within the descriptor in the GDT lets you specify what CPL levels have access to the descriptor.

Use CALLGATES to load a higher-privileged CS (and hence raising your current CPL within the kernel function). When you ret from the function, the old CPL will be restored, keeping your descriptor security intact. Callgates contain the entry point of the function as well, so a malicious userland app can't raise CPL to execute their own malicious code. The Intel manuals detail this well.

If you need to change DS for using the kernel function, you'll need a kernel-level wrapper function/macro, which modifies DS before and after the call. e.g.

Code: Select all

user_func()
{
   my_kernel_fn();
}

my_kernel_fn()
{
   KERNEL_ENTRY();
   ..blah..
   KERNEL_EXIT();
}
Segments are fun ;)
Poseidon

Re:protecting the memory

Post by Poseidon »

i already have a system call system, using an interrupt. I will implement now with extra entries, but can't a process just change its segmentpointers and jump in my kernel and mess the system up?
Ushma

Re:protecting the memory

Post by Ushma »

Poseidon wrote: i already have a system call system, using an interrupt. I will implement now with extra entries, but can't a process just change its segmentpointers and jump in my kernel and mess the system up?
No.

When loading a segment register, the CPU verifies that the code that made the attempt has the appropriate privileges. Ring 3 code cannot load a segment register with a descriptor of privilege level 0. That's the whole reason call gates or an interrupt is needed. You can't upgrade privileges by loading a segment register, only downgrade them.
Post Reply