Live data from Hacker News

Heap-based buffer overflow in Sudo

qualys.com

91–100 of 328 posts

Re: Heap-based buffer overflow in Sudo

#91
post #78

Earlier quoted context omitted.

Another question is who wants to maintain four decades old GNU C soup? It was written at a different time, with different best practices. In some point someone will rewrite all GNU/UNIX user land in modern Rust or similar and save the day. Until this happens these kind of incidents will happen yearly.

Rewriting sudo is a weekend project*. Getting people to adopt it is a many-year political campaign.

That would indeed be a huge feat of programming skill! I refer you to the configuration file documentation to treat as a spec: https://www.sudo.ws/man/1.8.3/sudoers.man.html

Implementing a subset of sudo is a weekend project, for some values of useful.

Re: Heap-based buffer overflow in Sudo

#92
post #88
post #78

Earlier quoted context omitted.

Rewriting sudo is a weekend project*. Getting people to adopt it is a many-year political campaign.

You can bet your last dollar that if the "right" RedHat or Debian developer rewrote sudo with feature parity, it would be adopted by all major distros in a couple of months. It's the sort of thing nobody really cares about except OpenBSD (which wrote their own). The problem is feature parity. Most rewrites cannot guarantee that off-the-bat, so they end up struggling to persuade people to switch - why break stuff that…

Poettering to save the day with systemd-sudo?

Re: Heap-based buffer overflow in Sudo

#93
post #71

Earlier quoted context omitted.

Incidentally, after inspecting doas for a few minutes, I found two near-vulnerability bugs in it. The first bug lets any user cause doas to read out of bounds of an array, though not in a way that's exploitable. Well, it's arguably a bug in libc. If you run doas with a completely empty argv (argc = 0, so not even an executable name; the two systems I tried, Linux and macOS, both let you do this), getopt will exit wit…

Nice finds. I would agree that that's more arguably a bug in libc than in doas, but also note that the startup code for any language has to consider this case. As far as theoretical operating systems are concerned, this is a consequence of the System-V ABI, so any OS compatible with it would have the same issue. As for the integer overflow case, it's also highly unlikely to be exploitable, even if it were unsigned -…

[deleted]

Re: Heap-based buffer overflow in Sudo

#94
post #52

Earlier quoted context omitted.

Briefly going through their website (sudo.ws) I am seriously wondering why anyone would want to put some of those features in a privilege management tool.

Todd Miller is a sharp developer and core OpenBSD contributor. I can only imagine the deluge of requests and pressure he faces to expand sudo. There's no end to the crazy stuff corporations demand, especially when it comes to integration--audit, logging, ldap, etc.

> Todd Miller is a sharp developer and core OpenBSD contributor.

I wonder why OpenBSD wrote their own version. Could it be that, knowing how the sausage is made, they thought it was better to have a salad...?

Re: Heap-based buffer overflow in Sudo

#95
post #45

Earlier quoted context omitted.

No, complexity strikes again. I haven't used sudo in years, preferring to use doas now. Its essential code is less than 500 lines and it does everything I've ever used sudo for, and that includes much more than `sudo `. $ man doas | wc -l 58 $ man doas.conf | wc -l 101 $ man sudo | wc -l 741 $ man sudoers | wc -l 3254 And a bonus: $ man sudoers | grep -C1 despair The sudoers file grammar will be described below in Ex…

But if sudo were written in Rust, it could have the same level of complexity and not be vulnerable. Yes, it would still be vulnerable to logic errors, like the last famous sudo bug where you pass -1 as the UID. But it wouldn't be vulnerable to this. (And this isn't the first memory safety bug to be found in sudo.) Yes, sudo's complexity is useless for 99.99% of its users. But wouldn't it be nice if the result were me…

> But if sudo were written in Rust, it could have the same level of complexity and not be vulnerable

I'm puzzled that we don't have a memory-safe ABI (e.g. amd64-safe) and runtime for C so we could just compile things with

    clang -safe sudo.c
to avoid memory errors. I'm fine with sudo (or whatever) taking a 60% performance hit to be more reliable - processors are thousands of times faster now than they were in 1980 when sudo was written. If we had a memory-safe ABI for C/C++ in common use its performance overhead could probably be reduced significantly over time due to implementation improvements, and we might see hardware acceleration for it as well.

There are a number of proof-of-concept memory-safe compilers for C using fat pointers, etc., but memory safety hasn't made it into gcc or clang. 64-bit CPUs can help because you can repurpose address bits. Even Pascal (which is largely isometric to C) supported a degree of memory safety via array bounds checking. I believe Ada compilers also support memory safety. PL/I was actually memory safe and is why Multics never had any buffer overflows. Obviously Rust is memory safe, but for a lot of legacy C code it is impractical to rewrite everything in Rust but eminently practical to recompile it with memory safety turned on.

Re: Heap-based buffer overflow in Sudo

#96
post #71

Earlier quoted context omitted.

Incidentally, after inspecting doas for a few minutes, I found two near-vulnerability bugs in it. The first bug lets any user cause doas to read out of bounds of an array, though not in a way that's exploitable. Well, it's arguably a bug in libc. If you run doas with a completely empty argv (argc = 0, so not even an executable name; the two systems I tried, Linux and macOS, both let you do this), getopt will exit wit…

Nice finds. I would agree that that's more arguably a bug in libc than in doas, but also note that the startup code for any language has to consider this case. As far as theoretical operating systems are concerned, this is a consequence of the System-V ABI, so any OS compatible with it would have the same issue. As for the integer overflow case, it's also highly unlikely to be exploitable, even if it were unsigned -…

