From ce12c7736f6dfbb46e061c1d13753ebfdbf4bf47 Mon Sep 17 00:00:00 2001 From: Andrew LeFevre Date: Thu, 4 Jun 2026 14:24:30 -0400 Subject: [PATCH] handle failing to load PAM getenvlist symbol correctly (#67477) --- session/pam/pam.go | 7 +++++-- session/pam/pam_nop.go | 7 +++---- session/pam/pam_test.go | 7 ++++--- session/reexec/reexec.go | 10 ++++++++-- 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/session/pam/pam.go b/session/pam/pam.go index f2080c4f6d1..636aeeea6bc 100644 --- a/session/pam/pam.go +++ b/session/pam/pam.go @@ -424,9 +424,12 @@ func (p *PAM) Close() error { // It should be noted that this memory will never be free()'d by libpam. // Once obtained by a call to pam_getenvlist, it is the responsibility // of the calling application to free() this memory. -func (p *PAM) Environment() []string { +func (p *PAM) Environment() ([]string, error) { // Get list of additional environment variables requested from PAM. pam_envlist := C._pam_getenvlist(pamHandle, p.pamh) + if pam_envlist == nil { + return nil, trace.BadParameter("failed to find PAM getenvlist symbol") + } defer C.free(unsafe.Pointer(pam_envlist)) // Find out how many environment variables exist and size the output @@ -443,7 +446,7 @@ func (p *PAM) Environment() []string { env = append(env, C.GoStringN(pam_env, pam_env_size)) } - return env + return env, nil } // free will end the PAM transaction (which itself will free memory) and diff --git a/session/pam/pam_nop.go b/session/pam/pam_nop.go index 4e716860c03..1b221603944 100644 --- a/session/pam/pam_nop.go +++ b/session/pam/pam_nop.go @@ -26,8 +26,7 @@ var buildHasPAM, systemHasPAM bool // PAM is used to create a PAM context and initiate PAM transactions to checks // the users account and open/close a session. -type PAM struct { -} +type PAM struct{} // Open creates a PAM context and initiates a PAM transaction to check the // account and then opens a session. @@ -43,8 +42,8 @@ func (p *PAM) Close() error { // Environment returns the PAM environment variables associated with a PAM // handle. -func (p *PAM) Environment() []string { - return nil +func (p *PAM) Environment() ([]string, error) { + return nil, nil } // BuildHasPAM returns true if the binary was build with support for PAM diff --git a/session/pam/pam_test.go b/session/pam/pam_test.go index 26575f464b3..bc8f78bc8e1 100644 --- a/session/pam/pam_test.go +++ b/session/pam/pam_test.go @@ -124,7 +124,9 @@ func TestEnvironment(t *testing.T) { require.NoError(t, err) defer pamContext.Close() - require.ElementsMatch(t, pamContext.Environment(), []string{"foo=bar"}) + env, err := pamContext.Environment() + require.NoError(t, err) + require.ElementsMatch(t, env, []string{"foo=bar"}) } func TestSuccess(t *testing.T) { @@ -237,8 +239,7 @@ func assertOutput(t *testing.T, got string, want []string) { require.ElementsMatch(t, lines, want) } -type discardReader struct { -} +type discardReader struct{} func (d *discardReader) Read(p []byte) (int, error) { return len(p), nil diff --git a/session/reexec/reexec.go b/session/reexec/reexec.go index f64eb19de5b..8d5a74023a2 100644 --- a/session/reexec/reexec.go +++ b/session/reexec/reexec.go @@ -446,7 +446,10 @@ func RunCommand() (exitErr error, err error) { defer pamContext.Close() // Save off any environment variables that come from PAM. - pamEnvironment = pamContext.Environment() + pamEnvironment, err = pamContext.Environment() + if err != nil { + return nil, trace.Wrap(err) + } } uaccHandler := uacc.NewUserAccountHandler(uacc.UaccConfig{ @@ -789,7 +792,10 @@ func RunNetworking() (code int, err error) { } defer pamContext.Close() - pamEnvironment = pamContext.Environment() + pamEnvironment, err = pamContext.Environment() + if err != nil { + return reexecconstants.RemoteCommandFailure, trace.Wrap(err) + } } // Once the PAM stack is called with parent process permissions, set the process uid