From b26c90411343d74b15deb24bd87077848e316dab Mon Sep 17 00:00:00 2001 From: Sam Morris Date: Wed, 9 Jan 2019 10:15:53 +0000 Subject: nss: prevent PROTECT_ERRNO from squashing changes to *errnop glibc passes in &errno for errnop, which means PROTECT_ERRNO ends up squashing our intentional changes to *errnop. Fixes #11321. --- src/basic/util.h | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'src/basic') diff --git a/src/basic/util.h b/src/basic/util.h index f009d37d4c..77ef1d9892 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -174,12 +174,33 @@ static inline void *mempset(void *s, int c, size_t n) { } static inline void _reset_errno_(int *saved_errno) { - errno = *saved_errno; + if (*saved_errno >= 0) + errno = *saved_errno; } #define PROTECT_ERRNO \ _cleanup_(_reset_errno_) _unused_ int _saved_errno_ = errno +/* + * NSS modules should indicate errors by assigning to the passed-in *errnop + * rather than errno directly; however in dynamically-linked programs, errnop + * == &errno, so PROTECT_ERRNO has to be disabled in order for assigning to + * *errnop to be effective. + */ +#define DISARM_PROTECT_ERRNO(r) \ + ({ \ + _reset_errno_(&_saved_errno_); \ + _saved_errno_ = -1; \ + abs(r); \ + }) + +#define DISARM_PROTECT_ERRNO_INNER(r) \ + ({ \ + _reset_errno_(_saved_errno_p); \ + *_saved_errno_p = -1; \ + abs(r); \ + }) + static inline int negative_errno(void) { /* This helper should be used to shut up gcc if you know 'errno' is * negative. Instead of "return -errno;", use "return negative_errno();" -- cgit v1.2.1