su segfaults when adding some custom pam_exec to the auth stack

zirias@

Developer
Asking here before opening a PR, because I'm not sure whether I might be doing something wrong...

I'm trying to allow "self-authentication" against the local passwd database without requiring root privileges. The typical usecase for this is screen lockers, and the typical workaround for them is using some external suid-root helper to carry out the PAM authentication ... but the well-known xscreensaver refuses to support this (IMHO for good reasons).

LinuxPAM includes a workaround for this specific usecase, a suid-root helper used by pam_unix.so itself. I suggested something similar for FreeBSD, but this was rejected. One suggestion for an alternative was to write a helper instead that's directly called by pam_exec.so, which makes sense for a workaround as it's a pretty unobtrusive way to add this feature (and can be delivered as a port).

For even more background:
---

So, now I'm working on a suid-root helper for pam_exec. Running into strange issues, I created a version with a lot of logging here: https://github.com/Zirias/unix-selfauth-helper/tree/bughunt

It seems to work as expected when I test it with some very simple test code:
Code:
#include <sys/types.h>
#include <security/pam_appl.h>
#include <security/openpam.h>
#include <stdio.h>

int main(int argc, char **argv)
{
    if (argc != 2)
    {
        fputs("usage: pamcheck user\n", stderr);
        return 1;
    }

    pam_handle_t *pamh = 0;
    struct pam_conv conv = { openpam_ttyconv, 0 };
    int rc = pam_start("xscreensaver", argv[1], &conv, &pamh);
    if (rc != PAM_SUCCESS)
    {
        fprintf(stderr, "%s\n", pam_strerror(pamh, rc));
        return 1;
    }
    rc = pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK);
    const char *result = pam_strerror(pamh, rc);
    pam_end(pamh, rc);
    fprintf(stderr, "pam_authenticate: %s\n", result);
    return 0;
}

But it fails in other situations. One of the first thing I tried was adding it to /etc/pam.d/system for testing, like this:
Code:
auth           sufficient      pam_exec.so             return_prog_exit_status expose_authtok /usr/local/libexec/unix-selfauth-helper
auth            required        pam_unix.so             use_first_pass nullok

Now, this makes su segfault, although from the log messages, the helper seems to run fine. If I remove the use_first_pass option, I'm asked for a password a second time (as expected), and after that, I still get a segfault. If I remove the expose_authtok option for my helper, the segfault goes away, but of course this renders the helper useless.

Any ideas what could be wrong here?

Did these tests on 13.1-RC6 so far...
 
Just found I can reproduce this without any of my code, just using /usr/bin/false, so I guess this is enough to open a PR: PR 263893.
 
I had a quick look ; it seems it's failing in su calling pam_setcred(), which is here and here. I'm not familiar with the guts of PAM, I'd expect that once su gets the
Code:
su[37213]: in pam_sm_authenticate(): /usr/bin/false returned invalid code 1
it would not continue.

The live trace shows it segfaults on NULL str in strcmp(). Trace is not complete though, some sections are missing (not sure why, setgid dump was enabled, maybe I'm missing something else too).

It will be interesting to see what PR has to say about it.
 
expose_authtok

Write the authentication token to the program's standard input

stream, followed by a NUL character. Ignored for

pam_sm_setcred().

looks like it is not ignored
also pam_authenticate() will set null for pam_authtok and the pam_exec to strlen will bomb strlen(null)
the problem is trying to obtain the token in pam_sm_setcred after it's pointer is set to null
 
covacat which part of the code are you refering to? Cause I can't follow right now...

I currently just ignore "setcred" (and tried both PAM_SUCCESS and some error codes, doesn't seem to have any influence). From a quick look at pam_exec source, it only writes the authtok when stdin of the external program is ready to read...
 
in pam_exec.c
C:
authtok_size = strlen(authtok) + 1;

when _pam_exec() is called from pam_sm_setcred it bombs because

C:
rc = pam_get_item(pamh, PAM_AUTHTOK, &item);
                      authtok = item;
will set item to null (PAM_AUTHTOK item is set to null when pam_authenticate() finishes)
 
Back
Top