Hacker News new | past | comments | ask | show | jobs | submit login
Sudo: Heap-based overflow with small passwords (redhat.com)
279 points by thewavelength on Nov 4, 2022 | hide | past | favorite | 233 comments



Sudo must be the program with the largest number of buffer overflows I’ve heard about. That news is repeating itself ever since I remember.

Maybe a good time to plug doas, a simpler alternative to sudo from OpenBSD folks[1], developed partly due to security fears about sudo. It’s also been ported to Linux and is available in e.g. Alpine and Debian.

[1]: <https://flak.tedunangst.com/post/doas>


To put the relative simplicity into perspective, here is the official Github mirror of sudo:

https://github.com/sudo-project/sudo

On the contributors tab:

https://github.com/sudo-project/sudo/graphs/contributors

We can see that sudo has been maintained by one person for ~29 years who has single-handedly committed ~2,936,000 changes over that time resulting in a net increase of ~480,000. It is also being actively developed with ~270,000 changes resulting in a net increase of ~40,000 lines in the last twelve months.

In contrast doas is, just eyeballing it, maybe ~500 lines and at most 1000 lines all together.


From a security point of view, staying small reduces attack surface. So if this holds all the features you need, that’s a valid option.

It doesn’t remove a bit of how impressive the dedication of Todd C. Miller is of course.

These are two solutions with a common core goal but greatly different concerns.


Todd is a saint for the work that he does here. Ultimately, like many other OpenBSD-related decisions, sudo was replaced by doas because of all the security-related issues with the code. Oftentimes, OpenBSD will replace a very functional solution, that has too many security issues, with one that has far less security issues and is, simply, good enough.


> ~2,936,000 changes

I don't think it makes sense to add all added and removed lines together and call it "changes": for example, this counts even a single character typo fix as 2 changes.


why on earth is sudo so complicated. All I want it to do is: ensure authorization, raise privileges, call exec.


> All I want it to do is: ensure authorization, raise privileges, call exec.

A lot of people do want to do more, especially in some corporate contexts people run very complex sudo setups.

Consider something like Linode; maybe you want some of the more experienced support people to issue some commands on some machines, without having full control. And you've got a gazillion machines so you don't want to setup each one individually (as well as revoke access once they leave). Things can get fairly complex pretty quickly once you move out of simple settings.

For my desktop machine, doas is perfect. For our servers it's fine too because we have just a few people with access. But I'm not everyone of course.

doas was explicitly written to NOT cover all use cases, and that makes it better for the (simpler) use cases it was intended to solve, at the price of not covering other use cases of course.


Maybe I’m misunderstanding you but doas handles the use-case you describe. I can enforce that some users can issue some commands on a given machine in doas.conf

As someone who manages infra including Linux and OpenBSD and does configure sudo and doas in this way, I’m pretty sure 99% of users would be fine with the simpler tool. Maybe the simpler, safer tool should be the default.


I don't think doas can integrate with PAM, LDAP, and all of that, and the possibilities doas.conf give you are vastly less than what the sudoers file gives you.

> I’m pretty sure 99% of users would be fine with the simpler tool

That probably sound about right, give or take a few %; it probably should be the de-facto default, with sudo being used when doas doesn't suffice. But the question was "why on earth is sudo so complicated?", and the answer to that is "because some people want/need complicated stuff".


From a security standpoint point you would want the opposite, the stricter doas on the more exposed servers and and the less strict sudo on the personal desktop.


That's the problem. We use sudo that autorizes user by it's SSH key via its auth socket... so we can essentially authenticate sudo via smartcard (Yubikey), and not keep the private key on user machine.

Some other folks use LDAP to get the sudoers files or even allowed ssh keys itself

There is also "just run thing as user" but also "set up same way shell would and pretend user logged as different user", first one is simple, second is a bunch of setup, copying env variables etc.

There is a good argument for splitting "just run app as different user" and "everything else that has to do with interactive shell and admins doing things on server" but now you have 2 configs to manage...


"ensure authorization" and "raise privileges" and "call exec" are all behind plugin-based architectures to allow for people to set up various ways to do things. The simple example: why do you only need to type in the password once per session/30 minutes calling sudo in most environments? How can people set things up with a hardware key? How do you make just some commands work and not others?

That being said I don't think sudo's code is complicated? It's big because it has all of these plugins supporting various mechanisms, but each file is pretty straightforward, and the control flow is really not that hard (after you get that it's plugins).


> All I want it to do is: ensure authorization, raise privileges, call exec.

And have an audit log? And clean the environment? In particular the path? Dynamic library path?

Still, I suspect "ensure autz" is the problem (implies Pam, 2fa, kerberos, etc etc).


Probably because of sudoers?


The documentation describes the configuration as a context free grammar using EBNF notation. This is impressive, but maybe a little more complicated than I want to get with a basic security tool. I suspect most people who don't have to modify it very often are going to secondary sources, like tutorials or stack overflow, and copying examples from there.


IMO, a more complex grammar allows for better descriptions. The only real type of grammar simpler than CFG is a regular expression. That's pretty limited, although (the older part of) CSS doesn't need more than that. But as soon as you want a nested construction, hierarchy or simply nested parentheses, you need a CFG. If it's difficult to configure, the problem is the (configuration) language, not the power of its grammar.

And there are excellent parser generators out there. You don't have to fear introducing bugs via them.


