diff options
author | Tobias Stoeckmann <tobias@stoeckmann.org> | 2024-01-04 18:30:28 +0100 |
---|---|---|
committer | Dmitry V. Levin <ldv@strace.io> | 2024-01-05 23:36:44 +0000 |
commit | b6faf3c6cbf2f27a1976e462e2ea6fa09f1aad3d (patch) | |
tree | 84d21d1944bdb4ea68e1c31a8942e99870676ee7 /libpam | |
parent | 14ad78c43158291f179a6e77c8695964659f2ed5 (diff) | |
download | pam-b6faf3c6cbf2f27a1976e462e2ea6fa09f1aad3d.tar.gz pam-b6faf3c6cbf2f27a1976e462e2ea6fa09f1aad3d.tar.bz2 pam-b6faf3c6cbf2f27a1976e462e2ea6fa09f1aad3d.zip |
libpam: handle long delays properly
If a delay close to UINT_MAX has been set, then the delay computation
might overflow the value due to added randomness.
Systems where linux-pam is in use should generally have a 32 bit
unsigned int and a 64 bit unsigned long long, and a time_t of either
64 bit or 32 bit. Under these assumptions, using the result for delay is
safe because of the division before assigning it to tv_sec (time_t).
Thought about using uint64_t type here but as long as "unsigned int"
is part of the API instead of uint32_t, no proper guarantees could be
made anyway.
Unfortunately we have to supply an unsigned int if a PAM_FAIL_DELAY
function has been set. In such a case, supply a UINT_MAX if delay is
larger than that. It's the best we can do without breaking the API.
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
Diffstat (limited to 'libpam')
-rw-r--r-- | libpam/pam_delay.c | 20 |
1 files changed, 13 insertions, 7 deletions
diff --git a/libpam/pam_delay.c b/libpam/pam_delay.c index b8fddbb6..67b7d73b 100644 --- a/libpam/pam_delay.c +++ b/libpam/pam_delay.c @@ -14,6 +14,7 @@ */ #include "pam_private.h" +#include <limits.h> #include <unistd.h> #include <time.h> @@ -61,19 +62,21 @@ static unsigned int _pam_rand(unsigned int seed) return N1*seed + N2; } -static unsigned int _pam_compute_delay(unsigned int seed, unsigned int base) +static unsigned long long _pam_compute_delay(unsigned int seed, + unsigned int base) { int i; double sum; - unsigned int ans; + unsigned long long ans; for (sum=i=0; i<3; ++i) { seed = _pam_rand(seed); sum += (double) ((seed / 10) % 1000000); } sum = (sum/3.)/1e6 - .5; /* rescale */ - ans = (unsigned int) ( base*(1.+sum) ); - D(("random number: base=%u -> ans=%u\n", base, ans)); + sum = base*(1.+sum); + ans = sum > (double) ULLONG_MAX ? ULLONG_MAX : (unsigned long long) sum; + D(("random number: base=%u -> ans=%llu\n", base, ans)); return ans; } @@ -88,7 +91,7 @@ static unsigned int _pam_compute_delay(unsigned int seed, unsigned int base) void _pam_await_timer(pam_handle_t *pamh, int status) { - unsigned int delay; + unsigned long long delay; D(("waiting?...")); delay = _pam_compute_delay(pamh->fail_delay.begin, @@ -99,6 +102,7 @@ void _pam_await_timer(pam_handle_t *pamh, int status) void (*fn)(int, unsigned, void *); } hack_fn_u; void *appdata_ptr; + unsigned int delay_uint; if (pamh->pam_conversation) { appdata_ptr = pamh->pam_conversation->appdata_ptr; @@ -106,14 +110,16 @@ void _pam_await_timer(pam_handle_t *pamh, int status) appdata_ptr = NULL; } + delay_uint = delay > UINT_MAX ? UINT_MAX : (unsigned int) delay; + /* always call the applications delay function, even if the delay is zero - indicate status */ hack_fn_u.value = pamh->fail_delay.delay_fn_ptr; - hack_fn_u.fn(status, delay, appdata_ptr); + hack_fn_u.fn(status, delay_uint, appdata_ptr); } else if (status != PAM_SUCCESS && pamh->fail_delay.set) { - D(("will wait %u usec", delay)); + D(("will wait %llu usec", delay)); if (delay > 0) { struct timeval tval; |