# su segfaults when adding some custom pam_exec to the auth stack



## zirias@ (May 10, 2022)

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:

PR about upgrading the xscreensaver port: PR 254178
Review (rejected) for suggested extension of `pam_unix`: https://reviews.freebsd.org/D34322
---

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:

```
#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:

```
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...


----------



## zirias@ (May 10, 2022)

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.


----------



## _martin (May 10, 2022)

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 
	
	



```
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.


----------



## covacat (May 10, 2022)

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


----------



## zirias@ (May 10, 2022)

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...


----------



## covacat (May 10, 2022)

in pam_exec.c

```
authtok_size = strlen(authtok) + 1;
```

when _pam_exec() is called from pam_sm_setcred it bombs because


```
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)


----------



## zirias@ (May 10, 2022)

Wow, please copy that to the PR. Might already be the whole bug!
*edit:* Thanks!


----------