Yea I sometimes have to refresh my memory on sudoers or just search for what I want to accomplish, hoping that someone has already handled the potential security gotchas (eg, exact fullpath command should always be specified).

I agree, in some typical cases I only need to specify "<user> can become root" or "<user> can become <user of group>", kinda like doas already does I think.

I'll probably try out doas when the next such special need arises, then resort to sudo if doas is insufficient for some reason.


> [...] as a context free grammar using EBNF notation. This is impressive, but maybe a little more complicated than I want to get with a basic security tool.

I apologize if I'm being trite, but Context Free Grammar doesn't mean that the semantics of whatever that grammar describes is simple. It just means that it's simple to parse into ... something. Parsing a CFG is also not impressive in the slightest. It is, in fact, trivial since the 1970s. Anyway,

You shouldn't be scared of the CFG bit... you should be scared of the semantics.


I also wonder....

    function sudo { su -c "$@"  root }
though I guess half the struggle is enabling sudo without a password


"sudo" asks you for your individual password. "su root" asks you for a single root password


To be precise, whether sudo asks for your password or the target's password is configurable, and different distros have different defaults.


I wonder how many other tools we "take for granted" are similar to these these conditions.


All of them.


> It’s also been ported to Linux

Last time I checked there were several different ports floating around. Now I see at least Debian has chosen opendoas, I guess people have mostly converged to that one. Also fun stuff like https://xn--1xa.duncano.de/slicer69-doas.html

The point being that while openbsd doas is undoubtedly very nice, the linux ports are separate projects


Been maining opendoas for a while now. The main problem I have with it is that the "don't require a password for ___ seconds" timeout is unconfigurable as far as I'm aware. So you have to enter your password fairly frequently, which can be annoying on non-sensitive machines.

But for simple systems that aren't running complex user privilege management, doas is very much a great replacement.


I don't see any tests on the github. Is there some way to do pipelines for open source projects that wouldn't require funding? Would a free gitlab tier account for stuff like this be within the TOS? I just find it kind of crazy how most of the open source ecosystem has no static analysis or unit tests. I'm not criticizing, I'm trying to figure out how to contribute.


Github does allow (some amount of) GH Actions for free, as does Gitlab.


It does but it's kinda a pain for use for anything but scripting languages in my experience.

They way it scales doesn't fit well with C/C++/Rust/Scala/Java/etc. build systems and test runners.

I'm also having problems with it at work all the time, like task randomly being reported as canceled after they already passed. Or task after completion hanging for well over 30min until some internal timeout triggers and they then get reported as failure. Or a task being reported as succeeded to the UI and as failed to follow up tasks. (All issues I ran into just in the last week :=(, some might be caused by us having to use local GH Actio runners due to how GH Actions work, but I also have seen all this problems before we started using local runners so probably not).


> The main problem I have with it is that the "don't require a password for ___ seconds" timeout is unconfigurable as far as I'm aware.

https://wiki.archlinux.org/title/Doas#doas_persist_feature

https://wiki.gentoo.org/wiki/Doas

With the persist keyword doas can remember an authenticated user and will not require confirmation by password for five minutes.


Indeed, I've been looking around somewhat during off-time with a colleague how much we actually use of sudo, and what doas couldn't do. We're indeed looking at starting a migration, because some DNS based, LDAP integrated, PAM integrated, really complicated priviledge escalator is becoming kinda scary as of late.

The biggest difference we found is that sudo is a little more convenient to manage with a config management solution, since each piece of config management code can just drop a file in /etc/sudoers.d. With doas, we have to coordinate a bunch of parts of the config management manipulating one file, /etc/doas.conf. This always turns out a bit messy. But maybe we'll just merge everything into one big and somewhat messy monster doas-conf-template with a ton of feature toggles and loops and go from there.

But beyond that, almost all of our sudo rules are 2-3 patterns: Admin can sudo as everyone, zabbix/telegraf can run data gathering commands, and maybe some other automation triggers like pgbackrest wiping a postgres data dir during a restore, that's about it. All of those are pretty trivial doas rules all in all.


The biggest difference we found is that sudo is a little more convenient to manage with a config management solution, since each piece of config management code can just drop a file in /etc/sudoers.d. With doas, we have to coordinate a bunch of parts of the config management manipulating one file, /etc/doas.conf.

Apparently whether it's used is configured at build time, because I get different results trying it on Arch and Alpine, but doas absolutely has a /etc/doas.d

EDIT: Oops, apparently Alpine added that - https://git.alpinelinux.org/aports/tree/main/doas/configurat...


Mh. I'm kinda sad that this is a distro patch. If that was upstream, we'd be using doas at this point in a few sideline setups, I'd guess. Plus, exploiting a directory list or writing files to a rather niche and secure directory generally requires rather high degrees of privilege and usually implies that the system is owned as a whole anyhow.


> EDIT: Oops, apparently Alpine added that

This seems like a really weird thing for a distro to add themselves rather than upstream.


not really, alpine really wanted it. openbsd did not, it was a simple patch. you are probably going to maintain a patchset anyway(for the port to alpine) might as well maintain one more to support a simple feature you really want.


It looks like doas is missing some important features sudo has, notably full I/O logging and wildcard and in the newest version regex support for matching arguments. The latter could maybe be worked around with wrapper scripts, but I don't know what you would do for logging. And the password persist option is experimental, and not configurable on Linux.

