Hacker News new | ask | show | jobs
by hardware2win 1323 days ago
Another day, another CVE in tool that we rely on everyday

The first question that we all want to ask

Could it be mitigated by safer, modern tech?

10 comments

Yes.

One does not even need to reach for Rust. Literally any other language (in common use) other than very badly used C++ would not have had this problem.

C delenda est.

What is the reason that safety-critical tools like sudo and OpenSSL are not written in Ada? Rust is still undergoing a lot of work but Ada has been around, has been stable, and it is fast.

Is it that GNAT only became available relatively late in the lifetime of GNU/Linux? Or is there another technical reason for it?

UNIX and C are symbiotic, for a long time, C would be the only compiler in the box, eventually C++ joined the party as they share the same origin.

Anything else required buying the product and justify why the compilers in the box wouldn't do it .

When UNIX SDKs became commercial, it was even worse, you would naturally one buy the main one, not pay twice for programming languages.

Then the UNIX clones also followed the same culture focusing on C for the clones. Early versions of the GNU manifesto explicitly refer that C should be the preferred language.

That is how we landed here.

but if sudo was written in java we'd have other problems ;)
Yes, I agree. I did not mean to imply that literally any other language would have been better for sudo, which I see is a viable reading of my original post. Go, for instance, would be a terrible choice, because the way the runtime deeply assumes you're running in a multithread environment, even before it gets to your "main" function, means that exactly the sort of UNIX hackery sudo is designed to do is effectively impossible. I have a system myself that is otherwise entirely in Go, but we have a very small C-based wrapper whose job it is to be setuid, open a few files with the escalated privileges, do some user verification, then change its uid and gid and exec the "real" Go program, because Go just can't do those things.

Dynamically typed languages as a whole would be a bad idea.

Java's startup time for such a small executable would be a problem.

I'm just saying this problem is unique to C, and in my opinion, sufficiently endemic to security software to disqualify it entirely.

Mind you, you might well end up at Rust in the end anyhow. Perhaps D. It isn't necessarily a long list for a sudo replacement. But...

C delenda est.

In a way it is kind of an ironic tragedy, that the followers of C church worship UNIX and Plan 9, while ignoring the end station from the priesters, Inferno and Limbo, where C was confined to the minimal trust base of the kernel and a couple of drivers, with everything else in userspace mostly written in Limbo.

Here is "runas" in Limbo, https://bitbucket.org/inferno-os/inferno-os/src/master/appl/...

Do you know one of the reasons why Multics had a better security score than UNIX on DoD assement?

PL/I does bounds checking by default.

For reals. The fact that C toolchains have never even offered a bullet-proof bounds-checked (no UB) mode, no matter what the slowdown, boggles the mind. For something like sudo, literally running 100x slower would not be an issue. Its highest priority should be security.
I have come to conclude that WG14 literally doesn't care about security, for them C should stay as a kind of portable macro assembler with amenities, and the same security guarantees as writing raw Assembly code.

Even the pseudo secure Annex K, requires separate arguments for actual length and max buffer length, thus defeating the purpose of being library functions for secure code.

Just having one of the many libraries that provide secure strings and vector handling, so that libraries can rely on a common vocabulary types would be an improvement.

100x slower would definitely be an issue. I am prompted for my sudo password probably 30x daily.
Come on, wtf? Your computer can literally emulate another architecture in real time and you think sudo 100x slower would be humanly sensible? Computers literally wait eons for human inputs in the majority of times.

I assume you actually think that sudo takes the time it does, but you just likely entered your password wrong and are made to wait deliberately through a sleep. Are we really that bad at ball parking code execution times?!

I just checked, and on the machine I'm sitting at 100x slower would mean it took 0.1s of CPU time.
How long does sudo take to load on your system. Multiply that by 3000, is it really a noticeable number?
Like what? It would be written once correctly and work as is intended pretty much forever.
I don't understand why redhat in particular still is so obsessed with C. I saw that Flatpak was written in C looking at the repo recently and for such a security relevant, relatively young project I don't know why people still stick to non-GC languages.
Rust came out in 2015, a year after the first release of Flatpak (back when it was still called xdg-app) in 2014. The ecosystem was also much smaller; some very necessary things for working nicely on Linux that exist now like zbus (the prominent async-compatible D-Bus library) wouldn't be a thing for several more years.

