A Skeleton Key of Unknown Strength (CVE-2015-7547)
dankaminsky.com
dankaminsky.com
Look: not only is this flaw not unprecedented, like, at all, but just last year we had a glibc vulnerability in gethostbyname() --- the most common libc DNS resolution function. You may remember the flaw by its brand name, "GHOST".
GHOST did not ruin the Internet or justify what I can best describe as 4000 words of concerned back-patting. And it was exploitable on day one!
Just patch the stupid thing, like everything else, and get on with your life.
I do object strongly to the bit at the end, about how ASLR, NX, CFG, &c are effective only at showing us who the best exploit developers are. Horse. Shit. There are today memory corruption bugs that are not exploitable because of runtime constraints. Moreover, when Linux and OS X bugs turn out to be widely and reliably exploitable, the reason tends to be that they hit something that isn't fully covered by runtime protections.
If you want to argue that critical, exposed network services shouldn't be written in C in 2016, you'll get no argument from me, or, for that matter, 98% of Hacker News. We should definitely get moving on porting stuff like DNS servers to things like Go and Rust.
Not 98% of Hacker News. There are an awful lot of people who think modern C++ is memory safe.
C doesn't let you do that. It's just incapable, and it's a handicap that leads to bad APIs and bad client code. Take gethostbyname() as a historical example. It returns a pointer to static data, which avoids memory leaks at the cost of being thread-unsafe. Want a fix? use gethostbyname_r()... ok, great, except now you're dealing with a function with six parameters and have even more ways to shoot yourself in the foot. Ok well, they're both deprecated anyway... use getaddrinfo()... just don't forget to use freeaddrinfo() because this function allocates a linked list. So don't forget to check for null pointers as you enumerate it. C++ brings value semantics, iterators, and RAII to table and these problems largely go away.
All this is why C++ is better than C. In C++ you can have memory safety, thread safety, type safety, and a simple API. It's not perfect, and it's not easy, designing APIs never is, but at least it's a remote possibility.
No, it doesn't, because it isn't memory safe.
> All this is why C++ is better than C. In C++ you can have memory safety, thread safety, type safety, and a simple API.
No, you can't. C++ is not memory safe. Use after free happens in C++ all the time, because smart pointers do not protect you from dangling pointers and null pointer dereference, among other things.
Instead of copy and pasting examples to show this, I'll just link to other posts of mine from the past two months: https://news.ycombinator.com/item?id=11111987, https://news.ycombinator.com/item?id=11054630, https://news.ycombinator.com/item?id=11055020, https://news.ycombinator.com/item?id=10819501.
I never claimed C++ statically enforced memory safety. Clearly that can't happen while its a superset of C. I just claim that it's steadily reaching the point where the most concise and elegant code with the best API is the safest.
And I'd argue that's the problem with C. The language is too weak to write safe code concisely, so you end up with too much cognitive load, get lazy, and then end up with sprawling unauditable messes like we see in glibc lately.
My concerns are not merely organizational. I do think we
need to start investing significantly more in mitigation
technologies that operate before memory corruption has
occurred. ASLR, NX, Control Flow Guard – all of these
technologies are greatly impressive, at showing us who
our greatly impressive hackers are. They’re not actually
stopping code execution from being possible. They’re
just not.
Somewhere between base arithmetic and x86 is a sandbox
people can’t just walk in and out of. To put it bluntly,
if this code had been written in JavaScript – yes, really –
it wouldn’t have been vulnerable. Even if this network
exposed code remained in C, and was just compiled to
JavaScript via Emscripten, it still would not have been
vulnerable. Efficiently microsandboxing individual
codepaths is a thing we should start exploring. What can
we do to the software we deploy, at what cost, to actually
make exploitation of software flaws actually impossible, as
opposed to merely difficult?What I mean is, we solve one vector, but is always another (logic flaw vs stack flaw). Is there a truly "perfect" way to code? Is there any academic philosophy that is impossible to exploit?
I ask from a very ignorant perspective. I can barely program.
Simple, forgotten example: You can't just patch a running OS kernel from an application program anymore. There's hardware in the CPU called an MMU, or Memory Management Unit, which inspects all attempts to access memory, read or write, and checks them against a policy the kernel set which aims to disallow all unsafe memory accesses. (This is like nine kinds of oversimplified, but it's not actually wrong... ) The MMU will alert the kernel if an application program attempts to access memory in a way contrary to policy, and the kernel typically kills the program dead right there. That's what a segfault is.
My point is, prior to the MMU, the only possible response to "Applications can modify running OS kernels willy-nilly." was "Don't do that then." There was no way to enforce that policy. That's why MS-DOS, which ran pretty much exclusively on hardware either without an MMU or with the MMU disabled, had no effective security policy: Any application could modify the only thing attempting to enforce that policy at any time, and nothing could stop it. In the immortal words of Bokosuka Wars, "WOW ! YOU LOSE !"
We take MMUs for granted now. We take OSes which use MMUs for granted now. We no longer have to rely on the care and kind nature of strangers to enforce the basic policy.
The trade-off is speed: Adding an MMU to the path to RAM inevitably makes accessing RAM slower. There's no way around it. We see it as a rock-simple win-win tradeoff that we've almost forgotten that there even is a tradeoff, but our computers would run faster without MMUs. We've just, as a hardware and software culture, decided that it's worth it.
So. The discussion here is, "Which other tradeoffs are worth it?" Because there are other technologies we could adopt, hardware and software and a mix of both, which could completely seal off other classes of attack vectors, and we need to decide which of those technologies are worth implementing.
Tomorrow we will take terabytes & terahertz for granted.
I see no end. Old-school vs new-school ad-infinitum.
Now its compilers are praised for speed, given 30 years of optimization efforts.
http://talk.commonmark.org/t/make-commonmark-safe-by-default...
The proposal being made, as per my understanding, is that by default CommonMark-compliant markdown should be evaluated in a "safe" mode--escaping html and whitelisting url formats--and that compliance with this behavior among interpreters should be enforced by the validation tools provided by CommonMark. This would conceivably result in CommonMark markdown becoming an easy default way to eliminate the possibility of XSS on sites that accept user-input in the form of comments, etc.
Unfortunately, the conclusion to the discussion seems to have been, "although it seems to be possible to trivially eliminate XSS attacks from user input using 'safe' markdown, that's an implementation detail so it's not the job of the standard".
I only found this yesterday, and I'm still trying to understand the current stance the project is taking on this (I don't know if it has changed), but I think it underlines how important--and uncommon--it is for people to adopt an attitude of "if we can eliminate a class of attack through a formalism or technology, let's do it."
If CommonMark were to adopt this approach, it could make the security advice given for processing user input as simple as "use a CommonMark-compliant markdown interpreter in the default 'safe' mode", whereas now it seems to be, "pick the right markdown interpreter that has a 'safe' mode you can trust, be sure to configure it properly, and then for good measure take the computationally expensive step of running your generated HTML through a sanitizer."
</s>
wat
The turtles need to end somewhere --- at the end of the day, you are writing something that becomes machine code, and you've lost the benefit of your high-level abstractions. The glibc bug is a perfect example --- glibc is an abstraction layer to make life safer that virtually all (excluding Debian and some other distros, but near enough) Linux code links against.
No matter where you put it, your stack is going to have a layer like that in it somewhere, and sometimes you're going to find bugs in that layer. Maybe next time it's a bug in your C-to-JS compiler that emits insecure code, or a bug in your `microsandboxing framework` that allows RCE. Shit, maybe there's a bug in your CPU architecture that allows RCE.
The glibc bug is an example of the sort of incredibly rare screwup you can't escape no matter how hard you try, and we're fortunate that 'the good guys' caught it before it had a chance to develop in the wild.
For example, I'm exploring ending use after free bugs by just not freeing memory. This sounds ridiculous until you realize that on 64 bit, leaking virtual memory (and therefore never recycling pointers) is actually not an insane idea, particularly for browsers that get to kill processes outright because they feel like it. Also, lots of UaF in there.
(I also don't think yours is a good plan, but I'll wait for you to publish more details before criticizing it further).
At the end of the day hard bounds checking (however slow it might be) also falls into this category of "approaches that do not try to survive falling into undefined states". I'm not saying ASLR et al isn't useful, just that we should put more energy intostaying within well defined states.
That's ultimately what "better" languages promise, after all. I'm curious if there are approaches that don't require rewrites, and very interested in actually measuring what does and doesn't absolutely suppress vulnerability, at what performance cost. We're not doing enough of that.
That environment is not going to be programmable in C, unless you want a huge performance hit.
We have options we're not exploring.
EDIT: From AWS (https://aws.amazon.com/security/security-bulletins/cve-2015-...):
""" We have reviewed the issues described in CVE-2015-7547 and have determined that AWS Services are largely not affected. The only exception is customers using Amazon EC2 who’ve modified their configurations to use non-AWS DNS infrastructure should update their Linux environments immediately following directions provided by their Linux distribution. EC2 customers using the AWS DNS infrastructure are unaffected and don’t need to take any action. """
That's how a well-configured server works by definition. How much do you want to bet your server's well-configured?
Rough estimate I'd say it's 50/50 whether I patch manually or allow unattended patches.
I'd be very, very careful making broad "interpreted language X would prevent this bug" statements - not only is it dependent on the VM not having remotely-exploitable issues, there's also the matter of VM-to-host leakage. For instance, it's possible to exploit the row-hammer behavior of the host system's DRAM from Javascript:
However, we've got lots and lots of common flaws that our present coding patterns aren't quite covering. This exact code written in JS wouldn't have been a problem. It wouldn't have been a problem even if it was just transpiled to JS and kept in a well defined sandbox (which isn't how we're doing sandboxing right now).
I imagine this only if these devices can't be disconnected. Life creates its own existential threats in a lot of parts of the "network", but they are contained or fixed eventually. Diversity is the key, and even though all life we know has the same fundamental building blocks, so far it worked out. The internet is not that fundamentally different. So instead of working on ways to increase maintenance, continue to make the internet a highly diverse place.
"... but we can set the tc "Truncation" bit to force an upgrade to the protocol with more bandwidth."
dnsq does not do TCP queries. Sorry.
I also developed a few systems for resolving all the names I needed in advance so I did not need to use DNS at all, except when periodically updating the list of IP addresses. I am glad I did that work. (But nowadays there are resources like scans.io)
When someone publishes a vulnerability in dnsq from djbdns (it does not send recursive requests), I'll have to dream up another solution to the problem of "DNS". I doubt that's going to happen, but I could be wrong.
There are too many other easier targets.
2. Supporting TCP queries is not optional. Some DNS servers will refuse to answer certain types of queries over UDP. In particular, ANY queries are often TCP-only, as they are a potential vector for DNS amplification attacks.
2. This is a personal solution. I am not writing software for anyone else. I do not have to use TCP for DNS queries and I have never found an authoritative server that refused to accept a UDP query. dnsq does not do TCP queries; I guess you could complain to the author he's violating some rule? If I am not mistaken, amplification problems happen because of ideas like open resolvers and enormous UDP packets, like those required for EDNS0 and DNSSEC. I am not a user of either of those ideas.