nuvious / pam-duress

A Pluggable Authentication Module (PAM) which allows the establishment of alternate passwords that can be used to perform actions to clear sensitive data, notify IT/Security staff, close off sensitive network connections, etc if a user is coerced into giving a threat actor a password.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Failed to allocate buffer for getpwnam_r

kedorlaomer opened this issue · comments

This is thrown from

    size_t buffer_len = sysconf(_SC_GETPW_R_SIZE_MAX) * sizeof(char);
    char *buffer = (char *) malloc(buffer_len);
    if (buffer == NULL)
    {
        syslog(LOG_INFO, "Failed to allocate buffer for getpwnam_r.\n");
        exit(2);
    }
    getpwnam_r(user_name, pwd, buffer, buffer_len, &pwd);

in src/util.c, since for some reason, sysconf(_SC_GETPW_R_SIZE_MAX) yields -1 on that system (alpine linux 3.13). Any more infos needed?

Yup, that may not be unexpected; Alpine linux is stripped down so much it may not even have PAM by default. Did you install pam into an Alpine container/vm/etc before you attempted this?

To check this out I did docker run -i alpine /bin/bash and checked /etc and didn't see any pam.d or other pam related configurations. Additionally, a find / -iname pam yielded no results.

You're right, a pristine alpine doesn't have PAM. This installation, however, does have PAM with a somewhat fancy configuration (it's in /etc/pam.d/base-auth instead of the path mentioned by you. The problem is, as far as I understand, unrelated to PAM being installed by default. The module is definitely being executed (which is how I found that the call to sysconf yields -1).

How would you go about debugging this?

To further debug I would just need more details about your environment; whether you're running on bare metal/vm/raspberry pi, what version of Alpine you're on and/or how PAM was installed, etc.

I am working on creating some compatibility unit tests that leverage docker to check against multiple distributions. I'll definitely include alpine into the mix.

I'm not sure regarding the procedure — it's an intriguing problem: I'm debugging /bin/login running functions from pam_duress.o that yield a SEGFAULT (gdb claims it's related to strlen somewhere). With enough time, I'll find the reason. Certainly, the first issue (which I “fixed” by setting buffer_len = 9999 in the above fragment) is that the call to sysconf may lie. After all, this endpoint is not in POSIX, so the corresponding libc (looking at you, musl) may claim it doesn't know the answer and return -1. In my case, musl-1.2.5-r5 is being used. The “proper” solution is trying getpwnam_r with exponentially increasing buffers, until it succeds (doesn't give ENOMEM). This is annoying, but portable.

The endpoint seems to be proper POSIX per https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwnam.html. The POSIX spec also mentions that -1 (without errno change!) means unlimited in sysconf, so presumably the fix is just a branch to use a “sensible” default in such case.

I'm not sure regarding the procedure — it's an intriguing problem: I'm debugging /bin/login running functions from pam_duress.o that yield a SEGFAULT (gdb claims it's related to strlen somewhere). With enough time, I'll find the reason. Certainly, the first issue (which I “fixed” by setting buffer_len = 9999 in the above fragment) is that the call to sysconf may lie. After all, this endpoint is not in POSIX, so the corresponding libc (looking at you, musl) may claim it doesn't know the answer and return -1. In my case, musl-1.2.5-r5 is being used. The “proper” solution is trying getpwnam_r with exponentially increasing buffers, until it succeds (doesn't give ENOMEM). This is annoying, but portable.

Belated reply but I'm starting to get back on this project a bit. Any info on what version of Alipine you're using? I'm actually working on Arch specific steps in issue #29 and thought I'd revisit this one as well.

Closing due to inactivity and lack of time to setup an alpine specific testing environment.

Uhhhhhhhhhh... It's still wrong in the man page sense, which is not good.

Re-opening based on @Artoria2e5 comments. Will try to take a look at this over the weekend.

I got this working last night on Alpine 3.19.1. Alpine uses musl for its C library, which doesn't use getpwnam_r. However musl does support getpwnam which works fine and allows . I have a patch that I use for my local Alpine package repo, but I doubt that it's suitable for inclusion upstream as it's intended to simply make this work on musl.

What needs to be done to make it suitable for upstream?

util.patch

this patch converts getpwnam_r to simply use getpwnam. If you want to preserve the use of the thread-safe version, we'll have to come up with some kind of macro.

Alpine uses musl for its C library, which doesn't use getpwnam_r.

No? musl has the _r version. Like, https://github.com/search?q=repo%3Abminor%2Fmusl%20getpwnam_r&type=code gives results. The implementation is right in https://github.com/bminor/musl/blob/007997299248b8682dcbb73595c53dfe86071c83/src/passwd/getpw_r.c#L34.

The _r thing is POSIX. Why would you expect musl to say no to POSIX?

... Please try my PR. Please.