PAM is crusty and has a bad architecture. The fact that it's written in C, and is linked into another program as a library makes it impossible to fully isolate it from its host application, and exposes it to a myriad possible exploit points.
Even wrapper binaries are not a great idea because of how UNIX works.
fork() + exec() means the executed binary inherits a lot of state from the caller. Open files, signals, environment variables, chroot, mlock, resource limits, seccomp... there's a myriad of mechanisms that an executed binary can be exposed to, and even if it somehow perfectly takes all of them into account and defends itself against any possible malicious manipulation, the next kernel version could add a new one.
That's why I think a sane, modern version of PAM should be a service and only communicate via a UNIX socket. That way you vastly reduce the attack surface, and allow locking up the PAM bits into their own, well defended box.
The calling convention is C, but you can write PAM in any language.
"and is linked into another program as a library makes it impossible to fully isolate it from its host application"
Huh? You can never isolate the client side code. You will always have something in your app.
"I think a sane, modern version of PAM should be a service and only communicate via a UNIX socket."
So, write a module that talks to a socket. That's how like half of the PAM modules already operate. You will always have to have code in the application to talk to whatever oracle you're using. What you're describing here isn't any different from how PAM already works.
I'm being serious, as exactly what you're describing sounds an awful lot like their micro-kernel approach. At least as of the last time I looked into it.
This sort of already exists in the form of sssd. In particular, pam_ssd.so connects to sssd's PAM responder & acts as a dumb client library to the authentication logic within the sssd process.
dale_glass|3 years ago
PAM is crusty and has a bad architecture. The fact that it's written in C, and is linked into another program as a library makes it impossible to fully isolate it from its host application, and exposes it to a myriad possible exploit points.
Even wrapper binaries are not a great idea because of how UNIX works.
fork() + exec() means the executed binary inherits a lot of state from the caller. Open files, signals, environment variables, chroot, mlock, resource limits, seccomp... there's a myriad of mechanisms that an executed binary can be exposed to, and even if it somehow perfectly takes all of them into account and defends itself against any possible malicious manipulation, the next kernel version could add a new one.
That's why I think a sane, modern version of PAM should be a service and only communicate via a UNIX socket. That way you vastly reduce the attack surface, and allow locking up the PAM bits into their own, well defended box.
throwaway09223|3 years ago
The calling convention is C, but you can write PAM in any language.
"and is linked into another program as a library makes it impossible to fully isolate it from its host application"
Huh? You can never isolate the client side code. You will always have something in your app.
"I think a sane, modern version of PAM should be a service and only communicate via a UNIX socket."
So, write a module that talks to a socket. That's how like half of the PAM modules already operate. You will always have to have code in the application to talk to whatever oracle you're using. What you're describing here isn't any different from how PAM already works.
salawat|3 years ago
I'm being serious, as exactly what you're describing sounds an awful lot like their micro-kernel approach. At least as of the last time I looked into it.
badrabbit|3 years ago
yrro|3 years ago
pabs3|3 years ago
Does Linux have process spawning that doesn't have this problem?
yjftsjthsd-h|3 years ago
mindcrime|3 years ago
badrabbit|3 years ago
smitty1e|3 years ago