If you don't need those features, doas is probably a good replacement. But if you do, it probably isn't an option.


> It looks like doas is missing some important features sudo has … and wildcard and in the newest version regex support for matching arguments.

Sometimes less is more. My immediate response to that is that it sounds like needless complexity which can be a source of errors, bugs and security-vulnerabilities.

What typical use-cases do these particular features have?


> What typical use-cases do these particular features have?

For the io logs: auditing. And in some cases such logs are necessary for compliance reasons.

For wildcards: allowing to run a command, but only if they supply a specific option that makes it less dangerous. Now, you do have to be very careful when doing that, but there are cases where it is useful and explicitly listing every variation of options that is allowed isn't practical.

I also forgot to mention sudoedit. Although, making something similar for doas would be pretty simple, so I'm kind of surprised there isn't something.


For wildcards;

Allowing a user to use systemctl with specific daemons, so ```systemctl * unit-name```, without a password. But anything outside of that I need a password.


It's actually good to not support such things, because it makes it way too easy to give more permissions than you intent to. In your example it effectively gives unlimited root access, as you can do `systemctl edit unit-name` and change the unit to run arbitrary programs as root.


Depends on what you do. If you have app server and use it to give access for developers to restart their apps, them getting root on the server is entirely irrelevant.

It's more so the curious dev don't just go sudo bash and changes stuff willy nilly then forgets what they changed.

We do avoid wildcards like plague but honestly regexp support would be more useful, then our devs could just have say

    ^/bin/systemctl (start|stop|restart|status) app-([a-z0-9\.\-]+)$
and be pretty safe.


Sure. But the simplicity of adding a wildcard makes it very easy for sysadmins to make a too simplistic configuration, which in turn ends up being a security vulnerability, maybe even if the code in sudo itself contains no faults.

To me this sounds like a feature for a non-default "root-manager", while the default should be kept simpler to avoid people falling into such traps.


You lost me somewhere between "regexp" and "pretty safe."


That's all well and true, but it's an expected downside which you'd see with any software which needs to be properly configured to run. If a user doesn't know they should take this seriously by ensuring that a tool which potentially grants root privileges is correctly configured, that shouldn't stop others who know better.


Yeah, why is that a command anyways...

But the point being that the users who have that also can just sudo anything anyways, and if an attacker is running shell commands, you're already in trouble.

I'm wondering if you're not right at this point though.


As meme as it is, Rust rewrite wouldn't be out of place...


> Sudo must be the program with the largest number of buffer overflows I’ve heard about. That news is repeating itself ever since I remember.

That you've heard about. There's two big reasons: (1) people often don't try to spend a lot of time finding exploits for userspace programs that don't open network ports or perform privilege escalation. And (2) when they do find exploits in those programs, they don't make it to HN.


I was thinking the same, this is the slackbuild for Slackware 15

https://slackbuilds.org/repository/15.0/system/opendoas/?sea...

It also contains some information on how to setup doas on Linux


There must not be a single suid program in a safe system. The concept of suid bit is flawed and nothing but a hack. You can build sudo-like functionality using ssh @localhost and additional root user with special shell.


That to me sounds like moving the problem from a privileged binary to a privileged daemon and putting a network stack in the middle. I don’t see how it solves anything. Any way you can secure sshd you can probably apply to the suid binary as well.


This requires enabling being able to log in as root, which I'd rather not enable.


And that sshd server is running as root, which is really just the same as setuid except with extra steps.


To be honest, your solution sounds far more hacky than a suid bit. A suid bit is effectively just a mechanism to implement privileged access in user space. I don’t see what’s hacky about that.


> Sudo must be the program with the largest number of buffer overflows I’ve heard about. That news is repeating itself ever since I remember.

libxml? zlib? PHP?

The déjà vs are many…


Or just uninstall sudo, at least on opensuse it is optional package.


[flagged]


Has absolutely nothing to do with the topic, and frankly, I rather trust a unified program with a set of functionalities done cleanly in a programming language over a set of random bash scripts trying to do the same, but failing. It’s not like you don’t have to communicate between them and it is goddamn bash.. I would make less error in binary.


A fun one. Buffer overflows tend to usually get associated with providing too much data; here's a nice case in which an overflow is triggered by providing too little. Seems like the buffer for storing the password was changed to be dynamically allocated, but only in some parts of the code; other parts still treated it as something that is at least nine bytes long (including the null terminator).

In practice, this means that if your password is only one char, then the actual buffer is two bytes long, and the seventh byte past the buffer is then zeroed/set to the null terminator. I wonder if and how this is exploitable.


Seems like the buffer for storing the password was changed to be dynamically allocated

When I see things like this, the first question I have is why? A password isn't going to be long enough to require dynamic allocation, so just use a fixed-size buffer. 255 is already generous and a good round number. The best solutions are often also the simplest.


This is why I love working in embedded. Our clients would never complain about these kinds of reasonable restrictions. There are tons of limits like this in our machines, which nobody notices but make my life much easier.

I guess things are different in the Linux/PC software world.


It also might explain the S in IoT.


I'd say not anymore, average microcontroller used in IoT got fat enough, nowadays even smaller chips come with AES acceleration too.

I'm frankly surprised some proper standard didn't pop up already, I guess closing the users in your own ecosystem as fast as possible is priority in the industry.