RH does have an interest in Rust, used in projects such as Stratis. It's just that the Linux dev ecosystem has been very C-reliant for a long time, and a massive amount of binding and other ecosystem work is still happening to make this possible.

*EDIT:* and the reason I mention Rust specifically is that, in these types of lower-level projects, a lot of things can start to get hairy very quickly in higher level languages. Things like some namespace APIs very much wanting to be run on a single thread, or trying to maintain performance when you're intercepting and examining every D-Bus message, or even just when you want your functionality to be in a reusable core library.

Safer systems languages than C predate C.
But the Unix environment is written in C, and there's a ton of legacy from the past several decades still to migrate from C. It's going to be slow going. That said, ditching sudo seems like the right thing to do, but then, writing a drop-in replacement is non-trivial too because sudo/sudoers is so baroque -- yet w/o a non-drop-in replacement would require user/customer migrations.

Meanwhile RedHat and others don't have infinite resources, and they inherited sudo.

Yes, because UNIX authors decided it was more fun to create C and ignore the history of safer systems programming.

They were also open about it, and thus created lint for validating the code, which most people ignore when writing C code.

Sure, there is a mountain of legacy code. But why start Flatpak in C?
I understand why they stick to non-GC languages (performance, startup time, the need for maintained wrappers for native calls, etc.), but I don't understand why they don't pick better ones. Rust is nice and shiny but even modern C++ with some good conventions would be miles ahead of plain old C.

Languages like D even allow you to disable the garbage collector for specific methods, giving you the benefit of GC-less performance and characteristics in critical code paths and the YOLO memory management of GC languages in the wrappers around them.

I guess the answer is "because all the people over at Redhat know C"

Well, work on flatpak started around 2013, 2 years before Rust was 1.0 (much less mature). So it's pretty new but not quite that new.

Just to throw out some guesses:

1) "because dynamic linking", if you're an OS vendor being able to ship one package to fix a security vulnerability instead of 50 is a big deal

2) you probably want to have a C-compatible API anyway so that it's possible to use the code from other languages, so combined with 1) the benefit of a language like Rust or D would be dulled slightly. Not eliminated, just reduced.

3) Less common architectures POWER and s390x are still relevant platforms in enterprise and while languages like Rust do have some support for them, C compilers for those platforms definitely get more attention.

What about modern C++?
You meant unsafe, not non-GC?
We could start by considering not writing stuff like

> /*

> * Truncate to 8 chars if standard DES since not all crypt()'s do this.

> * If this turns out not to be safe we will have to use OS #ifdef's (sigh).

> */

> sav = pass[8];

The solution is simplicity, not more complexity.

This bug was introduced by the latter.

If you seriously think a buffer for a password needs to be dynamically allocated, the "safest" and most "modern" shit won't help. It'll just contribute to the ongoing decline.

> the "safest" and most "modern" shit won't help

But it would

I'm pretty sure their point was that there are fundamental issues at play, and that switching languages does not make the problem go away.

Rust/whatever is not a magic bullet

This is complete nonsense. There aren‘t fundamental issues at play. The issue is time and time again memory safety and bounds checking. Avoiding that topic in favor of „fundamental issues“ is disingenuous at best.

Rust / Go / Modern Language X is not a magic bullet for every problem, but it sure seems to be a magic solution for this very problem which occurs incredibly often and is easily fixed by avoiding archaic languages for security critical stuff.

This kind of problem would be a non issue on PL/I, JOVIAL, NEWP, and several others that predate C for systems programming.
YES. I agree entirely.
It wouldn’t solve every problem, but it would solve this problem, and this problem happens to be a regularly reoccurring problem with serious consequences
I get their point, it's just ironic since modern languages very much do not suffer from "I think a password needs to be dynamically allocated".

It's also particularly silly since there are plenty of reasons why a dynamically allocated password could be quite nice.

So yeah, I get that their point is "bad devs will write unsafe code no matter what the language is", this is just a terrible case to try to make that argument.

In many of those issues switching language does indeed make it go away, because compiler will yell at the user if they do something stupid.
> ..array-out-of-bounds error that can result in a heap-based buffer over-read...

This was already a solved problem in NEWP, JOVIAL and PL/I, no need for modern tech, only not to insist in using broken by design one.

