I'd like to believe this isn't common anymore for new projects?
Inconsistent usage of braces, no clear memory ownership or life-cycles, zero tests.
I agree that absence of tests isn't great, and is very common with many C-based projects. But the rest of your comments reads like "ooh, it's C, disgusting!". I hope, I'm wrong.
It's true you could use a privileged spot in the filesystem and set things up to use that by writing some simple extra software, but it's equally true that you could lock down a TCP socket to a specific process with about the same amount of work.
Bottom line is that you need to validate your input from outside the process if you're running in a privileged context[1], and atop didn't.
[1] It's not mentioned in the linked email, but I assume the core problem here (and the reason it got a CVE number) is that the atop binary is setuid?
Can you educate me? I'm familiar with SO_PEERCRED that returns the user/group/pid on the other end. Would you then checksum the exe of the pid from /proc?
But really the simplest thing would just be to use a port <1024 so that only root can open it. That's literally what the feature was for. You can still be "attacked", but only by someone who already has local root.
Once more: people wanting to make this security bug about the specific socket family in use are doing bad security analysis. There's nothing wrong with TCP, the app just did it wrong and failed to recognize the security boundary being crossed.
I remain absolutely dumbfounded how people in this subthread are going to the matresses trying to explain why Unix sockets are great and TCP isn't, when they both suck in exactly the same way and the correct answer is "validate your input" and not "use a different API".
You seem to be misunderstanding the scenario I'm describing: I have a daemon that runs in a privileged context (as root.) I have a client that connects to the daemon, as any user on the box. The client cannot be run as root because the user does not have permission to do so.
I want to ensure that only my client can connect to the daemon. I can't use user/group permissions, because I don't care what user/group has access. I want to make sure a specific process (or a specific binary/executable) has access. To quote the comment I initially responded to:
> it's equally true that you could lock down a TCP socket to a specific process with about the same amount of work.
On a Unix machine, this is often done by creating a group to use for access (e.g. a docker group.) This works to lock down a TCP socket to a specific group but not to a specific process. Using shared secrets stored elsewhere on the box also doesn't help here, since any other process could access those secrets.
The best I know of is using something like XPC on macOS, using SO_GETPEERCRED and checksum'ing the pid out of /proc/<pid>/exe, or perhaps using some other platform-specific code signing API.
I was excited to hear that it was easy. I'm disappointed now.
For TCP, your only easy option is to have port <1024 - but that requires root. If you want a dedicated user, then TCP requires hacks - like creating a cookie file in some protected location, like XAuthority does.
But if you have a protected location, why even bother with all this? Just create a UNIX socket there directly, after all the difference is only in connect call, read/write loop is the same. And as an extra bonus there is much better visibility, and zero chance of someone accidentally grabbing your magic number.
Unix sockets are really underappreciated.
I'm interested in this as I've been working on a problem myself where I'm trying to restrict access to a specific process (or a specific application), without much care for which user is running that process. On mobile, there are lots of solutions for protected locations (as you suggest) that allow sharing files across applications within a publisher, for example.
Restricting use to "specific application for any user" sounds pretty dodgy, security-wise. Linux makes no guarantees that processes are protected from executing user, so it is entirely possible your process has the right name, but runs different code. LD_PRELOAD and ptrace immediately come to mind, but I am sure there are other methods too.
That's why Android makes a unique UID per app - this turns insecure "restrict by process name" problem into well-supported "restrict by UID/GID".
(And if there no need for security boundary, and you only want convenience check to avoid non-malicious mistakes? Then just hardcode magic string in your app and check it as a part of protocol.)
So put the socket in /run instead of /tmp?
I'm no expert, but this appears to be where they belong, and it appears to solve the problem. From https://refspecs.linuxfoundation.org/FHS_3.0/fhs/ch03s15.htm... : "System programs that maintain transient UNIX-domain sockets must place them in this directory or an appropriate subdirectory as outlined above." ... "/run should not be writable for unprivileged users; it is a major security problem if any user can write in this directory."
Hmm, good point. I think we made opposite assumptions about that.
If the daemon does run as a root, then no extra software is required. For Unix domain sockets, you can trivially create your socket in /run, and for TCP, you can trivially use a port below 1024.
If it doesn't, then some extra software or configuration is required in either case.
I tried looking it up, and I think it does run as root[1]. But I also found that the daemon uses a Python library to get GPU stats, and root might or might not be required depending on how the GPU software is configured[2]. So it could have gone either way.
---
[1] That's how I read this: https://github.com/Atoptool/atop/blob/master/atopgpu.service
[2] See https://github.com/gpuopenanalytics/pynvml/issues/19
How, actually? With UNIX sockets it can be a matter of setting file ownership and mode (at worst, a chmod and a chown).
What's the equally simple way to restrict access to a locally listening tcp socket?
What this "if" qualifier? You need to validate all input from outside the process. Whether the process is privileged or not is, frankly, not really relevant.
(I submitted a blog post a few days ago explaining "Parse, Don't Validate" in plain C, but it didn't get any traction).
Not all tools are designed to accept input from outside a security boundary. Obviously atop isn't one, but the world is filled with software that misbehaves on bad input. Ever DDoS your build system by misconfiguring something? Crash a running program by removing a cache directory (or unpacking a tarball on top of it)?
It's very rarely a bad idea to fail to validate input. But it's for sure not always a requirement either.
And to be blunt, it's not really possible either. You write "insecure" parsers/interpreters/whatever probably every day, we all do. And you "know" when it's safe and when it's not, I'm sure. But my point is that if that knowledge isn't based on at least a little bit of rigor ("crossing a privilege boundary" in this case), you're probably going to do it wrong.