Good 80-90% of devices could be just "an MQTT connection + a bit of code to pair it up initially and feed server data" + a bunch of templates for how typical services should present themselves (so a light will just work with any compatible "control center"). Then just sell user subscription to your cloudy cloud IFTTT clone or a separate box to put in house that does the same job.


> When I see things like this, the first question I have is why?

Perhaps because they were still fighting the last war, where they were hurt by a greater-than-255-character buffer overflow vulnerability.


One reason I'd like to write passwords directly to a heap allocated buffer would be so that I can limit where that password exists in memory, ensure it's zero'd appropriately, prevent it being paged to disk, etc.


> When I see things like this, the first question I have is why?

My default assumption is three letter agencies surreptitiously adding back doors.


With how many careless programmers there are, writing massive quantities of security-critical code...why would they bother? (Outside of a maybe a few narrow, high-value contexts.) That's like surreptitiously working to make sure that there are plenty of cat pictures on the web, and that water flows downhill.


As a default assumption, this may be a bit conspiratorial. Inserting something like this into a git repo is relatively easy to track, and a given "contributor" could not do many such things without being caught. Not saying we should ignore the possibility, though...

But there are plenty of ways for such agencies to gain similar access, including any kind of closed code in BIOSes, drivers, firmware etc. Or by taking control of select infra, and injecting MITM features there (that would remain stealthy, and only activate for very select targets.)


> Not saying we should ignore the possibility, though...

Two suspected and one confirmed attempt in linux from a post 6 years ago: https://www.reddit.com/r/linux/comments/54in5s/the_nsa_has_t...

Found this while looking for a more recent one I vaguely remember involving a bad implementation of I think /dev/random


This should be a reasonable position to take. There's means and motivation present. The threat model should be taken seriously.


Because then you'll have another vulnerability created by too long passwords.


Not necessarily, as you can put a limit on how many characters you read from the shell. But you're right that you can screw up in both cases, I would just say that if you have a fixed length for the buffer it is a bit easier to handle it correctly.


Using a language that stores the length as part of the type is the real fix here.


So are you proposing to use dependently typed languages then? Typical languages like C++ don't make it very convenient.

    template<size_t N>
    void do_something(char (&s)[N]) { ... }
Now when you have a string of unknown length, how do you reify it with that template? In practice languages then have to keep around an unknown type argument at runtime. This is incompatible with most languages where types aren't known at runtime.


Why overcomplicate things so much? He probably just meant to use std::string. Programs like this definitely don't need to care about the few dozen bytes added by std::string overhead.


std::string stores the length as part of the value, not as part of the type. (That’s probably what nicoburns meant, but it’s clear what caused the confusion).


This for sure, but the codebases that we alreaduly have in C/C++ aren't going anywhere anytime soon.


Those that are proper C++ would use a string type instead of raw C strings.

And if those developers care about security, bounds checking would be enabled.

As for C there is hardly anything we can do other than keep fixing exploits until hardware memory tagging becomes a common feature across all major platforms.


You still need to compare the length against a maximum, wherever it's stored.


No, in that case the language will do that for you.


This might be exploitable in some cases. There has been a "heated" discussion in 2014 about off-by-one NUL byte heap overflow that lead to this blogpost from projectzero:

https://googleprojectzero.blogspot.com/2014/08/the-poisoned-...

There have been other examples where only a 1 could be written.


> the seventh byte past the buffer is then zeroed/set to the null terminator. I wonder if and how this is exploitable.

Well, looking at the upstream code, the original value is saved away before zeroing it out and then unconditionally restored after running crypt.

If sudo is single threaded and crypt() doesn't malloc() anything, I don't think that can be exploited. Worst case would be a segfault if the password was somehow close enough to a page boundary.


> I don't think that can be exploited.

glibc malloc() should be aligned to 2*sizeof(size_t), so strup("")[x] on 64-bit systems (with 16-byte alignment) can never crash or overlap another object where x<16

