5 ms·
I agree with your post but I wanted to chime in that LD_PRELOAD isn't even a problem in this scenario! If you're running code as you then the permissions model
by throwaway09223 4y ago
I agree with your post but I wanted to chime in that LD_PRELOAD isn't even a problem in this scenario! If you're running code as you then the permissions model assumes you can modify/control it. Always. Whether by LD_PRELOAD, or by a debugging interface such as ptrace(2). Or just by copying the binary, modifying it and running that instead.
We already disable things like LD_PRELOAD or ptrace(2) for setuid scenarios, so again there's no issue.
> "You should always drop privilege after getting whatever handle you need"
Wanted to chime in here too. PAM doesn't require root -- the initial assumption is wrong. You can't just drop privileges in a PAM module though, because it's a function running in the application proper so any process-global state change would impact the calling process.
What you can do (and what some PAM modules I've written actually do) when invoked as root is you can seteuid() to a non-root user as long as you're sure to seteuid(0) back to root before returning from your module.
> "TCP adds a magnitude of complexity"
Erm, so most PAM modules already do this. This is how pam_ldap, pam_kerberos, etc all work. No big deal. But it also doesn't need to be changed.
Honestly, there is a real need for a service for updating local directory files like /etc/passwd. It's very stupid that we have individual binaries with ad-hoc C code editing /etc/passwd in 2022. But the right solution is something generic and modular more akin to a local ldap instance -- not reinventing the wheel with friggin' systemd.
- _8j50 4y agoFor most of what you said, you are right and I didn't know that, but that doesn't contradict my opposition to the original argument, you just have a better and more correct reasoning. That said, perimeter based security is dead, as in 2000's dead. There is no such thing as "if you control _____ we assume _____". No, unless explicit permission is granted by the thing controlling information, permission is denied. This could be accessing a file (basic unix acls will do) or connecting to a network service (e.g.: mtls). With LD_PRELOAD and ptrace() an explicit permissin isn't granted to the debugger by the specific debugee therfore regardless of who the user is or file acls permission must be denied. Even search order hjacking (I am only familiar with windows dlls not .so's for the record) is a vulnerability even if it is the same user running it because it can be used by threat actors for devious reasons. Especially global ld_preloading, that just has to go away. Find another way, look at macos!! > What you can do (and what some PAM modules I've written actually do) when invoked as root is you can seteuid() to a non-root user as long as you're sure to seteuid(0) back to root before returning from your module. Isn't that what I said by "drop privilege"? I've only used pam_exec so I never had to deal with this with pam but in general when I need root, I get whatever api handle, socket,etc.... and change uid/gid to a low-priv user. > Erm, so most PAM modules already do this. This is how pam_ldap, pam_kerberos, etc all work. No big deal. But it also doesn't need to be changed. Yes, some PAM modules, that's why it is modular as opposed to the suggestion I wad disagreeing with which is having one process that does TCP and everything else you can think of and that's fine because sandbox. You can write simple pam modules or complex ones with TCP, custom protocol,etc... and that marvelous modular architecture is not faulty and should not be replaced by a giant complex systemd process.
- throwaway09223 4y agoRight, we agree! I'm just adding some more information. > "With LD_PRELOAD and ptrace() an explicit permissin isn't granted to the debugger by the specific debugee therfore regardless of who the user is or file acls permission must be denied. " Explicit permission is in fact granted because they are running as the same user. There is a permission check on attaching gdb which is using ptrace(2). Regarding LD_PRELOAD or other linker instructions, again there is an explicit permissions check: In this case, the permission is the execute permission on the original binary. If you have permission to execute then you can set any linker parameter you wish, or even use a non-system provided linker! There's nothing stopping a user from compiling their own linker and using it to run a system binary, so long as it's running as them and not setuid as another user. > "Even search order hjacking is a vulnerability even if it is the same user running" It's not, and this kind of thinking is evidence of a faulty security model. Linker configuration is just one small aspect of invoking an executable. You can always simply copy and edit the executable instead, as I mentioned in my previous post. Or you can always use your own linker. Or bring your own statically linked binary, with no linking to system libraries at all. Looking for this kind of thing might be useful as a signal on an otherwise locked-down system (is development happening? Why?), but it has no place in a cohesive permissions model for a general-function workstation. It really cannot be a functional part of a well designed security architecture for a system which allows for software development. > "Isn't that what I said by "drop privilege"? I've only used pam_exec so I never had to deal with this with pam but in general when I need root, I get whatever api handle, socket,etc.... and change uid/gid to a low-priv user." Typically "dropping privileges" means setting the ruid (real uid), irrevocably becoming the lower-privilege user. This is the "grab a resource and give up access" model. This can't happen with PAM because it's a function not a separate process and it needs to return holding the same permission state it was called with. pam_exec would be forking and setting the uid in the child process prior to exec. In a single process scenario where a function must return with the process state unchanged, the euid (effective uid) can be set to a lower-privilege user. The ruid remains 0, so privileges aren't permanently dropped as they can be restored at any time with a subsequent seteuid(0) call. It's more a temporary lowering of privileges. This is not threadsafe, of course, as privilege is process-global state. > "and that marvelous modular architecture is not faulty and should not be replaced by a giant complex systemd process. " Agreed!