4 ms·
CPU bugs are extremely rare compared to software bugs. Like, millions to billions of times less likely. CPU bugs are news, software bugs are Tuesday. You might
by Veserv 3y ago
CPU bugs are extremely rare compared to software bugs. Like, millions to billions of times less likely. CPU bugs are news, software bugs are Tuesday. You might as well argue that a steel box protects its contents no better than a cardboard box because who knows, maybe a meteor will land on the box so steel is no better than cardboard. You can not just dismiss factors of millions on feelings.
Again, you are talking about machine code plus OS ensembles. The machine code can not access a filesystem or files unless the OS allows it just like your Java example. You can pass precisely a file or stream to your program if your OS supports such a notion. Even Linux, as insecure as it is, can express your notion of streams with pipes to input files. The insecurity of machine code on Linux is an artifact of OS design providing things like an innate right for processes to access a file system, not anything to do with the machine code.
Containerisation does not provide a security boundary and is difficult because the OS design and the programs targeting that OS API are not designed to operate in that way. Such a program would not operate correctly in your Java model either because the program only functions when there is a global filesystem conforming to the implicit requirements of the programs. As soon as you modify that program to operate correctly according to your model it then becomes trivial to precisely provide the same dependencies to the machine code variant as long as your OS supports such abstractions.
Every single abstraction you are describing can be expressed as a OS concept at the cost of performance. An argument can be made that the performance impacts are too high, so commercial designs sacrifice protection and that by supporting language-level protections you recover enough performance to enable secure designs. But, in that case you would expect proof-of-concepts demonstrating feasibility and proven protection in the equivalent, but non-performant model, and only then optimizing the performance by leveraging language-level protections. Until that is done there is precisely zero reason to believe any language-level protections are robust.
To say it again, language-level protections are strictly more powerful than OS/machine code level protections. If you can prove them then you can trivially prove any OS level protection by jus allowing less fine separation. If you can not demonstrate weaker results like a unhackable OS design, then you do not have a robust language-level solution. It is like proving P != NP without proving something easier like P != PSPACE.
Language level solutions would be awesome, but they are not a stepping stone to protection, they are the end result once you have already mastered security.
- James_K 3y ago> can express your notion of streams with pipes to input files Not if you've disabled syscalls. As it turns out, process isolation is incredibly complex. Millions of lines of code between in kernels and container systems are dedicated to this issue that could be trivially solved with a software based approach, if only files were distributed in a source format. > The insecurity of machine code on Linux is an artifact of OS design providing things like an innate right for processes to access a file system, not anything to do with the machine code This design decision is intimately related to the format in which code is distributed, the linking and loading of ELF files, as well as the compilation of software. Otherwise containerisation would be as simple as giving each process a private file-system. > As soon as you modify that program to operate correctly according to your model it then becomes trivial to precisely provide the same dependencies to the machine code variant as long as your OS supports such abstractions. Okay, so you take some information from the source and add it to the machine code to solve the problem. Let's say another problem comes up and you do that again. The limit of the process is source-based distribution, and maybe some kind of cached IR (similar to what Java does). The more information you add to machine code, the less it resembles machine code. But when you modify the machine code format, you have to modify your operating system, which is wasteful when this problem has been effectively solved in user-space for decades. The argument against this is always "we can modify the OS to achieve the same thing as you could without the OS", which is always true but not exactly useful. Why is it better to implement these things in a complicated way in the operating system? Modern computers are fast enough to JIT compile Java software, so I see no reason to still use binary formats which require all this extra effort. > CPU bugs are extremely rare compared to software bugs You should be comparing to the kind of software bug you are mentioning here. Specifically one where a bit of basically interpreted code that can't even read or write files somehow gains total control over the process its running in. Preventing this is so simple that it just isn't logical for such a bug to exist. You might think it likely because of the frequency of bugs in operating systems that use binary programs, but that is because securing a binary program is much more complicated than securing one which is interpreted. > But, in that case you would expect proof-of-concepts demonstrating feasibility and proven protection in the equivalent, but non-performant model, and only then optimizing the performance by leveraging language-level protections. Until that is done there is precisely zero reason to believe any language-level protections are robust. Well using Haskell as an easy example here, the language is fairly performant, and you know all functions without side-effects are safe. By redefining the IO monad, you can then at a software level control every file access that the program attempts and guarantee that it does nothing malicious at minimal overhead. Obviously if I were implementing a practical version of this, I wouldn't chose Haskell for it, but the point still stands that Haskell proves the feasibility of such a system.