On 32-bit systems and with other mallocs you could potentially be reaching another page (like I think you are imagining) or trashing some bookkeeping bits which might crash free() but I cannot yet see how you would induce that, nor convince myself it cannot be done without spending more time thinking about it (something I'm reluctant to do with my afternoon)


Probably only with severely niche libc. Is there any libc that allocates data with granularity smaller than 16 bytes?


Very doubtful there is one. Seems like a total nothing burger


Sudo is a security boundary, it has to be rock solid and an issue that doesn’t immediately look exploitable is still a big deal. Sudo runs under the control of the attacker, it’s playing with fire!


Case in point: the whole speculative execution was only suspected to maybe be exploitable decades ago, and only now we have a bunch of PoCs


...which are still only useful under highly contrived conditions which require knowing so much about the target that it wouldn't be a practical concern.


> I wonder if and how this is exploitable.

Would be at worst a memory read past the inputted password, which wouldn't be super useful outside of a leak for another vulnerability but even that seems unlikely.


No, the code overwrote the 9th byte of the buffer to add a null terminator: https://github.com/sudo-project/sudo/commit/bd209b9f16fcd127...

So it's not just reading past the end of the buffer, but it's overwriting a single byte potentially belonging to another object. It may still cause a crash but it's relatively unlikely that it could cause something more severe.


> No, the code overwrote the 9th byte of the buffer to add a null terminator: https://github.com/sudo-project/sudo/commit/bd209b9f16fcd127...

Ah that makes a lot more sense.

> So it's not just reading past the end of the buffer, but it's overwriting a single byte potentially belonging to another object. It may still cause a crash but it's relatively unlikely that it could cause something more severe.

Yeah I agree that nothing severe should come from it. The allocations are probably larger then the size of the buffer being used so it may not even right off the end of its own allocation.


I don’t understand how this can be correct:

    if (pw_len == DESLEN || HAS_AGEINFO(pw_epasswd, pw_len)) {
 strlcpy(des_pass, pass, sizeof(des_pass));
 pass = des_pass;
    }
Doesn’t that truncate your password if it happens to have DESLEN characters?


It is a very known exploit. Easily found with the stupid fuzz tests but even easier found with tests that tests all edge cases. You have to have a set of complete amateurs of coders to end up with this problem in production.


It is funny what you get downvoted for in this garbage forum. 15 years ago we built stuff in C and used cheap commercial available tools that detects EXACTLY this issue. There is no excuse to end up with this in prod 2022. Amateurs.


15 years? Lint was created in 1979 exactly to track down common errors in C, and until clang static analysis it was largely ignored.

No wonder that these kind of tooling keeps being ignored until we get liability in software products.


It looks like this only affects DES passwords. Glibc has supported other hashing algorithms for a very long time and most Linux distros have used them by default for years. I don't think there is a way for an unprivileged user to choose DES if it's not the default, so it's very unlikely this can actually be triggered.


Very good point. And, overriding defaults would mean that you have sufficient knowledge to know what not to choose. So, the practical impact of this is virtually nil.



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?


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?


Seems to float around 0.005s (using "time sudo -k" to avoid timing user input), so yeah, x3000 = 15 seconds. Very noticeable.

Or even the x100 from (G)GP, that's a half second. Sometimes spiking to a full second.


I have once seen a proposal to make any sudo call wait for 10 seconds before doing anything so that the person running it has a moment to thing about what they just did do (and have ~10 seconds to ^C cancel it).

The person arguing also brought up that normally anything needing sudo should be automatized so that should be fine.

I'm not doing enough system administration to judge if that is a sane idea or not ;=)


That might be a reasonable idea but the time probably shouldn't be imposed by performance constraints.


Does it say somewhere that non-neteork-io PAM modules are supposed to be constant time?

  def add_noise(t=10):
    time.sleep(t-1)
    time.sleep(
      uniformrandom(min=0,max=1))
Constant time: https://en.wikipedia.org/wiki/Time_complexity#Constant_time

(Re: Short, DES passwords https://en.wikipedia.org/wiki/Triple_DES :

> A CVE released in 2016, CVE-2016-2183 disclosed a major security vulnerability in DES and 3DES encryption algorithms. This CVE, combined with the inadequate key size of DES and 3DES, NIST has deprecated DES and 3DES for new applications in 2017, and for all applications by the end of 2023.[1] It has been replaced with the more secure, more robust AES.

Except for PQ. For PQ in 2022: https://news.ycombinator.com/item?id=32760170 :

> NIST PQ algos are only just now announced: https://news.ycombinator.com/item?id=32281357 : Kyber, NTRU, {FIPS-140-3}? [TLS1.4/2.0?]


I'm not sure I follow this comment.

Adding a random amount of time seems like a reasonable thing to do.

Not sure what the links are all about, or the discussion of time complexity... I mean, there isn't an "input size" to talk about big-O scaling anyway, in the case of sudo.


Should the time to complete the (single-character) password-hashing/key-strengthening routine vary in relation to any aspect of the input ?

Timing attacks > Avoidance https://en.wikipedia.org/wiki/Timing_attack


That assumes that sudo the executable taking longer would linearly increase the time when in fact your OS loaded the exe into memory, created a process, allocated memory and let it go. A significant amount of time was just that, nothing related to the program’s job.


"time /bin/false" and "time /bin/true" consistently give me 0.001s though


“ When used alone, the -k (kill) option to sudo invalidates the user's cached credentials.”

IO wouldn’t get slower though, and likely that takes the majority of its running time.


I am seeing an average of 0.0008 over 100 runs on Linux (i.e. less than a millisecond).


Careful, admiral Hopper will give you an earful if you disrespect milliseconds.


Ah, fair enough, that's a bit high of a multiplier.


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?


Because C can run on almost everything? For example, take Doom and the whole "Can it run Doom?" meme


Except for some weird architectures, where C is supported, C++ is as well.

And if either GCC or clang are supported, they support safer languages than C and C++ on their standard collection of frontends.


How many architectures run Flatpak that don't have a compiler for any safer systems language? I don't think you run Flatpak on weird embedded chips, but maybe I'm mistaken.


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.


sudo feels like a broken concept to me in general.

sudo make install, ok, great, some of the many operations you need to do requires privileges? Better give elevated privileges to all operations!

Even worse with GUI: enter your password to install. Now I have absolutely no clue what the scope of sudo is.

Of course I don't want to enter my password for all individual cp and mv operations, but if sudo had a better/smaller scope that'd be great.


The real broken concept here is root. Why do I have to give a process the ability to do anything it wants with the system if I want it just to write to a file in /etc, or to bind to port 80?

On the other hand, having to always explicitly specify all the fine grained capabilities a process might need is a pain, too.


Port 80 doesn't need root access. Have an administrator `setcap cap_net_bind_service=+ep /your/binary/here` and you can use any port you want.

Files within /etc do, for security reasons, but there's no reason why you couldn't use user groups or other ACLs to secure those folders.

chown /etc to nobody:wheel and chmod it to g+rwx; users in group wheel will now be able to manage /etc. You've got to make sure you set your umask right if you do use sudo for /etc again, but that's also just part of your system configuration.


Changing ownership of /etc/ and directories under it like that sounds fine in theory but in practice breaks in many ways.

I did some extensive testing of this some years ago (on Debian/Ubuntu) and many system services and tools expect/require these directories to have specific ownership and permissions.

In the context I was experimenting with it was pretty simple too - renaming the UID 0 'root' account to some other name. That revealed that many tools actually test for "root" (the string) not uid == 0.

As I dug into the code of those tools I found many would also check and insist on particular ownership and modes on the directories and files.

I forget which one really annoyed me, but 'all' I wanted to do was allow members of group 'adm' to read/write into a particular sub-directory of /etc/ but the service would bail out if the directory wasn't owned by "root":"root" (or 0:0) and had 0700 permissions which is a pain when wanting to run services unprivileged and using 'setcap' to enable capabilities without starting as UID 0 and dropping privileges.


An alternate approach is to set the sysctl for this:

    net.ipv4.ip_unprivileged_port_start=80
Or whatever port you want unprivileged to start at. If you set it to 0 it means any user can bind to any port < 1024.

Ref: https://www.kernel.org/doc/htmldd/latest/networking/ip-sysct...


> Have an administrator `setcap cap_net_bind_service=+ep /your/binary/here` and you can use any port you want.

And remember to do it again every time the binary is updated :/

> chown /etc to nobody:wheel and

Bad idea! nobody is supposed to own no files at all. You run untrusted services (or untrusted users without account; something like anonymous FTP access) as nobody. This would potentially allow the least trusted entity to change your configs.

Apart from that. Since root can read any file anyways there is no reason to change the owner. And some programs may complain if the configuration is not owned by root.


> And remember to do it again every time the binary is updated :/

Depends on the way the file is replaced; if it's overwritten and not deleted + created, the flag should stick around I believe.

> Bad idea! nobody is supposed to own no files at all. You run untrusted services (or untrusted users without account; something like anonymous FTP access) as nobody. This would potentially allow the least trusted entity to change your configs.

You're right, should've used root:wheel rather than nobody:wheel. Oops...


Yes, having to always explicitly specify all the fine grained capabilities a process might need is a pain, too.


With Ubuntu's AppArmor you can run a lot of software without hassle because the ACLs come with the OS package.


Having a process request its required capabilities and sudo displaying that list to the user, who can agree to sudo giving giving them only those capabilities would be good.


Being able to write to /etc/ is effectively just granting full access, since there's lots of things in there that can run code.

Doing fine-grained access is really hard; even without "root" you still have things like, say, "archive_command" in postgresql.conf which will allow running people to run arbitrary commands as the postgres user, and is that really what you want? There's lots of little things like that ranging from application configurations to crontabs to your init system.


Go ahead, send your commits to the Linux kernel then.


Sudo feels like a broken concept to me because it's there to protect the machine and other users.

But these days many computers are only used by one user.

Everything I care about on my computer is readable by my user and a program running as my user could put fake binaries in my path.


This is why the concept of "granular permissions" is so important on modern pcs, and I personally think linux is severely lacking in this regard.

Flatpack et al. have improved this situation somewhat, but come with their own drawbacks. Linux needs a central application-level permission system like Android, where I can grant/revoke e.g. internet access to applications. Frankly, I should never have to use sudo to install anything in my daily life, that is unfortunately not the case with the common ubuntu install, and will probably stay this way for a long time.


Yeah, for the most part today any user who is logged in is somebody I trust with the machine. What needs to be restricted is what _applications_ can do.

My browser shouldn’t ever be allowed to to write to /etc/shadow regardless of whether it’s running as root or not. AppArmor gets us part of the way there but the UI to make everything play nice is too difficult.

Android’s security model makes a lot of sense to me, and from what I understand it’s all based on top of normal UNIX user/group privileges, just with per-app users/groups. I’d like to see more desktop distros experiment with it.


Could you have a system where each capability has its own group, and each executable has capabilities represented by their group memberships? Then it would be easy to build a UI on top of those groups to manage fine-grained permissions.


For desktop use, sudo let's you elevate your permissions as necessary (polkit kinda replaces some sudo stuff, but similar concept). The reason you want this is when you run anything, it will _by default_ run as your unprivileged user, not root. That is a huge security benefit and pretty standard across desktop OS these days.

Now on a server, sudo for a single user probably doesn't make sense, just use root and keep it simple.


> That is a huge security benefit and pretty standard across desktop OS these days.

But is it really though? That's the parent was alluding to.

I have the same feelings - all my important data are readable/writeable as my user, if I somehow manages to run a malicious program as my normal user it's game over as far as I'm concerned, having root would cause no extra damage.


Root access can be more insidious, like adding a crypto miner in the background or some other kind of virus masquerading as a system process. Your data would still be there, just silently being exfiltrated, along with your keystrokes/passwords.


Are you suggesting running everything as root?

As in when you setup a new vm or whatnot, that you shouldn't create a user account to run thing as?

Does this include things like nginx not dropping privileges to run as a user?


With just one user managing the server, for sysadmin tasks like SSH, use root, especially if you're going to sudo everything you do anyways. For services, they should still run as unprivileged users.


A - I have access to quite a few *nix servers, where multiple login users and/or services with district UIDs are a thing.

B - Not sure how practical most of this is yet, but there's cool stuff around isolating individual programs even on single-user machines.

C - My desktop has a couple things that listen on the network, and it's nice that they only have access to specific things.


Well, kinda. For user, sure, but we could definitely get some security from having more granular permission for apps that the user runs (without going into extremes like Qubes OS).

For example, sound demon like pulseaudio runs as your user (...for some reason, fucking Lennart) but it really should not have write access to anything aside from its own config and for 99,99% users also not have access to read anything your user owns aside from its own config.

Even browsers should probably be limited, or user should at least get prompt, there is little reason to allow browser to dig around your system willy nilly, let alone in locations like ~/.ssh


To be fair, it's the permission model that's not kept up with use cases. On a multiuser system sudo makes a lot of sense.


I feel that most computers may be used by 1 user but belong to someone else with their own requirements as to what is permissible. Company laptops seem to be more common than personal machines. Most will just have iPads and phones For personal use.


You can sudo to other users besides root.

For installing things, you generally need write permissions to /usr/bin and likes. So you could create an user with such privileges and sudo to that.

The real issue, I think, is Linux not being capability based, so there's no programmatic way for scripts to communicate which sort of permissions are needed.


> communicate which sort of permissions are needed

OpenBSD has something like this https://man.openbsd.org/pledge.2


Unfortunately not. Pledge is _awesome_, but it's a different thing.

Pledge protects the system from buggy well-intentioned, cooperative software that could have bugs. What's needed is something that protects the system from ill-intentioned, uncooperative software.


> buggy well-intentioned, cooperative software that could have bugs

Ugh, that's what I get for not reading before clicking submit...


SELinux was intended to address this very thing. It's a complex beast that people find too difficult to understand and thus usually it gets disabled.

I see this attitude in pentesting too on embedded systems. A developer encounters a problem they don't quite understand but the problem disappears when they run their app as root, so away we go.


You can just allow those smaller scope commands and nothing else in sudo.

That's a part of a reason for its complexity it does allow you to do anything between "make user be another user with all priviledges" to "just allow to run this particular command and nothing more".

Having one that had option for more limits would be interesting (say use cgroups to change running user but disallow command from modifying anything aside from this one single directory you specified) but, well, that's way more code that also needs to be secure...


> sudo make install

Even ignoring security issues, all of make getting elevated privileges can cause other issues as well.

All it takes is the incremental build system being a little finicky, and "sudo make install" could rebuild an object as root, and now one or more of your ".o" files are owned by root and your build directory is broken.


Sudo has two protective jobs. One is to completely prevent people from elevating if they aren't in sudoers. The second is a best-effort attempt at preventing people from blowing their own foot off, by running most commands without privileges.

If you are in sudoers and you are compromised, then there are like a million ways of getting root for a malicious program. They could override your sudo, override your terminal, override your shell, override your de, even override say "cat" so that instead of exiting when it is done, it starts a shell that mitms all your commands and waits for a sudo one.


set-uid is especially dangerous, so that's the best target for removal.


Why is "sudo 1.8.0 through 1.9.12" affected, but rhel8 shipping sudo 1.8.29 and rhel9 shipping sudo 1.9.5, are not affected?

<https://access.redhat.com/security/cve/CVE-2022-43995>

  Description:
  ... Sudo 1.8.0 through 1.9.12 ...
  Statement:
  The sudo package as distributed with Red Hat Enterprise Linux 7, 8 and 9 is not affected by this issue as it currently doesn't ship the affected code.
<https://access.redhat.com/downloads/content/sudo/x86_64/pack...>

  1.9.5p2-7.el9
  1.8.29-8.el8


<https://news.ycombinator.com/item?id=33467522>

Got it. Linux distributions (ex. RHEL) have --with-pam in configure, so not vulnerable (code not compiled). (If you have --with-passwd in configure, then passwd.c is compiled, and you are vulnerable, but Linux distributions do not do this.)

<https://ubuntu.com/security/CVE-2022-43995>

  sudo packages in Ubuntu are compiled with PAM support, so the vulnerable code isn't part of the binaries.
  Not vulnerable (code not compiled)


Alright, this is getting tiring.

Zig, Nim, Rust, D, V, whatever -- can't we just move on from C/C++ already? It's obvious they are not up for the job.


I do wonder if a dependently typed language like Agda or Idris would be a better choice for something like sudo. They are not terribly slow (to run), by today they are well-understood, and they can formally prove invariants about the program.


Could be. Having both strong static typing (and a more formal one) and less code will help a lot.


C and C++ are far from the same thing. That said, D does seem kinda nice so I wouldn't mind seeing some rewrites of critical infrastructure in it. Preferably something that'll benefit more from the rewrite than ls would.


Sure C++ is a tad better than C but compared to e.g. Rust and Zig it's pretty convoluted and verbose when trying to achieve things that they achieve with 2-5 liners.

And even if modern C++ is amazing -- I have no doubt it's improving all the time -- that doesn't change the fact that there are metric tons of C++ code out there that nobody will ever modernize. So C++ getting improved with time is sadly an almost moot point.

I'd personally advocate for Rust but I've heard people say there are a few other languages that allow you to achieve the same memory safety so, by all means, let's please start rewriting and make our everyday tools something different than a Swiss cheese of potential and actual security threats. It really is time.

The language doesn't matter, the outcomes do. And in terms of outcomes I maintain that C and C++ have not stood the test of time in terms of security and amount of foot guns. Too much sentimental value is attached to them as well and that doesn't help matters either.

We work with tech. We don't make love with it. We should all start acting like this is a job and not [only] a hobby.


> Sure C++ is a tad better than C but compared to e.g. Rust and Zig it's pretty convoluted and verbose when trying to achieve things that they achieve with 2-5 liners.

yeah, if one is stuck in C++98 mentality.


Like a ton of existing C++ code out there? :P

I don't make the rules, sadly I've been forced to leave code to never be upgraded again. I imagine it happens to many others.


Like a ton of code out there written by folks that don't care to update themselves, or not seen as business value to rewrite.

That doesn't change the fact how the recent versions of those languages look like in 2022.


I don't think we disagree because both of what we say is true at the same time. It's not either/or.



As far as I can tell this is a non-issue. A single byte is written potentially outside a dynamically allocated buffer but the original contents is restored before the function returns (sudo is single-threaded). At best it could be a crash, but even that is unlikely unless using address sanitizer or valgrind.


Come on :D CVSS of 7.1, Complexity Low, Availability and Confidentiality High. sure...


What do you think is an appropriate score? Looks reasonable to me.


Attack complexity High (chance for an attacker to get anything at all is very low), Availability None (you're not crashing any service that's running in the background) and Confidentiality Low (data leaked is not in the attackers control and not likely to be interesting). Adds up to a score of 2.9


IF you can execute code this way (which is an IF) then it's way more severe than a 2.9, and you could absolutely do anything you want with the system (you'll be root).

Complexity High isn't about what an attacker gets, it's about whether or not any specific configuration must exist for the attack to happen. For instance, if an app that talks to several services over different file transfer protocols has a vulnerability in only the FTP component, and these are not under attacker control, that's Complexity High.


Seriously, why is sudo so complicated? Most of the time, all sudo has to do is hash a password, check that hash against a file, and if successful, run a program as root.

Why can't we just have a minimal version of sudo that does just that and only that so the majority of smaller servers and home users can run sudo without fear of a security bug ever other month? Preferably using the same executable path so that everything else doesn't break.

It just seems like most of sudo's security bugs come from weird obscure features almost no one uses. Like that time sudoedit had a security issue. I didn't even know that command existed until it broke things, and it still seems pointless when you can just run "sudo nano" or "sudo vi".


sudoedit runs the editor as the original non-privileged user, which is nice if you're using a configurable text editor like vim/emacs so you're not suddenly using whatever (lack of) configuration the root user has setup. It can also be nice to know any other stuff a complex editor can do like running other programs won't happen in the privileged context.



This sort of fail isn't new to sudo, migrate to doas if you can - a much simpler(immensely) and less error-prone program.


Time to write sudo alternative in rust


`please` in fact does exist. NixOS even has a module for it. ;)

