Page 2 of 2

Re:Device drivers <-> kernel protection

Posted: Tue May 11, 2004 4:43 am
by Brendan
Hi,
Pype.Clicker wrote: Now, consider this: in order to perform a UtlraDMA disk request, i need to write the physical address of the target memory area into the memory-mapped 'buffer' of the busmaster device. How would the microkernel ensure that the disk driver isn't evilly writing a microkernel frame number there, or a random number (likely to come from another process) ?

Same for ISA DMA ports: the Soundblaster driver shouldn't be allowed to toy with them directly, but rather use a trusted service to program the DMA on its behalf, no ?
In general you're right, but some things can be done to minimize the risk. In my OS the only way that a device driver can get a physical address is to use the "void *alloc_DMA_buffer(linear_address, pages)" function. It doesn't prevent all DMA problems, but if the device driver can't keep track of it's own buffer it wouldn't pass basic beta testing. It does mean that a device driver can't be tricked into using incorrect physical address ranges by external code. For ISA DMA the kernel can check that the DMA transfer is going to a buffer that was allocated specifically for DMA (my kernel sets a flag in the page table entries).
And as such DMA things cannot be reliably performed at user level, why not simply moving the whole 'lower level' part of the driver at the kernel level ? What sense does it make to have a user-level driver that need a kernel plugin to make its job ?
Using a kernel plugin wouldn't make any sense at all (most programmers would plugin the entire driver instead). While it's not 100% bullet-proof it's a lot better than a wet paper bag (device drivers at CPL=0) in terms of security, as long as you can accept the performance implications.

BTW if you where a malicious virus writer how much fun could you have with win95's VxD's? I'd start by re-directing the interrupt vectors for the API's...

Cheers,

Brendan

Re:Device drivers <-> kernel protection

Posted: Tue May 11, 2004 5:40 am
by Candy
Brendan wrote: In general you're right, but some things can be done to minimize the risk. In my OS the only way that a device driver can get a physical address is to use the "void *alloc_DMA_buffer(linear_address, pages)" function. It doesn't prevent all DMA problems, but if the device driver can't keep track of it's own buffer it wouldn't pass basic beta testing.
Mallory wrote: void *buffer = (void *)urandom() & 0xFFFFF000;
read_data_at_random(buffer);
So spoke Mallory. The trick is old as ages ;)

The idea is that you protect the module from overwriting any data. That means, you either use the ostrich algorithm (stick your head in the sand and pretend it doesn't exist), or you protect it properly, which means microkernel approach, dumping the code in user space and actually preventing these things. You're using a hybrid, which is like locking your front door while leaving the back door open.
Using a kernel plugin wouldn't make any sense at all (most programmers would plugin the entire driver instead). While it's not 100% bullet-proof it's a lot better than a wet paper bag (device drivers at CPL=0) in terms of security, as long as you can accept the performance implications.
Limit the size of the plugin, require all plugins to be thoroughly checked. Require them to put as least as possible in the plugin.

Or, just use the kernel area functions :)

Re:Device drivers <-> kernel protection

Posted: Tue May 11, 2004 6:30 am
by Solar
I read several papers on "downloadable driver cores", where those parts of the driver that have to run in kernel space have to be expressed in some form of metalanguage, which upon "downloading" it to kernel space, is compiled to binary after thorough sanity checking.

That's language theory, and way out of my field of expertise; I just thought I'd throw it in since it's a tidbit of idea that seems to belong in this thread.

Re:Device drivers <-> kernel protection

Posted: Tue May 11, 2004 7:05 am
by Brendan
Hi,
Candy wrote: The idea is that you protect the module from overwriting any data. That means, you either use the ostrich algorithm (stick your head in the sand and pretend it doesn't exist), or you protect it properly, which means microkernel approach, dumping the code in user space and actually preventing these things. You're using a hybrid, which is like locking your front door while leaving the back door open.
Here's a list:
- Performance
- Security
- Flexibility/power
- Features
- Programming environment simplicity
- Memory use
- Development time

Improve one and you'll make the others worse. Everything is a trade-off... Prioritizing them is left as an exercise for the reader ;)
Limit the size of the plugin, require all plugins to be thoroughly checked. Require them to put as least as possible in the plugin.
Increase security and make environment simplicity, development time, performance (slightly) and memory use (slightly) worse?

Unless I personally check every kernel plugin's source I can't be sure it doesn't contain malicious and/or buggy code, and that would take too long (if my OS ever gets large enough for security to be a concern).

During the course of my current rewrite I will make sure that only device drivers can use some of the kernel functions (IO port access, DMA buffer allocation, special physical memory area mappings, etc).


Cheers,

Brendan

Re:Device drivers <-> kernel protection

Posted: Tue May 11, 2004 7:33 am
by DennisCGc
Here's a list:
- Performance
- Security
- Flexibility/power
- Features
- Programming environment simplicity
- Memory use
- Development time

Improve one and you'll make the others worse. Everything is a trade-off... Prioritizing them is left as an exercise for the reader ;)
That's called: OS Design :o ;)

Re:Device drivers <-> kernel protection

Posted: Tue May 11, 2004 8:16 am
by Pype.Clicker
Solar wrote: I read several papers on "downloadable driver cores", where those parts of the driver that have to run in kernel space have to be expressed in some form of metalanguage, which upon "downloading" it to kernel space, is compiled to binary after thorough sanity checking.

That's language theory, and way out of my field of expertise; I just thought I'd throw it in since it's a tidbit of idea that seems to belong in this thread.
This is indeed possible, though for instance making sure UDMA programming will not overwrite kernel frames require the kernel to have been told by a 'trusted' source that register #i in the PCI block is the starting frame address... otherwise it couldn't perform sanity-check on the code.

There's also what's called "proof-carrying code" where the code is given as compiled binaries together with a list of data that shows the evidence the code doesn't enfringe a set of rules.

Imho, checking if a collection of small plugins performing only basic functions is safe is manageable, while checking if something as huge as the Linux Kernel is safe would be a nightmare ...