helpers: lockfree lookup of nobody user on unix systems (#14866)

* helpers: lockfree lookup of nobody user on linux and darwin

This PR continues the nobody user lookup saga, by making the nobody
user lookup lock-free on linux and darwin.

By doing the lookup in an init block this originally broke on Windows,
where we must avoid doing the lookup at all. We can get around that
breakage by only doing the lookup on linux/darwin where the nobody
user is going to exist.

Also return the nobody user by value so that a copy is created that
cannot be modified by callers of Nobody().

* helper: move nobody code into unix file
This commit is contained in:
Seth Hoenig 2022-10-11 08:38:05 -05:00 committed by GitHub
parent 1593963cd1
commit ba1e337f8b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 31 additions and 25 deletions

View File

@ -1,4 +1,4 @@
//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
//go:build unix
package allocdir
@ -40,17 +40,14 @@ func dropDirPermissions(path string, desired os.FileMode) error {
return nil
}
nobody, err := users.Nobody()
nobody := users.Nobody()
uid, err := getUid(&nobody)
if err != nil {
return err
}
uid, err := getUid(nobody)
if err != nil {
return err
}
gid, err := getGid(nobody)
gid, err := getGid(&nobody)
if err != nil {
return err
}

View File

@ -9,23 +9,6 @@ import (
// some NSS implementations are not concurrency safe
var lock sync.Mutex
// nobody is a cached copy of the nobody user, which is going to be looked-up
// frequently and is unlikely to be modified on the underlying system.
var nobody *user.User
// Nobody returns User data for the "nobody" user on the system, bypassing the
// locking / file read / NSS lookup.
func Nobody() (*user.User, error) {
lock.Lock()
defer lock.Unlock()
if nobody != nil {
return nobody, nil
}
u, err := user.Lookup("nobody")
nobody = u
return u, err
}
// Lookup username while holding a global process lock.
func Lookup(username string) (*user.User, error) {
lock.Lock()

View File

@ -0,0 +1,26 @@
//go:build unix
package users
import (
"fmt"
"os/user"
)
// nobody is a cached copy of the nobody user, which is going to be looked-up
// frequently and is unlikely to be modified on the underlying system.
var nobody user.User
// Nobody returns User data for the "nobody" user on the system, bypassing the
// locking / file read / NSS lookup.
func Nobody() user.User {
return nobody
}
func init() {
u, err := Lookup("nobody")
if err != nil {
panic(fmt.Sprintf("failed to lookup nobody user: %v", err))
}
nobody = *u
}