protecting the memory
protecting the memory
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
thanks
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:protecting the memory
- 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.
- 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.
- Colonel Kernel
- Member
- Posts: 1437
- Joined: Tue Oct 17, 2006 6:06 pm
- Location: Vancouver, BC, Canada
- Contact:
Re:protecting the memory
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".
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:
- Too much overtime at work
- Got married
- My brain got stuck in an infinite loop while trying to design the memory manager
Re:protecting the memory
Protection can also be done through segmentation if used in your kernel.
Re:protecting the memory
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
Thanks guys
Re:protecting the memory
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.)
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:protecting the memory
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 wrote: I've now two GDTs, one for my kernel and one for userland.
Re:protecting the memory
Hi,
Cheers,
Brendan
I think you mean you've got 2 GDT entries (or 2 seperate segments), not 2 seperate GDTs .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
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.
Re:protecting the memory
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
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
Re:protecting the memory
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.
Re:protecting the memory
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.
Segments are fun ;)
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();
}
Re:protecting the memory
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?
Re:protecting the memory
No.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?
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.