From aa88bf4527cced6e3e16ca3e5ae07076cc8217f0 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 25 Mar 2018 10:13:26 -0700 Subject: security: drop and regain privileges in all threads After enabling pam_fscrypt for "session" and creating a directory protected with a login protector, I was no longer able to log in as that user. The problem is that the Go runtime is creating threads after pam_fscrypt drops privileges, but pam_fscrypt is not re-acquiring privileges on those threads because the Go wrappers for setreuid(), setregid(), and setgroups() in the "sys/unix" package are using the raw syscalls which operate on the calling thread only. This violates glibc's assumption that all threads have the same uids and gids, causing it to abort() the process when a later module in the PAM stack (pam_mail in my case) tries to drop privileges using the glibc functions. Fix it by dropping and regaining privileges using the glibc functions rather than the "sys/unix" functions. This also avoids any possibility that privileges could be changed in a thread other than the "main" one for pam_fscrypt, since the Go runtime does not guarantee which OS-level thread runs what. It would be nice to also exit all Go worker threads before returning from pam_fscrypt, but the Go runtime doesn't seem to support that. --- pam/pam.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'pam/pam.go') diff --git a/pam/pam.go b/pam/pam.go index bd15c38..ca5bd9d 100644 --- a/pam/pam.go +++ b/pam/pam.go @@ -134,14 +134,14 @@ func (h *Handle) StartAsPamUser() error { if _, err := security.UserKeyringID(h.PamUser, true); err != nil { log.Printf("Setting up keyrings in PAM: %v", err) } - return security.SetThreadPrivileges(h.PamUser) + return security.SetProcessPrivileges(h.PamUser) } // StopAsPamUser restores the original privileges that were running the // PAM module (this is usually root). As this error is often ignored in a defer // statement, any error is also logged. func (h *Handle) StopAsPamUser() error { - err := security.SetThreadPrivileges(h.OrigUser) + err := security.SetProcessPrivileges(h.OrigUser) if err != nil { log.Print(err) } -- cgit v1.2.3