Glibc getaddrinfo stack-based buffer overflow
googleonlinesecurity.blogspot.com
googleonlinesecurity.blogspot.com
> "The vectors to trigger this buffer overflow are very common and can include ssh, sudo, and curl. We are confident that the exploitation vectors are diverse and widespread; we have not attempted to enumerate these vectors further."
> "Remote code execution is possible, but not straightforward. It requires bypassing the security mitigations present on the system, such as ASLR."
It is time for the bimonthly Internet security meltdown. Again. When they say that "exploitation vectors are diverse and widespread", they really mean it. Patch ASAP. This is a race; it is only a matter of time before criminals start automatically and systematically scanning every server on the internet for this, and you really really want to be patched before that happens.
Thinking a bit more long term, it's pretty clear at this point that we need to expunge all C language networking code from the world, replacing it with Rust or pretty much anything else. That's not sufficient by itself, but it is necessary, or else the periodic Internet security meltdowns won't ever stop.
But it's not hard to get a system to do a dns query. Sometimes even connecting to it will cause your ip to appear in the logs which are then sometimes reversed ip. But one could easily just create a webpage with img.src pointing to the host.
DNS being distributed could halt the attack upstream by patching their servers to stop the queries so any vulnerable clients won't get compromised even if they make the query.
Anybody connecting to a public network that pushes network settings may still be affected. For wifis with a capture portal (hotel wifi etc) you usually have to use the network-provided dns server.
It was already clear in 1961 when Burroughs used Algol and C wasn't even born.
It was clear when Hoare stated on his speech in 1980:
"Many years later we asked our customers whether they wished us to provide an option to switch off these checks in the interests of efficiency on production runs. Unanimously, they urged us not to - they already knew how frequently subscript errors occur on production runs where failure to detect them could be disastrous. I note with fear and horror that even in 1980, language designers and users have not learned this lesson. In any respectable branch of engineering, failure to observe such elementary precautions would have long been against the law."
I can quote lots of other security research papers since computers exist.
But then UNIX workstations took over the computing world, bringing C with them.
The Borland languages like many other that allowed for system programming in those days, allowed for disabling bounds checking, as Borland customers weren't like Hoare ones.
I never felt the need to disable them.
Yes they did had a few ms to the program execution, but nothing that would impact the user experience of the application.
This is one of the biggest problem in our industry, specially among C and its derived languages (C++, Objective-C), to micro-optimize each code line without any sort of measurement how it impacts the final application.
Of course there are cases where it really matters, like HPC, games and such, but those are a tiny portion of the software that gets written every day.
Time for the bimonthly Hacker News hour of C and C++ hate.
As much as I'd like to think Rust is a nice option for the future, everything leads me to believe that if it ever gets as widespread as C you will have the same caveats, because the main issue is not the language but the programmers using it.
No amount of hand holding and safety will prevent bad practices from being used when they prove efficient in one way or another (laziness is a real killer).
Yes, they are.
> We have no way to know as no modern language has the reach and widespread usage of something like C.
None needs to have that widespread usage for us to see this. Many bugs in C code causing big security issues are impossible to make in more modern programming languages. Sure, you can make other security issues, of course you can. But the net result is less security issues.
> the main issue is not the language but the programmers using it.
All bugs are caused by programmers making mistakes, but that doesn't mean the language isn't an issue. A language which requires more effort to write correct and secure programs is an inferior language. A language with a long list of situations where the compiler will silently invoke unpredictable behaviour, a list any programmer will sometimes fail to fully account for, is an inferior language.
https://blog.hboeck.de/archives/879-Safer-use-of-C-code-runn...
It is theoretically possible to use ASAN on glibc as well, but it's complicated and certainly not ready for any kind of production use.
Also although this is my work, it's far from clear to me whether using ASAN in production really is a useful thing. Practically I'd rather suggest looking at the safestack and CFI features of clang for production use instead.
grep -irn getaddrinfo .
./src/libstd/sys/common/net.rs:123: try!(cvt_gai(c::getaddrinfo(c_host.as_ptr(), ptr::null(), ptr::null(),
./src/libstd/sys/windows/c.rs:1235: pub fn getaddrinfo(node: const c_char, service: const c_char,
./src/libstd/sys/windows/net.rs:69:/// Provides the functionality of `cvt` for the return values of `getaddrinfo`
How many places doesn't rust source code use C structures or call C APIs?
In the rust source tree, run this:
grep -irn '[^a-zA-Z0-9]c::' . |wc
615 3143 56000
grep -irn 'extern "C"' . |wc 279 1719 23448Yes, Rust programs can be affected by this. But only because they call into C at a lower level, for the libc layer. If glibc was in Rust it would provide security to all application, including ssh or curl which aren't in Rust.
Also, extern "C" is for C FFI exports not calling C APIs. The world unanimously decided C FFI is the least common denominator, so its not like Rust can provide a different API with better safety hints.
Just as an ironic aside - C enthusiasts may even have switched to musl-libc already, and are not affected by bugs in glibc, while rust-loving people are vulnerable!
Also interesting, Go has for a long time supported using its own dns resolver instead of libc, but only recently in go 1.5 uses the go dns resolver by default on unix systems.
"C" to OS, Kernel, Computer Language, applications is like oxygen is to life on earth.
Yes, O2 causes fire from time to time, but you can't live without it.
There's the solution! Replace C with "C", a garbage-collected version of C! The quotes mean it's safe!
/s
Any language which has a toolchain which produce flat binaries or use link scripts to specify sections can potentially be used for kernel and os dev. Bonus points for a toolchain which can compile itself.
There are kernels written entirely in Rust with some assembly glue. Others are writing production embedded domain-specific OSes in Haskell, OCaml, etc. for real, mission-critical systems right now and have been doing so for the last 5-10 years.
C inherently or inadvertently leads to giant codebases and subtle bugs when used too liberally, as opposed to higher-level, statically-compiled languages like Haskell and others.
The main issue with legacy code is how we choose to either keep investing effort in putting fingers into the levees or try something new in an incremental fashion.
PS: I would like to see Go get with it and support non-usermode, self-hosted and embedded development without including a giant, hard-to-port runtime in everything.
seL4 was modeled in Haskell, then written in C. Then they used tools to verify that the Haskell models matched the C code.
Well, yes, the effort to replace even a small part of current code base with something perceived as "safe code" is huge. The re-factoring effort is so great that there is no doubt a significant number of new seurity problems wouldn't be created.
They would of course be different kind of problems. Not indexing errors, perhaps, but something we don't even know about. And justifiying this very large cost is not so easy.
You're talking about the forrest - while we're talking about how making trees from scratch is difficult and messed up no matter how you go about it.
At some point, you have to talk to the computer directly (aka "unsafely"). Things like bounds checking, garbage collection, and other runtime utilities sound like great ideas until they translate to significant monetary costs each month.
Not everything is as trivial as writing GUI glue code in a nice comfy language with a magical framework. Although, most of it is.
> it can't be safe at that low level without a performance penalty.
Many of Rust's safety guarantees come from compile-time checks that then do not have any runtime penalty.Yes, sometimes you still need unsafe, but even then, it's a superset, not a subset: a lot of safety checks still happen inside an unsafe block.
That said, I do think that building a libc in Rust would take a significant investment and I'm not sure who's going to even attempt it, if anyone.
But not bounds checks, which are unfortunately what you need with respect to buffer overflows.
[1]: http://doc.rust-lang.org/std/primitive.slice.html#method.get...
I do a lot of low-level Rust programming and a lot of low-level C programming. I don't know what the performance penalty you're claiming exists comes from. Can you elaborate as to the specific Rust features that you claim are slow?
(Incidentally, the project I'm working on right now in Rust beats all of the existing C competitors in performance by a lot.) :)
I was trying to highlight the fact that unsafe Rust and C are not that different when you're doing bitwise operations on bare metal.
I was wanted to drive the point that additional abstractions are undesirable at that low level unless they can be enforced at compile time. I'm concerned by some of the magical thinking being espoused in this thread about what's actually reasonable in terms of the trade offs you can make.
In other words I was talking about safety, not speed.
I'm glad to hear Rust is out performing C though. I just wish I had a better IDE than atom... Didn't you once mention Xcode support for Rust?
I re-read what I wrote and I fail to see where I attacked or even (God forbid) criticized Rust.
So far IME, the rust community is extremely defensive and antagonistic to anyone they perceive to have made the slightest criticism. It's immature and irritating. It's the only thing that really turns me off from fully embracing it.
I can't participate in a community that's fundamentally hostile to skepticism.
But previously you said "because it can't be safe at such a low level without a performance penalty" which clearly implies performance is part of your argument. This is what I was talking about in my other reply, which mentioned "without narrowing the scope or clarifying your intent".
> I re-read what I wrote and I fail to see where I attacked or even (God forbid) criticized Rust.
This is more about backing up claims with concrete examples. pcwalton is a Rust developer, I'm sure he would be very happy to hear a specific shortcoming he wasn't aware of, or was undervaluing. That's how improvements are made.
> So far IME, the rust community is extremely defensive and antagonistic to anyone they perceive to have made the slightest criticism. It's immature and irritating. It's the only thing that really turns me off from fully embracing it.
There may be some of that, but I also see a lot of rust community members trying to explain where people's assumptions are wrong, and it being taken as being antagonistic. The fact that Rust has some compile time checking that could actually make some of the low-level code faster is what I think is being alluded to by pcwalton. Of course there will be things that rust won't catch, and will need to be done in both C and rust, and there's things that other languages may catch that rust doesn't and vice-versa.
> I can't participate in a community that's fundamentally hostile to skepticism.
That's an interesting way to put it. You've made assertions, and when asked for clarification or evidence, began your response by calling the other commentor's motives into question (is it a reasoned response, or was it overly emotional because they were "defensive"). Asking for evidence of assertions is skepticism, and to balk in face of requests to do so is actually what I would consider being defensive.
To be absolutely clear, I don't think you would have been downvoted if you didn't start your reply with "A little defensive, maybe?". I didn't downvote you, but my initial assumption was that the downvoting I saw was because of that.
I guess I felt I was being attacked for a point that I wasn't even trying to make. That is, I was responding to you under the impression that I had clearly said something differently than what was interpreted. All without taking the time to read over my own post carefully. Then I got overly emotional which resulted in us talking past each other unproductively and rude remarks on my part.
So I'm sorry for being a melodramatic jerk yesterday. I am actively working on my self control and civility, but I definitely made a mistake here. Hope you have a good day.
Also, my statement was not that general or vague. Maybe it could have been clearer, but it appears to have also been misinterpreted by pcwalton.
A bit higher up:
It was clear when Hoare stated on his speech in 1980:
"Many years later we asked our customers whether they wished us to provide an option to switch off these checks in the interests of efficiency on production runs. Unanimously, they urged us not to - they already knew how frequently subscript errors occur on production runs where failure to detect them could be disastrous. I note with fear and horror that even in 1980, language designers and users have not learned this lesson. In any respectable branch of engineering, failure to observe such elementary precautions would have long been against the law."
- https://news.ycombinator.com/item?id=11110456
... which directly contradicts the "no one" part.
Speed is all that matters, I actually learned that from Graydon's blog:
http://graydon2.dreamwidth.org/233585.html#cutid1
Rust sacrificed the majority of its runtime and adopted C's memory model late in development so people wouldn't have to pay a performance cost or depend on confusing heap allocation semantics. That's why it has a really good chance at disrupting the embedded space.
To the vast majority of people and organisations writing software, performance of the software, to within an order of magnitude, just isn't a big deal.
What exactly do you patch? Say you have a TCP server, written in Python or in Go. Do you have to update Python and Go ASAP then and recompile the Go server? Custom compiled Apache, Nginx? Recompile those? That's a lot of work..
man systemctl
daemon-reexec
Reexecute the systemd manager. This will serialize the manager
state, reexecute the process and deserialize the state again. This
command is of little use except for debugging and package upgrades.
Sometimes, it might be helpful as a heavy-weight daemon-reload.
While the daemon is being reexecuted, all sockets systemd listening
on behalf of user configuration will stay accessible.This question had me feeling kind of old. Does nobody learn what shared libraries are anymore?
None of them restarted. So I restarted them all myself...
I bet this bug will live on forever in people's Docker stacks.
You _can_ statically link glibc, but then you lose some stuff. https://sourceware.org/glibc/wiki/FAQ#Even_statically_linked...
And 'immutable practices' don't damage anything - they simply make things take longer, duplicate effort, make inefficient use of resources, and make everything generally more inflexible. The only benefit seems to be high level abstraction at the cost of everything else.
[0] https://golang.org/pkg/net/ (see "netdns" setting)
[root@server ~]# find /bin/ /sbin/ /usr/bin/ /usr/sbin/ /usr/lib* /usr/local/bin/ /usr/local/sbin/ /usr/local/lib* -type f -perm /u+x -exec file {} \; | grep statically | cut -d : -f 1 | xargs rpm -qf | sort -u
busybox-1.2.0-7.el5.x86_64
cryptsetup-luks-1.0.3-5.el5.i386
cryptsetup-luks-1.0.3-5.el5.x86_64
device-mapper-1.02.39-1.el5.i386
device-mapper-1.02.39-1.el5.x86_64
device-mapper-multipath-0.4.7-34.el5_5.1.x86_64
dmraid-1.0.0.rc13-63.el5.x86_64
dump-0.4b41-4.el5.x86_64
e2fsprogs-1.39-23.el5.x86_64
glibc-2.5-123.el5_11.1.i686
glibc-2.5-123.el5_11.1.x86_64
glibc-common-2.5-123.el5_11.1.x86_64
grub-0.97-13.5.x86_64
... etc. And yes, it can be a lot of work. It's easier to only use your distro's official packages and update the patched ones they release. Luckily most software devs are smart and compile dynamically. > The vectors to trigger this buffer overflow are very common and can include ssh, sudo, and curl.
Why are browsers missing in the list? Don't they use getaddrinfo() as well?> We are confident that the exploitation vectors are diverse and widespread; we have not attempted to enumerate these vectors further.
https://plus.google.com/+WilliamChanPanda/posts/FKot8mghkok
"The problem is that Chromium is issuing too many DNS queries in a short period of time, which may overload upstream devices (typically cheap NAT routers) ... which will then ignore DNS queries for a period of time."
But what you really want, is to force other people to write code for you, but in a language you prefer (and for it to be easy and convenient for you). Good luck with that.
I've never needed ENDS0, but maybe the need will arise someday. Meanwhile...
Short term, I'd prefer to expunge all "C networking code" originating from BIND authors, e.g., libresolv.
Now one might think that the discussion at https://news.ycombinator.com/item?id=11110646 already covers this. All that the content DNS server has to do is set the TC flag in the DNS/UDP response, and it can quite happily get the proxy DNS server to re-try via DNS/TCP. The interesting point is that in fact that discussion does not cover this.
This is because the idea that one can exploit this with a malicious content DNS server has as its unstated premise that DNS/UDP and DNS/TCP responses are passed straight through caching DNS proxies. This is the case for some DNS proxy softwares, where if the data have just come in from the back end and form a complete answer, they are passed through as the front-end answer. It isn't the case for dnscache. dnscache always answers from cache, even if the data have just arrived from a back-end transaction.
So those "crafted DNS responses" beginning with 2048 bytes of valid protocol, that the malicious content DNS server has to generate, have to survive being unpacked, stuffed into dnscache's cache, extracted back out of dnscache's cache, and turned into an answer response by dnscache's from-scratch answer construction code. And this without being able to use the authority or additional sections, without being able to use more than one (non-CNAME) RRset in the answer section, and without any guarantee of any given RRset ordering. This is ... somewhat difficult.
The devil in the details of this problem lies in one sentence of the analysis that accompanies the patch:
> Overflowing bytes are entirely under the control of the attacker and are the result of a crafted DNS response.
If you've done as the people at https://news.ycombinator.com/item?id=11112527 and https://www.reddit.com/r/netsec/comments/462xx0/glibc_getadd... did, you might have convinced yourself how simple it is to exploit this. Just set up a malicious content DNS server that does what this does, and Bob's Your Uncle. But in fact those demonstrations are not how DNS lookups work. People do not point the BIND DNS client library at (malicious) content DNS servers. The DNS client library is pointed at the front end of a proxy DNS server, which performs back-end lookups to the (malicious) content DNS servers.
* http://homepage.ntlworld.com./jonathan.deboynepollard/FGA/dn...
So one has to take into account what the proxy DNS server does in between its back end and its front end. The response returned to the BIND DNS client library from the front end is not "entirely under the control of the attacker". As in the case of dnscache, where front end responses are constructed from cache and from scratch, it's actually quite difficult for the attacker to control it at all, let alone cause dnscache to send a valid-flawed-valid response sequence. It's not just dnscache where this is a difficulty for an attacker, either.
Which is why the analysis talks of man-in-the-middle attacks. To exploit this with far greater chance of success, one gets in between the BIND DNS client library and the proxy DNS server, or just plain supplants/subverts the proxy DNS server. Which is yet another reason why it's a good idea to run a proxy DNS server locally, on each machine or at least on the LAN, and make sure that "local" traffic is blocked at relevant machine/LAN borders. An attacker who can field DNS traffic to [::1]:53 or 127.0.0.1:53 in order to be that man in the middle has already had to overcome some quite tricky obstacles. (-:
* http://homepage.ntlworld.com./jonathan.deboynepollard/FGA/dn...
It's worth noting that we've been here before. A lot.
* https://cr.yp.to/djbdns/res-disaster.html
* http://www.kb.cert.org/vuls/id/542971
* http://www.kb.cert.org/vuls/id/803539
* http://www.kb.cert.org/vuls/id/844360
... And so on.
It is to me.
It's true that in this case it's not what mitigates this vulnerability. Although it has certainly mitigated many others over the years and, sadly, probably will do so a few more times in the future. There's just no getting rid of the BIND legacy.
Correct me if I am wrong, but using a local dnscache and the fact that dnscache does not implement ENDS0 should be enough to mitigate this one.
I have been running a local tinydns root.zone and dnscache for many years. Really like the software.
Be wary of making programming languages a religion. The Java zealots did it, and you can see the results where full Java projects are used in places where a 20 line Python script would have been easier.
If you're serious, one of your pet projects should be trying to implement BSD sockets with Rust. Then try compiling some C apps against your implementation. Then do some performance tests showing memory and time benchmarks of your Rust vs libc implementation. Do a blog post on it. Then we'll take you seriously.
I see no "programming languages a religion zealotry" in parents post, but I see a lot of bitterness in yours. Perhaps it's time to reflect.
PHP... Is deployed because it's perceived to be easier and friendlier than other religions, and so wins with that popularity war (as MySQL did). Facebook HHVM is another approach. Folks know the likely warts and mitigate to shrink the attack surface by defending deeply from front layers down to backend services.
Postgres was harder to use in the 2000's despite having a clean codebase but got mucb easier to use, in large part due to MySQL, while leading on features inspired by Oracle DBMS and more recently NoSQLs with hstore.
Attacking popularity for what gets the job done is moot because defense is never ending vigilance for anything real.
Perhaps the focus should be on starting to formally-verifying core libs like zlib, OpenSSL, OpenSSH (portable), glibc, etc. for correctness and resilience against side-effects and ABI promises.
For this particular piece of code one would hope that the fix we'll see now would also include around 100 new lines of comments, splitting of hundred-line functions into a dozen smaller ones etc. I suspect that just by doing that someone would notice another flaw of this magnitude. Also, the updated code would be easier to maintain or rewrite in the future. The whole idea that all changes are kept as small as possible because of concerns that refactoring might break something says something about how brittle it is and how much of the testing is just battle hardening and not proper tests.
That's why the suggestion to implement BSD sockets first is an interesting one. It's a non-trivial interface (which is important to be a useful proof of concept), but it's widely used, relatively well-defined, and could potentially be plugged into applications without replacing other pieces (though that may turn out to be tricky). If it works, you could start implementing more native interfaces that way. If it doesn't, maybe we'll understand better why C remains so dominant for system libraries. (Personally, I don't think it's just inertia or the cost of rewriting all that software, but that's why I'd like to see a project like the one suggested.)
We need to discredit performance zealots and gently herd them to a profitable careers in videogame development where they can't do much harm.
And, there's plenty to dog on Java about, but that language and VM very intentionally makes it an ordeal to load a 3rd party binary blob. Modern development systems/VM's seem to have waved off concerns about unmanaged code and security; Node.JS compiles and loads binary blobs from dependencies all willy-nilly. Java took and takes security seriously.
I've been excitedly watching this over time; I think in a few years Rust could just be straight-up faster than C the majority of the time, depending.
I wanted to encourage developers to be open to compiled Rust being nowhere-near an order of magnitude slower than equivalent compiled C and still have it be an acceptable architecture choice for systems-programming.
Also performance is not such a big deal as dictate security considerations. One's fancy medical web app is worthless if it leaves the potential for theft of medical data.
Also, we need more unit testing, fuzzing and formally proven correct libraries (a-la seL4). Most C development is really bad about unit testing and fuzzing because it's incredibly laborious and verbose, even when it's known to be a good idea.
Will you bell the cat? I'd pay a lot of money to see Linus' reaction to your massive network-stack replacement kernel patch written in Rust.
More seriously though, who is prepared to fund this? Is the risk worth that much effort? Because I see a lot of people being vocal about it on HN, but no real attempt is made to come up with a safe Rust-based alternatives
* Is Google Public DNS a potential mitigator? Sub-thread at https://news.ycombinator.com/item?id=11113113 .
* Is Google Public DNS a potential exploit vector? Sub-thread at https://news.ycombinator.com/item?id=11111300 .
* Are there any BIND settings that are potential mitigators? Sub-thread at https://news.ycombinator.com/item?id=11110646 .
* What happens if one's DNS proxy server doesn't itself support sending >2048 byte answer messages to the BIND DNS client library in the first place? Sub-thread at https://news.ycombinator.com/item?id=11111617 .
* How exploitable is this? What about Windows? Sub-thread at https://news.ycombinator.com/item?id=11110443 .
* What about MacOS 10? Sub-thread https://news.ycombinator.com/item?id=11113471, and a mention of BSD libc at https://news.ycombinator.com/item?id=11111702 .
RHEL6 - https://rhn.redhat.com/errata/RHSA-2016-0175.html - update to glibc-2.12-1.166.el6_7.7.x86_64.rpm
RHEL7 - https://rhn.redhat.com/errata/RHSA-2016-0176.html - update to glibc-2.17-106.el7_2.4.x86_64.rpm
Debian - https://security-tracker.debian.org/tracker/CVE-2015-7547 Use "aptitude show libc6" - needs to be 2.19-18+deb8u3 (jessie), 2.21-8 (sid)
Ubuntu - http://people.canonical.com/~ubuntu-security/cve/2015/CVE-20...
SUSE - https://www.suse.com/security/cve/CVE-2015-7547.html
Interesting to note this tip:
While it is only necessary to ensure that all processes are not using the old glibc anymore, it is recommended to reboot the machines after applying the security upgrade.
From - https://lists.debian.org/debian-security-announce/2016/msg00...
Therefore at the very least you will need to restart anything which depends on glibc. This should give you a list of packages:
lsof | grep libc | awk '{print $1}' | sort | uniqI'm guessing Ubuntu will add something here once they get a fixed released - http://www.ubuntu.com/usn/
Should be able to see centos updates here, once they are released, for files glibc-2.12* with a 2016 timestamp -
Out of the box SSH seems to use getaddrinfo:
reverse mapping checking getaddrinfo for <host> [<ip>] failed - POSSIBLE BREAK-IN ATTEMPT!> Priority: High
Is - https://launchpad.net/ubuntu/+source/eglibc/2.19-0ubuntu6.6
apt-get update
apt-cache show libc6
*snip*
Version: 2.19-0ubuntu6.6
This was released on 2015-02-25apt-get update not seeing it at the moment though, guess its the mirror I'm using.
Edit - working now. I can see:
Version: 2.19-0ubuntu6.7Also, why is all this important and useful information scattered all over the place? Ubuntu people, if you're reading, on this page: http://packages.ubuntu.com/trusty/libc6 I think you should have a history of updates to the package, and which security vulnerabilities it covers, with a link back to the above linked page. Looking at this page, looking at my system, looking at the news, I kind of have no idea what's going on.
I was going to complain that this people.canonical.com CVE page should also be linked from some sort of Ubuntu security bulletin, but I googled first and found that that's exactly where it's linked from. Still, I somehow reckon I would have never thought of that if not for this conversation. It should perhaps be linked from the packages page, though I'm not a UX guy, maybe that would just add confusion. But, this CVE page, with the domain "people.canonical.com", linking to launchpad pages, it doesn't look like it's made for users. You could make some improvements to make it more user friendly like the packages page. You could make it explicit: "Here's the packages you need to upgrade. here's the command to run to upgrade your whole system. Here's the command to upgrade just this package." As it stands, this doesn't even tell you what binary packages to get (libc6, I think? I'm still not even sure!), this just lists the source package (glibc). And, change "DNE" and "pending" to indicators that are more clear to us. Or, make a new page if this one is not meant for users.
For security stuff (not just Ubuntu by any means), all sorts of useful information is scattered all over the place. To name a few questions that I never determined clear answers to:
* What about this Android MMS attack that was supposed to be catastrophic and so easy to mount, that supposedly like half of all Android users are still vulnerable to? We've not heard of a single actual exploit in the wild. Where's some sort of official source downgrading its severity?
* If the libpng thing was such a fiasco, why were there no updates in Ubuntu for so long? Did it turn out not to be such a serious attack vector? Where's the documentation on that determination?
* For heartbleed: I recall having to poke around looking at the "built on" date for my openssl packages to see whether I was upgraded or not. That's not an acceptable state of affairs.
I'm not looking for answers to these particular questions now, I'm just wondering, why do we all have to rely on rumors and advice from random people in discussion forums for this stuff? There's a recent trend of understanding that improved UX can improve security (Signal, etc). Here's a good place to make some improvements, IMHO.
Sorry if I've come off as entitled here, it's just a source of irritation to me.
apt-get install debian-goodies
Then you can run: checkrestart
And it will list services which require a restart. For example: service sudo restart
service ssh restart
service cron restart
service ...
On Debian 8 (Jessie) i had to restart the systemd services as well: systemctl daemon-reexec
systemctl restart systemd-journald
systemctl restart systemd-logindglibc-2.22-r2 was released at the same time as glibc-2.21-r2 and it contains the fix for this issue. The Changelog merely says "misc upstream fixes" but I verified the relevant changes are there.
The GLSA is https://security.gentoo.org/glsa/201602-02
I imagine if they would, they would put more money into the problem: either fund linux development or created more of a market for commercial server operating systems (which can still be open source, at least in some interpretations of the term), for example.
May be US (as de-facto main government-level actor in IT and internet) could create voluntary certification that opened up companies to such liabilities? Small startup operating from a garage — no certification necessary, but users are aware that no one is guaranteeing anything. IBM? Level A certification which they advertise everywhere, with billions of dollars in potential fines.
I even feel the breath of having Ada (the language) enforced over all of us again, and similar ideas...
(Not that Ada is so bad as a language, it's more about the ideas of enforcement and top-down control...)
Unfortunately, I doubt this will ever happen while Linus is around. He seems to be quite fond of C. I assume he would argue this is a matter of shitty developers, not a shitty language.
> I assume he would argue this is a matter of shitty developers, not a shitty language.
All developers are shitty.
(For my projects I prefer D, but Rust has a point here)
There is no silver bullet here. If one takes into account all the sources of bugs, C may very well be the best choice given its maturity and its ecosystem. Our best bet is likely to put more resources towards glibc development and especially fuzz testing. I bet there are only 1-2 developers who work on glibc full-time.
The C standard doesn't require the compiler to check the validity of array indexing and pointer dereferences and such, but it also doesn't require the compiler not to. Can they be added without destroying performance and compatibility?
Some of this already exists, with stuff like stack canaries and address sanitizer. But can it go beyond these ad hoc solutions that catch common mishaps, and become something truly reliable?
It should be possible to just flip a switch on the compiler and have it so that, for example, if you alloca() X bytes and then use the resulting pointer to access byte X+1, that is reliably caught at runtime. And not just as some single patch that specifically looks out for alloca() abuse, but as part of a wider system that understands and catches all out of bounds access.
http://www.cs.berkeley.edu/~necula/Papers/ccured_pldi03.pdf
"CCured is a program transformation system that adds memory safety guarantees to C programs by verifying statically that memory errors cannot occur and by inserting run-time checks where static verification is insufficient."
Also, even if rustc has soundness bugs, you won't find them if you don't look for them, and even then, just trying to make your program fit the types will prevent most bugs.
By the way, glibc's code is too horrible to be read - musl is a more modern alternative.
And if you don't want to use the standard library, you just say #![no_std] https://doc.rust-lang.org/stable/book/using-rust-without-the...
Rust certainly looks like a better starting point for modern, safe low-level programming than C. C served us quite well for over 40 years, but perhaps it's time to move on...
I'll get crucified for saying this but it's easier to write safe code in C++ than C. C requires a perfect discipline very few people can maintain.
Cyclone-lang had good ideas about how to fix C, almost 10 years ago. I wish it has been more successful. i was less "alien" looking than Rust.
However, it is very hard to avoid C++ developers that don't follow the modern C++ mantra to use it as if it was C, specially in the enterprise space.
You end up with "C compiled with C++" code style, which usually isn't subjected to any kind of code reviews or static analysis.
I've heard someone in real life say "git just isn't there yet", so I couldn't resist humoring myself with this comment, sorry.
However I'm all for experimental research projects developing alternative solutions.
But this is yet another bug that could not exist at all in a language with automatic memory management. And there are lots and lots of those bugs.
What we need is not to have knee-jerk reactions akin to angry mops carrying flaming torches and sharpened pitchforks. What we need is to praise the excellent work researchers are doing and to offer our time and/or money into:
a) more security research,
b) development of experimental alternatives written in memory safe languages,
c) yet more security research except this time on the experimental counterparts,
d) thorough testing of the experimental counterparts to ensure functional compatibility.
Maybe a few years down the line we will have something usable in a few bleeding edge Linux distributions, but it will be even longer still before it will have the backing of Debian, RHEL and SLES.
In my mind, these use cases are quite limited though - integration into 3rd party libraries, legacy codebases, and working in embedded environments. I also agree that performance can be a reason, but see Knuth's opinion on premature optimization.
I also think that when writing C, and C++ it makes a lot of sense to restrict oneself as much as possible a la the kinds of standards in the Google Style Guide, or NASA's style guide.
Can people tell me why they start projects in broad C++, and C still? I may be completely missing some piece of the puzzle.
For example, in the mobile OS space if you want to write native apps, without rewriting 100% of the application code per platform and avoid toolchain debugging headaches, C and C++ are the only languages available in iOS, Android and WP SDKs.
In WP case, there are APIs like DirectX that aren't fully exposed via WinRT, so you need to write a C++ wrapper for those type of APIs.
There are other options, but they are either commercial (e.g. Xamarin), or require lots of DYI hacking with the SDKs toolchains.
So if you want to remain productive and not pay for the commercial solutions, there aren't any other alternatives.
Which means, even I with my safety rants, end up using them for my mobile OS hobby coding.
However if I would be doing this commercially, Xamarin would be my first option.
You don't even have to rename .m to .c, but you can.
So my theory is that it's not so much that people are especially inclined towards starting projects in C, but that projects in C have fewer barriers to distribution and thus adoption.
By natural selection, C code spreads and becomes standard; programs in Java, JS, Ruby, Haskell, Ocaml, etc. don't tend to leave their native ecosystem.
I don't think I'm immune to the hazards inherent in the language. I try my best be aware of them and to write safe code, and still find myself introducing a segfault now and then. Luckily, tools like valgrind and Coverity can really help to catch these kinds of issues early (of course, they can't catch everything, but I've been amazed by just how much they do catch).
On Linux it's easy: It is (or was, until very recently) the least sucky alternative. All others have (or had) issues with OS support (C#), distribution (Java: OpenJDK vs. Oracle JDK; Python: 2.5 to 3.4 parallel in use by different distributions; Vala: Every compiler update breaks the language; etc. pp.), availability of libraries (Ruby, PHP, Perl… for anything that's not their speciality) or general obscurity (OCaml, …).
Go and Rust (and JS, C# and Vala recently) seem to be changing this, thankfully. But those too will depend on the availability of high-quality bindings for all the C(++) libraries you have to use to get anything substantial done.
Certain language own certain domains, for better or worse, this means that most developers interested in low level programming will know C/C++, and that the will be a substantial amount of tooling already in place.
This is abusing what "unsafe" means. As a language, C++ is inherently unsafe. However, some C++ programs ("written properly") are correct.
If written properly C++ is not unsafe, then written properly C is not unsafe.
Eg. Don't use C++ as C with vectors, use C++ with the more modern language features:
It's the difference between:
// where f is of type fstream of a file containging "this is a string\r\n"No I think he meant that if you adhere to certain language constructs the language is just as memory safe as Rust/others.
Eg.
Don't use C++ as C with vectors, use C++ with the more modern language features:It's the difference between:
std::string A = "ab" + std::string("c");
// And:
char Buffer[512] = {};
strcat(Buffer, "ab");
strcat(Buffer, "c");
Or alternatvily: std::vector<uint8_t> SomeData = { 1,2,3 }
std::vector<uint8_t> OtherData(SomeData.begin(), SomeData.end());
// and:
std::vector<uint8_t> SomeData = { 1,2,3 }
std::vector<uint8_t> OtherData;
OtherData.reserve(3);
memcpy(...)
In the first one you're 'protected' by the stl code, which is arguably the same level of protection as afforded by any memory safe language’s library code. std::string A = "ab" + std::string("c");
// And:
char Buffer[512] = {};
strcat(Buffer, "ab");
strcat(Buffer, "c");
Or alternatvily: std::vector<uint8_t> SomeData = { 1,2,3 }
std::vector<uint8_t> OtherData(SomeData.begin(), SomeData.end());
// and:
std::vector<uint8_t> SomeData = { 1,2,3 }
std::vector<uint8_t> OtherData;
OtherData.reserve(3);
memcpy(...)
In the first one you're 'protected' by the stl code, which is arguably the same level of protection as afforded by any memory safe language’s library code.It's not; as soon as code uses (for instance) references, you're running the memory-unsafety gantlet. E.g. even something super-modern like
for (auto& thing: vector)
is risky: what if the loop body happens to somehow call `vector.push_back(x)`?Some people like to say that these bugs are trivial to avoid ("who would write code like that?!"), but they miss the insidious (and common) case: when code several layers down the call stack (in some arbitrary callback assigned at runtime, say) grows the vector/map from under you.
[1] not talking about memory safety, but as a general "probability of having a defect".
There certainly is a spectrum.
Sure.
---
Compelling features:
- Unrivaled portability (yes, contrary to folklore C - and to a lesser extent C++ - is more portable than Java)
- Excellent libraries
- Excellent documentation and learning resources
- Unrivaled tooling
- perfect mapping to how the computer works
- Unrivaled performance (other than Rust)
- exceptional, engaging, and intelligent community (specifically referring to the cpp community)
---
Why start a C++ project today?
- you want to write a web browser
- you want a platform agnostc GUI
- you want to learn OpenGL or Vulkan
- you want to use Unreal and you're not a visual learner
- you're want to write the business logic for a cross platform application and share as much code as possible
- you're implementing you're own programming language
- your implementing an algorithm or data structure you've been studying
- you're bored
- you like programming in C++
- you want to learn template meta-programming
- you want to learn functional programming
- you want to learn how to write a device driver
- you need the performance
- you are not writing mission critical software (aka 99% of all side projects)
- you're a curious person
- you're a contrarian and everyone you know uses Java
- you want to become a more well-rounded engineer
- you want to learn about the ins and outs of language design and features
- you want make a lot of money
- you only know C++
Those are a few reasons. Hope that helps you solve your puzzle.
PS: Do the anti-C people realize that a kernel in Rust/Nim/whatever would be under a big unsafe block anyways? Yeah, you have to program "unsafe" code eventually. Those nice high level abstractions are not omnipresent, you know. They need something to abstract.
> a kernel in Rust/Nim/whatever would be under a big unsafe block anyways?
Only portions of it do. The whole point of unsafe is that you can encapsulate it, and then go from there.My point is that unsafety is unavoidable. You can encapsulate unsafe Rust or wrap plain old C, it's, for all practical purposes, the same. At that level language features matter a lot less. I agree we should minimize and encapsulate loosely checked code as best we can.
Okay. Based on my current project (Porting AVS out of shit-tier Microsoft C++). I want a region of memory in which I can treat as a bitmap and set pixels at given location to given colours. I know of no other language that gives me this block of memory to draw into. That's probably because I don't know enough. Most languages seem to tout how immutable things are. That's a big word for many people and it just means "does not change".
If other languages want my attention then maybe they need more than a "Hello, World!" and some string processing. Show me your malloc equivalent and see if I can go from there.
http://www.lispworks.com/documentation/HyperSpec/Body/f_mk_a...
https://wiki.haskell.org/Numeric_Haskell:_A_Vector_Tutorial#...
Considering the time and effort it would take to safely and completely replace glibc with a new implementation, and the limited scope of its effect on Internet-wide security, it would be more productive to require the kernel itself to support patches like PaX, Exec Shield, or grsec in general, so that all applications (not just ones made with a specific language) would have stack-smashing protection.
The Internet has been using DNS resolvers known to be vulnerable to cache poisoning birthday attacks for at least 14 years. We add basic defenses that prevent the majority of attacks, and trudge on, rather than fix the protocol itself, which is a big complicated mess. The smaller, less effective fixes reach a broader number of use cases with less effort, and so we get along okay.
Likewise, we know that no matter what language we use, there will be at some point a problem with regard to accessing memory, and so we put protections in place to limit the scope of those attacks in a broad sense. It's a more effective mitigation for a greater number of use cases. It is not a panacea.
C only became a thing in computing after UNIX workstations became popular.
Before it, there were quite a few safer systems programming languages to choose from, that got steam rolled by C adoption in OS SDKs.
Due to its relation with UNIX, it will most likely happen with Apple (Swift), Microsoft (.NET Native, System C#, C++/GSL), Google (Java FTW on Android, Go) than any other OS vendor.
But I am also looking forward any of them pick D, Rust, <whatever safe lang> in the process.
This made me smile. Need I point out that Android runs on top of Linux? Or that you can still use C/C++ on Android? http://developer.android.com/tools/sdk/ndk/index.html
I also feel the pains that Android teams imposes on the NDK users to use it as little as possible.
If you bothered to read the contents of the link that you pushed.
"Notably, using native code on Android generally does not result in a noticable performance improvement, but it always increases your app complexity. In general, you should only use the NDK if it is essential to your app—never because you simply prefer to program in C/C++. When examining whether or not you should develop in native code, think about your requirements and see if the Android framework APIs provide the functionality that you need"
Also Android Java is nowadays AOT compiled to native code. So whatever C and C++ dependencies there are, could certainly eventually be replaced if there were willingness to do so.
Besides, have you ever tried to implement libc in ANSI C, without language extensions and a sprinkle of Assembly?
I have never attempted to put together a full libc in ANSI C, no. My experience there is limited to putting together parts of it for various microcontrollers, where I was more or less bound to ANSI C and chose to use no assembly.
That's a long way of saying, what's your point? And why do you feel the need to get personal?
Non native speaker here.
As I mentioned in the reply and in another thread, I do use the NDK, but I wouldn't if there were better alternatives.
30 years ago those microcontrollers would probably be programmable in Assembly and Forth, Pascal, Basic and C dialects. At least when I think about Z80 like ones.
C popularity pre-dates workstations. DEC (Digital Equipment Corporation ) , maker of popular mini computers, used it extensively.
Yes Apple runs on top of BSD, because they weren't able to write a new OS and had to buy one, which happened to be built on top of BSD.
Once upon a time they had their OS written in Object Pascal, but then they decided to rewrite it in C to welcome those UNIX devs.
Nothing prevents them to rewrite parts of the OS in Swift after the language gets more mature.
It is only a question of willingness, political will and money.
It was a mix of Object Pascal and Assembly. The Pascal extensions that Borland later adopted in TP 5.5.
Search for Pascal.
Cherry picked from the search results
http://www.folklore.org/StoryView.py?project=Macintosh&story...
The fact that many C programmers forget, is that it is impossible to implement the C runtime or an OS with pure ANSI C code.
Somehow it is ok for C to use Assembly and compiler specific extensions, but not for other systems programming languages to do the same.
I don't understand your last comment. I am not saying that the OS doesn't qualify as "written in Pascal" because it contains assembly. I am saying it doesn't qualify because it didn't contain Pascal. The early versions were subject to absurd space constraints that required everything to be written in assembly. My understanding is that high level languages started to be used for parts of the OS later on, but it remained predominantly assembly until well after the PowerPC transition.
It was the Lisa that was written in Pascal.
http://www.folklore.org/StoryView.py?project=Macintosh&story...
The only reason to get a C compiler for CP/M, MS-DOS or Amiga was to be able to bring work home from those expensive workstations at work or university.
Not on my country, it was all about Borland compilers, even in the Windows 3.x days.
Microsoft was even the last vendor to add support for C++ on the last MS-DOS version of Microsoft C, version 7 if I remember correctly.
But you can't simultaneously argue that C wasn't used for PC platform development in the 1980's and that Borland C was dominant.
I never said directly I was referring to Borland C, actually it was all about Turbo Basic and Turbo Pascal.
I and a few others did use Turbo C, but we jumped right into Turbo C++ the year thereafter, as we could not envision using plain C after having done systems programming in the other Borland languages.
C was left for programming classes, usually trying to convince the teacher to use C++ instead for projects, sadly it only worked occasionally.
Why do "we" have to agree? If somebody really believes this is necessary, why don't they just do it?
Lines 952 ... 1389 [=~450 lines of code], with more than a dozen of variables holding random state. Think about the complexity you have with all the conditionals and loops, often copying and pasting similar conditions with (xx1 && xx2) variants.
While discusions about the relative merits of Rust, C, Ocaml, Intercal are fun, with enough dedication you can write unauditable/unreviewable code in any language. Even though you might avoid memory corruption, you still can't prove that such kind of code does anything correct.
Thank you for sharing that. It's really nothing to do with C, I agree. Just a drastic lack of coding standards. Don't people refactor key code after functionality is proven and tests developed?!
I mean just look at this https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/pos...
That size of methods, huge macros, the low ratio of comments to (non-obvious) statements etc.
I know it's easy to criticize very old and tested code, but there is no (and never was any) excuse for code like that.
But the musl code too has bloody ZERO comments for a nearly 100 line long method of dense/opaque C code! Why? Is commenting and splitting code into functions frowned upon in "traditional" systems programming?
Who is it that writes code like this? Why isn't code like this rejected by a maintainer with "split this into at least smaller 5 functions and comment anything non-obvious"?
Edit: looking again it's actually not that bad, it does have two lookups already broken out and a lot of the verbosity is just field assignment. Would be happy with a dozen lines of comments and a split into 2-3 functions.
When you're reading an API you want to understand how it works without cracking open the source. When you're looking at an implementation it is your duty to load the source into your comprehension, at which point comments become irrelevant, or worse, misleading.
At work, I have to deal with a code base where code is split up like that, and it's a royal pain to follow, and the resulting functions aren't usable by anything else.
[1] The two hardest problems in computer science is cache invalidation, naming things, and off by one errors.
The point of smaller code is testability. It's worth even making it somewhat harder to read. If a test makes three things in succession that in their own functions would have required 3 tests each, the aggregated do-everything function requires much more than the 9 test cases. So dividing the method in two, even if arbitrary and bad for readability can have a positive impact since the total code volume is reduced a lot.
All of this ^ only applies if the code actually has tests. If not - then don't divide arbitrarily if it reduces readability at all. But then again without tests you have bigger problems than readability...
If you make this "accessor" function static [1], then you have to include the test code in the same C file (cluttering that file with code only used for testing [2]) or you clutter the C global function namespace with a function that's quite possibly only used on one location (and thus, can't be inlined at all due to C semantics---just some of the realities of attempting TDD in C).
[1] Functions and variable marked as "static" are only visible in the file.
[2] And you end up with pretty much dead code in a release version. You could exclude such code from a release build, but then you can't actually test the release build of each function.
Or, you know, run a fuzzer.
From there coordinated release dates will be agreed, and barring big surprises like one distro pushing out an update too soon everybody _should_ release at the same time.
Sometimes people get sick, take a holiday, or drop the ball for other reasons. I'd expect Ubuntu did get notified, but haven't yet tested/built their fixed packages to push out.
From what I'm reading this should only affect systems that use a compromised DNS server or in a MitM attack scenario. Which is serious but not so easily exploitable (I think).
Oh it is. All you need is an open wifi with a router only dealing IPv4 addresses... start up radvd and serve your machine as authoritative IPv6 DNS server, and profit.
Besides, how many distro's are actually configured for dhcpv6 stateful configuration out of the box?
So in theory, all you need to be exploited is to connect to a compromised host and resolve its hostname.
- A back of the envelope analysis
shows that it should be possible
to write correctly formed DNS
responses with attacker controlled
payloads that will penetrate a
DNS cache hierarchy and therefore
allow attackers to exploit machines
behind such caches.
So even if you trust your local ISP and DNS servers, any random domain on the internet may be resolving to an exploit.Also, this vulnerability has apparently been around since 2008, and sitting in public view on the bugtracker for many months. Who knows who else has been sitting quietly on this for however long? :-/
Configuring BIND to use a specific buffer size (only for BIND 9.3.2 and newer):
Add the following line to the "options" section of your named.conf file:
edns-udp-size: n
Configuring Unbound to use a specific buffer size:
Add the following line to the "server" section of your unbound.conf file:
edns-buffer-size: n
source: https://labs.ripe.net/Members/anandb/content-testing-your-re...
Sounds promising, however.
It's a fork of an ancient version of BIND.
Starting with version 2.2, the resolver in the GNU C Library comes
from BIND 8.
https://sourceware.org/git/?p=glibc.git;a=blob;f=resolv/READ...- Earl Boebert
iptables -t filter -A INPUT -p tcp --sport 53 -m connbytes --connbytes 512 --connbytes-dir reply --connbytes-mode bytes -j DROP
iptables -t filter -A INPUT -p udp --sport 53 -m connbytes --connbytes 512: --connbytes-dir reply --connbytes-mode bytes -j DROP
iptables -t filter -A INPUT -p tcp --sport 53 -m connbytes --connbytes 512: --connbytes-dir reply --connbytes-mode bytes -j DROP
Parts of the linux kernel or glibc or any other critical C code gets replaced by rust code little parts at a time, which is also calleable from C (https://doc.rust-lang.org/book/ffi.html)? That way these libraries could be made safer in a controlled and incremental manner.
And to reiterate I'm asking for technical limitations, not political or dogmatic.
What you need to understand is that almost 100% of engineering is economic. Is it worth the time to rewrite things in a new language, to rebuild the tool chain to make things easy/convenient, to deal with the gotchas in each new language and their compilers ? On and on the list goes. And most of the issue is there isnt incentive, users of free software have a first mover problem in that if someone else pays for the software to be made, nonparticipants get it for free. Thus we all wait for someone else to pay for all the wonderful things that would benefit us all.
For some projects this isn't a problem. For example, Firefox is replacing bits of itself little by little with Rust, which is fine because Rust targets all platforms that Firefox is built for (though it did take some wrangling to get Rust working on Windows XP). However, a project like glibc is used across a much greater variety of platforms, and many of those platforms may have nothing but C compilers. And those C compilers may very well be buggy and nonstandard, so even transpiling to C won't help unless you're willing to hand-tweak the generated code.
You can't just pass a Vec<> to some C code and expect it to work. The reality is that you're going to end-up writing a lot of C-like Rust - Which either acts on C types directly or converts them to Rust types and then does things to them and converts them back. Either way, the safety is largely lost due to this because C types are not going to be safe.
You also can't use any inline C functions or preprocessor macros in your Rust code, meaning that the interop between C and Rust isn't really that good - FFI lets you call functions, but functions only make-up a part the C API. The rest would have to be duplicated in Rust and kept up-to-date, which is a huge development burden and very error prone.
And when you're finally "done" and all the C code is gone, what you're left with is just a lot of C-like Rust, communicating with each-other through the C API using C types with unsafe code everywhere. Essentially C but in Rust form. You'd have to do a ton of refactoring to turn this into anything like idiomatic Rust, and you can't do that refactoring till all the C code interfacing with that Rust code is completely gone so you can stop supporting interop with C.
The bottom line is that it you could do it, but it won't work well because it's missing the big picture - If you don't write Rust code like Rust, then you don't get the safety guarantee's, and you can't do that if you're trying to recreate a bunch of C interfaces in Rust. C interfaces are not safe in the way that Rust would want them to be safe. It's the same reason why you can't write a converter to convert from C to idiomatic Rust - You have to design the system differently to get the gains from Rust, which is a non-trivial thing to do. Rewriting small parts in Rust isn't going to result in the design differences that you need, and the interop between Rust and C isn't very good, leading to lots of problems while you're dealing with both languages in the same code base.
https://www.youtube.com/watch?v=2BdJeSC4FFI is a further exploration of this idea and how it works. Yes, you do need that small layer, but future libraries will make it even easier. There's the Neon work, for example: http://calculist.org/blog/2015/12/23/neon-node-rust/
https://github.com/nodejs/docker-iojs/issues/44#issuecomment...
Most apps will work out of the box, but you can see in that issue 1+ year of various people debugging and fixing issues to just get existing test cases to pass.
For example:
https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/pos...
compare with
http://git.musl-libc.org/cgit/musl/tree/src/network/getaddri...
* http://git.musl-libc.org/cgit/musl/tree/src/network/getaddri...
* http://git.musl-libc.org/cgit/musl/tree/src/network/lookup_s...
* http://git.musl-libc.org/cgit/musl/tree/src/network/lookup_n...
* http://git.musl-libc.org/cgit/musl/tree/src/network/lookup_i...
* http://git.musl-libc.org/cgit/musl/tree/src/network/resolvco...
See also the BSD libc implementation of getaddrinfo():
* https://svnweb.freebsd.org/base/stable/10/lib/libc/net/getad...
* http://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libc/net/getaddr...
If you switched SSL library from OpenSSL after Heartbleed, odds are you went from bad to worse.
Which pkgs on Ubuntu will be necessary to upgrade once they roll the fix to the repos?
If I understand the Google sec article correctly, this requires a single packet > 2048 bytes to be received by a host using glibc.
> The vulnerability relies on an oversized (2048+ bytes) UDP or TCP response, which is followed by another response that will overwrite the stack.
Is my understanding correct?
If it is, then it's worth pointing out that many links on the public Internet have an MTU of 1500 bytes. This is an historical legacy of original Ethernet from the 80's. Path-MTU-Detection(PMTUD) doesn't really work on the Internet, so it's safest to assume that you only ever get 1500 bytes.
Given all that, this places a burden on anyone wanting to eploit this. Since they cannot assume a PMTU greater than 1500 bytes between endpoints, they're limited in how they can exploit the bug. Correct?
Please correct me if I'm wrong. I always feel these bug reports are missing that vital piece of information I need to operationalize the bug. And thanks.
PMTUD doesn't work at all on the modern Internet, not for IPv4, and not for IPv6. So again, I'm just wondering how dangerous this exploit really is. I'm not saying it isn't dangerous, I'm saying our understanding of it should be tempered somewhat due to many links not fragmenting properly that have MTUs of 1500 bytes.
Example (tested on Ubuntu 14.04 64-bit):
mkdir -p root/lib/x86_64-linux-gnu root/lib64 root/etc
cp -a --parents /lib/x86_64-linux-gnu/lib{c,nss,resolv}* root
cp /lib64/ld-linux-x86-64.so.2 root/lib64
cp CVE-2015-7547-client root
echo 'nameserver 127.0.0.1' > root/etc/resolv.conf
sudo chroot root ./CVE-2015-7547-client
If it prints nothing it crashed. Try running with strace to be sure.Premature optimization is a root of all evil indeed.
P.s. whatever language you use its irrelevant. Bugs are in the heads. Code is just the reflection.
Here is CentOS 7
[ 389.064412] do_general_protection: 159 callbacks suppressed
[ 389.064416] traps: CVE-2015-7547-c[1161] general rotection ip:7fa6b0d8fd67 sp:7ffdaf034a30 error:0 in libresolv-2.17.so[7fa6b0d87000+16000] $ ./CVE-2015-7547-client
[1] 15697 segmentation fault (core dumped) server:
vagrant@precise32:/tmp/CVE-2015-7547$ sudo python CVE-2015-7547-poc.py
[UDP] Total Data len recv 36
[UDP] Total Data len recv 36
client:
./CVE-2015-7547-client
CVE-2015-7547-client: getaddrinfo: Name or service not known
vagrant@precise32:/tmp/CVE-2015-7547$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 12.04 LTS
Release: 12.04
Codename: precise
vagrant@precise32:/tmp/CVE-2015-7547$ ldd --version
ldd (Ubuntu EGLIBC 2.15-0ubuntu10) 2.15
Copyright (C) 2012 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.Maybe we should start by releasing an update there asap, and go from there?
(I just switched our last Linux server over to FreeBSD, despite some software we use not being available; so I'm happy to sit this one out.)
Also, keep this in mind:
>While it is only necessary to ensure that all processes are not using the old glibc/eglibc anymore, it is recommended to reboot the machines after applying the security upgrade.
[1] https://lists.debian.org/debian-security-announce/2016/msg00...
[2] https://lists.debian.org/debian-security-announce/2016/msg00...
I'm thinking about a background tool (iptables plugin?) that simply truncates long DNS replies, so that they can never cause a buffer overflow.
sudo lsof -n | grep DEL
is your friend in this matter.http://people.canonical.com/~ubuntu-security/cve/2015/CVE-20...
Are "upload file by URL" functions potential vectors? (payload in malcious dns response)
Is this contingent on a cooperating DNS server (not truncating the record?)
Among others the page lists:
> [...] when /etc/resolv.conf or /etc/nsswitch.conf specify the use of features that the Go resolver does not implement, and when the name being looked up ends in .local or is an mDNS name.
Those things you can't check at compile time.
In any case, you can tell whether the binary is statically linked or not.
Statically linked:
$ file /usr/bin/consul
/usr/bin/consul: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
$ ldd /usr/bin/consul
not a dynamic executable
Dynamically linked: $ file /bin/echo
/bin/echo: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, stripped
$ ldd /bin/echo
linux-vdso.so.1 => (0x00007fff01fff000)
libc.so.6 => /lib64/libc.so.6 (0x0000003bcd800000)
/lib64/ld-linux-x86-64.so.2 (0x0000003bcd000000)
Notice the libc.so.6A quick search in the PowerDNS codebase [1] reveals four sites where getaddrinfo() is called. This isn't obviously the code for recursive lookups but that doesn't matter. If an attacker can trick it to query their rogue DNS they have won.
I don't want to suggest that Google uses PowerDNS, I just used is as an example.
[1] https://github.com/PowerDNS/pdns/search?utf8=%E2%9C%93&q=get...
My point is that if you could use this bug to use one rogue DNS to own other DNSes this could be leveraged to bring large parts of the Internet down.
I don't know how hard or easy this could be. A quick glance into PDNS reveals four calls to getaddrinfo()[1]. So it might be possible...
[1] https://github.com/PowerDNS/pdns/search?utf8=%E2%9C%93&q=get...
One uses AI_NUMERICHOST and thus doesn't do any DNS client activity. A second isn't supplied arbitrary domain names as input, they being the ones configured for the location of a specific back-end data source by the server administrator. The third is used only inside a "zone transfer" subsystem and again isn't supplied arbitrary domain names as input, the domain names again being in local data specified by the server administrator.
And the fourth is not even part of the executable program, the code being disabled with #if 0 .
The "S" in "DNS" stands for "system", not "server", by the way. A rogue DNS server would "own" other DNS servers.
http://www.opensource.apple.com/source/Libinfo/Libinfo-477.2...
I'm really worried that I still hear about buffer overflows in this day and age. Of all the libraries in the world, glibc should probably be written in some subset of Idris that compiles into 100% safe C. We have the technology to move to this now
... and together with stuff using glibc (indirectly) constitutes 99.99% of your software.
How much software/languages implement their own DNS resolver instead of just calling libc? How about syscall wrappers?
A managed language generally doesn't give you direct access to syscalls at all. In rust you can perform them without having to go via C.
One possible reason why java might implements its own name resolution is because it wants to do async name resolution which is not possible (at least portably) via getaddrinfo and friends.
(Dismal enough that I ended up writing my own DNS encoding/decoding library (https://github.com/spc476/SPCDNS) with the aim of being easy to use as well as safe. It assumes nothing about the incoming packet and does extensive validation (enough that it found bugs in other DNS libraries). It also avoids dynamic memory allocations. It's used at work in two projects that get heavy use (millions of DNS queries a day) and so far has performed without incident, so well written C code is possible.)
For ex with getaddrinfo: https://gist.github.com/zwetan/0c047d36542cc6979652
I know because I did it on purpose, even if it managed code written in AS3 you don't want to reinvent getaddrinfo, you want to reuse it "as is" as much as possible.
This is different from, for example, java bytecode which is verified and guaranteed to be memory safe.
This is not a mere technicality: an heartbleed vulnerable version of openssl compiled on top of asm.js or NaCl would still leak secret information.
edit: typo
On the other hand memory safety does not prevent bugs like Heartbleed or resent OpenSSH key leak. As the underling issue is related to broken reuse of a cached buffer, such code can be written in Java or even Rust just as well.
You are right that Heartbleed is not a memory safety issue, I should have been more careful. I just wanted an example of an exploit that doesn't need to escape the process boundary to cause damage.
This is important if you export multiple symbols for a function, that is, have a program that depends on a specific implementation of a function. That could mean you depend on different versions of the same library ("functionname@@VERSION_1, functionname@@VERSION_2"), or completely different implementations of a function ("functionname@@IMPL_X_VER_1", "functionname@@IMPL_Y_VER_2").
Wait a second. That seems like a strange feature to want, right? Well. It's particularly useful for runtime library fun stuff. LD_PRELOAD in a library that magically changes the implementation of function. A cool example of this is of preeny[1], a collection of libraries to help with debugging.
Additionally, it's useful for replacing libraries that would depend on C implementations without having to recompile them, though some preloading magic at runtime may be required.
This is only the thing, for me at least, that's blocking for making Rust system libraries. Now, any sane person may say, "Cargo will take care of versions and stuff", and that's true. Sadly, that's not the case if you ever want to use those nice and safe Rust libraries from C though.
Though, I may be completely wrong about the state of symbol versioning in Rust. I simply ran 'nm -g libopenssl.so' on sfackler's rust-openssl project and failed to see any @@<version> in the output -- that is specifically being exported, and not re-exported, by libopenssl. There may be better libraries to use, but eh.
I could be completely wrong on this though. I've been mainly going off of what I read here[2], and here[3] (alternatively, for a more in-depth version, try here[4]).
TL;DR: symbol versioning may not be a thing.
Disclaimer: I've had to use symbol versioning pretty heavily, so it's important to me. I could also be completely wrong about Rust not having it.
[1]: https://github.com/zardus/preeny [2]: https://gcc.gnu.org/wiki/SymbolVersioning [3]: https://www.akkadia.org/drepper/symbol-versioning [4]: https://www.akkadia.org/drepper/dsohowto.pdf
As far explicitly using the symbol versioning scheme you mentioned, you can do it with an attribute today:
https://play.rust-lang.org/?gist=92be155702d53c6411b2&versio...
(Disclaimer: I haven't actually compiled this as a dynamic library and checked, but its what that attribute is for, and the names seem to be used verbatim in the ASM output)
It seems as if symbol versioning in Rust is nicer than in C. I'll have to play around with that a little bit.
I'm hoping I never to have to deal with writing version scripts or inline assembly again -- or at least having to write less.
Are you seriously suggesting that rewriting an implementation of the C standard library in a language that isn't C is something that makes any bit of sense?
I think you have a fundemental understanding of the roll the C-standard library plays in the C language. Not to mention UNIX in general.
Maybe you're suggesting we need an OS based in Rust instead of C (which is more reasonable), but in that case why wouldn't you use Rust's standard library as the backbone of that system?
Let me put it this way, if the GNU/Linux C standard library gets rewritten in Rust or Idris (sigh... seriously?) I will switch to Windows 10 with default settings for the rest of my life. I would rather have the NSA log my every key stroke than participate in a community where that is considered a good idea.
Wrap existing C with safe Rust, not the other way around! We don't rewrite unsafe C code in Unsafe Rust so that it can be called from all the unsafe C code in UNIX. Such a translation is so pointless and error prone.
I can't even believe I'm the one being called backwards here.
They're definitely not. The power of Rust is not avoiding all `unsafe` ever, but wrapping that unsafe into finite-scope, safe wrappers. Something like mmap would presumably interface with the OS's internal memory management routines, which would definitely have to have `unsafe` somewhere since they're hitting the hardware, but it seems very reasonable for the amount of unsafe exposed to much reduced (possibly even to zero). See, for instance, http://os.phil-opp.com/modifying-page-tables.html . Basically, as soon as you're above the absolute raw hardware level, you can start introducing extra help to reduce unsafety/catch bugs.
In any case, code inside `unsafe` still benefits from all the conventional Rust checks, e.g. iterating over a slice won't go out of bounds due to a typo in the loop even inside `unsafe`, nor will references accidentally become dangling. (Of course, the `unsafe` block may do something explicitly that causes either of these problems, but this exact same risk is pervasive in all C code, rather than just around explicitly marked areas.)
> Wrap existing C with safe Rust, not the other way around! We don't rewrite unsafe C code in Unsafe Rust so that it can be called from all the unsafe C code in UNIX. Such a translation is so pointless and error prone.
Note that this is exactly what is done now, the features of Rust for making safe interfaces makes Rust often a far nicer way to use C interfaces than C itself, without overhead (IMO, of course). See http://blog.rust-lang.org/2015/04/24/Rust-Once-Run-Everywher... , for example. Of course, zero-overhead Rust is only as safe as the C code it wraps, it can't (in general) protect against the C code not correctly implementing its stated contract(s).
Maybe you could separately map shared RefCells to guard the pages returned by the mmap wrapper? If the region is backed by a file, you'd need to check those RefCells on every IO access too, though.
Examples would be:
* read-only: &ROMemMap -> &[u8]
* read-write: &mut RWMemMap -> &mut [u8]
* write-only: fn set(self: &mut WOMemMap, i: usize, b: u8),
or more generally: &mut WOMemMap -> &mut [WriteOnly<u8>] where WriteOnly<T> has fn set(&mut self, T)
Now for the shared case, consider this: aliasing rules can be avoided with atomic operations, i.e. Arc<AtomicUsize> is shared and can be safely (atomically) read/written by multiple threads.
In the multi-process case, you could provide an atomic API, although we don't currently seem to expose byte-level atomics (likely not present on some platforms) so if you wanted to write a demo you'd need to use the unstable intrinsics atm.
FWIW restricted to single-threaded code, this results in the Cell get/set API which is not hardware-atomic but cannot overlap with other accesses to the same memory, as Cell doesn't implement Share so any threading abstraction will block you from doing any kind of sharing of Cells.
That is, you can share &[Cell<u8>] pointing to any bag of bytes that sits in read-write memory, and anything in the same thread can read or write to it, safely.
However, as you say, exposing a safe mmap version for libraries to call is a different problem with different difficulties. eddyb's sibling suggestion of teasing out the multiple entangled uses of mmap sounds like a good one, although someone would have to experiment with it to be sure.
Cool stuff though, I really hope rust catches fire soon. I love that it has revitalized the appeal of implementing operating system level projects like text editors and shells. I never would have wanted to try and write a windowing system before Rust. Now that's something I'm actively investigating for fun.
There's no technical reason why the C standard library can't be written in a language other than C. Lots of language libraries are written in languages other than the one they're primarily used with and work fine.
There's no technical reason why it can't be done, true. It's still a hilariously bad idea that would never succeed. That's aside from the fact that's a completely pointless wheel-reinventing endeavor. Rewrites in general are pretty difficult to justify.
Sorry, I guess my aggressively pragmatic side is showing today. The idea is really dumb.
To be honest, "Let's rewrite the C standard library in Rust" is one of the worst pieces of bikeshedding drivel I've ever read. And I like Rust 100 times more than I like C.
The way forward for C on Windows from Microsoft own SDK is to use the clang frontend + Visual C++ backend, or another C compiler from someone else.
Yes, C++ is as unsafe as C, given its copy-paste compatibility, but at least it provides the tools to program safely (if one chooses to) and the C++ community cares much more about safety than the C one.