https://github.com/edneville/please



Please stop calling for a rewrite with the next language which is currently in trend. Use the right tool which fits your purpose. An example to learn: https://news.ycombinator.com/item?id=31089216

Lessons:

    * Serious bugs doesn't care in which language the error happens
    * C++ implementation was safe
    * Java implementation was unsafe
    * Test-Coverage would help...
PS: I don't say Rust is good/bad. C++ is good/bad. Or is good/bad. Neither about Java.


>Serious bugs doesn't care in which language the error happens

This just isn't true.

Buffer overflows are not possible with bounds checking.

Using a language that provides containers with bounds checked access methods would have prevented this. This isn't a point of debate or something, it's a fact.

C is virtually the only language that doesn't provide a safe way to access elements.

C++ provides bounds checking with std::array, std::vector and std::string using the "at()" methods. All Rust containers are checked by default. Pretty much every other language also is checked by default as well. All of these language's could have prevented this error and the other buffer overflow errors which there are tons of.


Sure but you wouldn't be reading a password into a std::array or std::vector in C++, you'd be reading into a std::string or possibly something like a std::stringstream. And both of those containers will handle sizing and reallocation for you.

If your point is that C++ lets you do unsafe things then yes, of course it does. But so does Rust.


I think you may be misinterpreting my comment a bit, I did not mean that C++ was bad here, but rather a large improvement.

My point was that in C++ (and others) you can completely prevent this entire class of errors by using the standard containers. std::string, just like std::vector and std::array provide the checked access methods which will prevent buffer overflows when used.

Almost every language other than C lets you access elements of a container safely, and oftentimes even the default methods for access are safe! In C++ there are compiler flags that make operator[] safe by default for all of the std containers too.


sudo has long history of bugs that would be impossible in Rust in the first place.

Yes, given enough care and effort you might write code that will not have those bugs, but not having a possibility (aside from unsafe{}) to have them in the first place is usually better approach.

Like, yeah, it is a dumb meme but in this case not without merit.


Overflow should be named hunter2 or sudoer2




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: