I have been thinking on how an app could be "perfectly" isolated from the rest of the system. Now I know we will never achieve "perfect" in practice, but in theory, how could one go about it? I put together a few thoughts:
- IMHO the security that we are talking about has to be on the lowest possible level or in other words the only place that software cannot circumvent: hardware.
I am not advocating against security restrictions on higher levels, but since with higher level the complexity also rises, there will be security holes and someone will find them.
Now by hardware I mean of course the kernel-mode of the processor and its rings.
- I have looked on the various system calls of different operating systems and here again I see that there is already a huge amount of complexity in the number of system calls. If I were to create a sandbox, I would reduce the system calls to the absolute minimum required.
Here it is worth mentioning, that the apps that are supposed to run in this sandbox can by any means be implemented/built specifically for the sandbox. I do not want to introduce the requirement to be able to port existing applications into this sandbox!
So to have something we can agree on lets say the apps in the sandbox need:
- timing (Edit in response to @Pascal: time & date, hardware timers)
- reading / writing / creating / deleting files (no directory modification required)
- display (specifically opengl)
Of course those need to be restricted too: There will be a supervisor process that decides to which hosts the sandboxed process may connect and which files it may see and change and to which part of the screen it may draw.
- In C it is common practice to call functions with a pointer (or address) to a range in memory (e.g. an array or a string) and a number of bytes to read/write. When designing the system calls for the sandbox, I would go a way that is more common in higher level programming languages: every pointer must point to a struct that first contains the datatype of the memory range and it's size. Also I would only allow ranges in memory that have been accquired by calling one of the system calls, e.g. the system call will always know what it is working with and will fail if it is not given something already known to it in the first place (including a safe storage/copy of the the type and size information so that the kernel cannot be tricked into writing/reading outside of range).
As you probably guessed I made a few assumptions that would need verification. I am restricting those assumptions to the major OSs: Linux, Windows, MacOS, Android, iOS. PIU stands for Process in usermode (= not kernel mode). So here goes: Is it true that
- A PIU can only ever read/write its own memory never any other unless through system calls?
- A PIU can only ever access the harddrives through system calls?
- A PIU can only ever access the network through system calls?
- A PIU can only ever access any other hardware using system calls?
- When forking a process I can disable/remove/replace each and every system call?
- There is no way for a PIU to use any other system call then the ones I defined/allowed when forking?
- In a custom system call (= inside kernel mode) I can use the original system calls directly (without using interrupts)?
So far if all my assumptions are correct I would (theoretically) be able to create a "perfectly" safe sandbox. There is one area though I have absolutely no feel for: display.
How does opengl work? Does it directly talk to the graphics card or does it use system calls as well? Can something running on the GPU affect other graphical applications? Can I draw to any area of the screen or can that be restricted? Is the GPU somewhat connected to the current CPU mode (kernel/user)?
When answering this question please refrain from arguing that one should not replace system calls or one should use this or that existing sandbox/vm implementation. If we talk about the replacement of system calls please tell me what security and performance implications that might have and if we talk about existing sandbox implementations tell me how they solve certain problems that are related to the question or how certain malware circumvented their security mechanisms.