https://bugs.openldap.org/show_bug.cgi?id=10658
Issue ID: 10658 Summary: lutil_passwd_generate() returns uninitialized memory as the generated password when it fails to get random bytes Product: OpenLDAP Version: unspecified Hardware: All OS: All Status: UNCONFIRMED Keywords: needs_review Severity: normal Priority: --- Component: slapd Assignee: bugs@openldap.org Reporter: hamano@osstech.co.jp Target Milestone: ---
- Affected versions: 2.5.20, 2.6.16, master
## Summary
When `lutil_entropy()` fails, `lutil_passwd_generate()` returns -1 but leaves `pw->bv_len` and the already allocated `pw->bv_val` in place. The callers in slapd check `bv_len` rather than the return value, so 8 bytes of uninitialized memory are set as the new password and returned to the client in the Password Modify response (genPasswd).
## Details
`libraries/liblutil/passwd.c`:
```c int lutil_passwd_generate( struct berval *pw, ber_len_t len ) { if( len < 1 ) return -1;
pw->bv_len = len; pw->bv_val = ber_memalloc( len + 1 );
if( pw->bv_val == NULL ) { return -1; /* bv_len is still len */ }
if( lutil_entropy( (unsigned char *) pw->bv_val, pw->bv_len) < 0 ) { return -1; /* bv_val is uninitialized, bv_len is still len */ } ... ```
Callers:
- `slap_passwd_generate()` in `servers/slapd/passwd.c` ignores the return value of `lutil_passwd_generate()`. - `slap_exop_passwd()` and `slap_sasl_setpass()` in `servers/slapd/sasl.c` detect a generation failure only by `bv_len == 0`.
So when `lutil_entropy()` fails, the uninitialized buffer (raw bytes, not even mapped to crypt64) is hashed and set as the new password, and returned as genPasswd.
- If `password-hash` uses a salted scheme (such as the default `{SSHA}`), generating the salt fails for the same reason and the operation fails with "password hash failed", so no password is set. - With an unsalted scheme (`{SHA}`, `{CLEARTEXT}`, ...) the password is set as is. - `bv_len` is also left set when `ber_memalloc()` fails (the callers then use a NULL `bv_val`).
`lutil_entropy()` simply opens and reads `/dev/urandom`, so it fails when the process has run out of file descriptors (EMFILE, which can be caused remotely by opening many connections to slapd) or in a chroot without `/dev/urandom`.
## A better improvement: use getrandom(2) in lutil_entropy()
If `lutil_entropy()` tried `getrandom(2)` (Linux 3.17+, glibc 2.25+) first when available, it would not consume a file descriptor and this failure would practically no longer occur. The randomness comes from the same kernel CSPRNG as `/dev/urandom`.
Since `getrandom(2)` can fail as well, I think the `lutil_passwd_generate()` fix above is needed either way.
https://bugs.openldap.org/show_bug.cgi?id=10658
--- Comment #1 from HAMANO Tsukasa hamano@osstech.co.jp --- https://git.openldap.org/openldap/openldap/-/merge_requests/950