> Could it be mitigated by safer, modern tech?

Like... Coverity Scan?

In my experience, this bug looks like a classic example for something that Coverity should find.

And it looks like sudo is already on there: https://scan.coverity.com/projects/sudo

The last analysis was 2 weeks ago. I wonder if this CVE is among the outstanding memory corruption and illegal access defects (5 each).

Related, but sudo is not in scope for this project:

https://github.com/uutils/coreutils

And the second question, would be: What is the cost for it and would we be willing to pay it?
And the third question, would be: What is the cost for using outdated technology and are we really willing to pay it?
The answer to the first question is „literal billions in damages“ and the answer to the second one is „seemingly yes“. Library / application maintainers and product companies rarely pay the cost if yet another memory safety issue leads to a new 0day.

Perhaps changing that would finally turn people off of C/C++

Yes, when we aren't happy with physical goods there are laws and liabilities to take into account, same should apply to software products.
Well, in practice we are paying it.
Yep, the real question is for how much longer.
Until someone can come up with the time or money to fix the feature gap between the many safe rewrites and the standard coreutils (and convinces packagers to ship the safe ones).
Or governments start to pay attention like the last US security bill.
You are talking about perf?

People use fucking java in HFT

dont worry, our basic tools are fine with Rust, go or even c#

For cli tools startup performance matters a lot, and many languages struggle on that point (eg Java) go and rust would probably be acceptable though.
Apparently not, when so many of them are written in Python and Perl.

As for Java, if the extra ms are the end of the world, one can JIT cache or AOT compile it anyway.

Bounds checking would have prevented this outright.

Bounds checking has been standard in every language other than C since 1970, but for some reason C programmers refuse to use it, normally using arguments like "just make sure the indexes are correct", which is basically "just don't write bugs".

Bounds checking in systems languages precedes C for a decade, making it worse their decision to ignore it.
sudo is almost 150k lines of code, has been developed since about 1980, and works (and is used!) on a wide array of systems.

Are you going to rewrite all of that in $other_language_than_c? How many hours of work do you think this will take to rewrite?

This is the real issue.

> sudo is almost 150k lines of code

I'd argue that's (at least part of) the problem. More code = more surface area for bugs, and sudo has a lot of code.

It is, but that code wasn't added for the craic and does solve real use-cases that you can't just ignore for a full-featured drop-in s/sudo/.../-type replacement.

(also, 150k lines of code is a little bit misleading, since not all code is for all platforms, sudo has a plugin architecture I believe, etc.)

Translating that one to one would take 10 developers at 100loc / day less than half a year.

Surely that can‘t be that much in the name of security, no?

I think that is a very optimistic estimate considering it's pretty difficult security-sensitive code which integrates with quite a number of system components in complex ways across a large number of different platforms (this particular bug was introduced for HP-UX compatibility for example).

But you're welcome to try of course. But if it was that easy I bet someone would have done so already. This is the classic "zomg look at how complex it is, let's just rewrite it from scratch!" and then you discover that the complexity is there because it solves a long list of edge cases.

> Surely that can‘t be that much in the name of security, no?

Meh; in reality, almost no one was affected by this particular bug, and even if they were, you needed system/shell access to be affected. Like many sudo security problems in reality they're often actually not that big of a deal. Of course, it could be improved, but there's a long list of other things that are more impactful.

> But you're welcome to try of course

Ah yes, the classic "do it yourself then" comeback argument. Thing is, I am a single developer with rent to pay and a family to feed. In all honesty, I would have little to gain when rewriting sudo / mission critical software in a secure language.

What I was going for is that gigantic companies with tens of thousands of people and manpower use tools like sudo / brew / sqlite / <security dependant tool x> every day. They are the ones who would benefit the most by rewriting critical software in something else than C, and they seem to be getting on that track for internal software.

But for open source stuff, no one cares and that's criminal in my mind.

If you care about it, then you should put in the work; that's kind of how this open source thing works. That how pretty much any volunteer effort works. No one can "force" anyone to do anything, nor should they, and this includes using sudo. If you don't like sudo for whatever reason: then don't use it. If you think there "should" be a replacement: then write it.

Who are you or I to determine where others – including "gigantic companies with tens of thousands of people and manpower" – should spend their time and money?

Eventually it will be written in javascript.