> I would agree that that's more arguably a bug in libc than in doas, but also note that the startup code for any language has to consider this case.

This is true, but for a language where dynamically sized arrays are a standard data type, the most natural thing to do is to start by collecting the arguments into an array (maybe copying the strings at this point, maybe not). All further argument parsing is done with the array and is thus bounds-checked. I checked Rust's standard library and sure enough, it follows this pattern. Though, I could imagine some hypothetical startup code messing up the argc=0 case if it tried to separate argv[0] from the rest of the arguments while constructing the array.

> Anyway, I like your comment, but I'd recommend a different moral to this story: in the space of 47 minutes you were able to conduct a reasonably thorough audit on the doas codebase. Wanna give that a shot for sudo now?

Fair point. (And I didn't downvote you.) But in my opinion, that just confirms my view: ideally you want both simplicity and memory safety.

Re: Heap-based buffer overflow in Sudo

#97
post #45

Earlier quoted context omitted.

But if sudo were written in Rust, it could have the same level of complexity and not be vulnerable. Yes, it would still be vulnerable to logic errors, like the last famous sudo bug where you pass -1 as the UID. But it wouldn't be vulnerable to this. (And this isn't the first memory safety bug to be found in sudo.) Yes, sudo's complexity is useless for 99.99% of its users. But wouldn't it be nice if the result were me…

>But if sudo were written in Rust, it could have the same level of complexity and not be vulnerable. This is not true. Complexity breeds bugs, including security bugs, and memory safety doesn't change that. Your example is a good one - here's another: doas once failed to limit the environment variables which are passed to the child process, which could be used to nefariously influence the program running (e.g. with L…

A lot of your statements are pretty strong, and imo totally incorrect.

> Complexity breeds bugs, including security bugs, and memory safety doesn't change that.

Yes, memory safety changes that radically.

> A simpler program will generally be more secure than a complicated one, no matter what language either is written in.

Disagree, but the statement is really weak anyways, especially since 'complexity' is an ill-defined term. More features? Cyclomatic?

> urthermore, rewriting an established program from one language to another will always introduce more bugs than it fixes, and more severely the more complex the program is.

Should be obvious to anyone that this isn't true.

> The single best way to improve security is to reduce the attack surface,

Not true, but it's a great way to start.

Re: Heap-based buffer overflow in Sudo

#98
post #78

Earlier quoted context omitted.

Rewriting sudo is a weekend project*. Getting people to adopt it is a many-year political campaign.

That would indeed be a huge feat of programming skill! I refer you to the configuration file documentation to treat as a spec: https://www.sudo.ws/man/1.8.3/sudoers.man.html Implementing a subset of sudo is a weekend project, for some values of useful.

That's part of the dark outcome of so many untested features: it makes it easy to cast FUD upon any potential replacements. As we have no black-box test suite that shows `sudo` implements all of these features, so we also cannot have faith that any replacement would. Ideally it should be possible to run sudo's black box tests against any potential replacement. To start with, we need those tests.

Re: Heap-based buffer overflow in Sudo

#99

Earlier quoted context omitted.

>But if sudo were written in Rust, it could have the same level of complexity and not be vulnerable. This is not true. Complexity breeds bugs, including security bugs, and memory safety doesn't change that. Your example is a good one - here's another: doas once failed to limit the environment variables which are passed to the child process, which could be used to nefariously influence the program running (e.g. with L…

A lot of your statements are pretty strong, and imo totally incorrect. > Complexity breeds bugs, including security bugs, and memory safety doesn't change that. Yes, memory safety changes that radically. > A simpler program will generally be more secure than a complicated one, no matter what language either is written in. Disagree, but the statement is really weak anyways, especially since 'complexity' is an ill-defi…

>Disagree, but the statement is really weak anyways, especially since 'complexity' is an ill-defined term. More features? Cyclomatic?

I'm not sure of any definition of complexity you could appeal to which makes my argument weak.

>>rewriting an established program from one language to another will always introduce more bugs than it fixes, and more severely the more complex the program is.

>Should be obvious to anyone that this isn't true.

The opposite is painfully obvious: (1) Writing code causes bugs. (2) Rewriting an established project involves writing more code than leaving it would. (3) Writing all of that new code will introduce new bugs which were not present in the original.

Re: Heap-based buffer overflow in Sudo

#100
post #96

Earlier quoted context omitted.

Nice finds. I would agree that that's more arguably a bug in libc than in doas, but also note that the startup code for any language has to consider this case. As far as theoretical operating systems are concerned, this is a consequence of the System-V ABI, so any OS compatible with it would have the same issue. As for the integer overflow case, it's also highly unlikely to be exploitable, even if it were unsigned -…

> I would agree that that's more arguably a bug in libc than in doas, but also note that the startup code for any language has to consider this case. This is true, but for a language where dynamically sized arrays are a standard data type, the most natural thing to do is to start by collecting the arguments into an array (maybe copying the strings at this point, maybe not). All further argument parsing is done with t…

Aye, I agree. But if we consider that case, a similar mistake could be made: hard-coding argv[0]. The result is different, in that the program just aborts, but it's still the Wrong Thing To Do, and in both cases it never leads to anything exploitable. Bugs are bugs, no matter what language. We could come up with examples all day. Just head to your nearest Rust program's bug tracker :)
Post reply on HN