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.
GNU Lesser General Public License v3.0
1.33k stars 39 forks source link

Failed to allocate buffer for getpwnam_r #7

Closed kedorlaomer closed 3 months ago

kedorlaomer commented 3 years ago

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?

nuvious commented 3 years ago

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.

kedorlaomer commented 3 years ago

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?

nuvious commented 3 years ago

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.

kedorlaomer commented 3 years ago

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.

Artoria2e5 commented 3 years ago

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.

nuvious commented 2 years ago

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.

nuvious commented 1 year ago

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

Artoria2e5 commented 1 year ago

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

nuvious commented 1 year ago

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

davidestorey commented 6 months ago

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.

kedorlaomer commented 4 months ago

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

davidestorey commented 4 months ago

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.

Artoria2e5 commented 4 months ago

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.