Merge pull request #11487 from poettering/unprotect-errno
Make sure NSS modules can change errno if they want
This commit is contained in:
@@ -174,12 +174,21 @@ static inline void *mempset(void *s, int c, size_t n) {
|
||||
}
|
||||
|
||||
static inline void _reset_errno_(int *saved_errno) {
|
||||
if (*saved_errno < 0) /* Invalidated by UNPROTECT_ERRNO? */
|
||||
return;
|
||||
|
||||
errno = *saved_errno;
|
||||
}
|
||||
|
||||
#define PROTECT_ERRNO \
|
||||
_cleanup_(_reset_errno_) _unused_ int _saved_errno_ = errno
|
||||
|
||||
#define UNPROTECT_ERRNO \
|
||||
do { \
|
||||
errno = _saved_errno_; \
|
||||
_saved_errno_ = -1; \
|
||||
} while (false)
|
||||
|
||||
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();"
|
||||
|
||||
@@ -74,6 +74,7 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
|
||||
} else {
|
||||
hn = gethostname_malloc();
|
||||
if (!hn) {
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = ENOMEM;
|
||||
*h_errnop = NO_RECOVERY;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
@@ -96,6 +97,7 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
|
||||
l = strlen(canonical);
|
||||
ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * (n_addresses > 0 ? n_addresses : 2);
|
||||
if (buflen < ms) {
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = ERANGE;
|
||||
*h_errnop = NETDB_INTERNAL;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
@@ -186,6 +188,8 @@ static enum nss_status fill_in_hostent(
|
||||
assert(errnop);
|
||||
assert(h_errnop);
|
||||
|
||||
PROTECT_ERRNO;
|
||||
|
||||
alen = FAMILY_ADDRESS_SIZE(af);
|
||||
|
||||
for (a = addresses, n = 0, c = 0; n < n_addresses; a++, n++)
|
||||
@@ -202,6 +206,7 @@ static enum nss_status fill_in_hostent(
|
||||
(c > 0 ? c+1 : 2) * sizeof(char*);
|
||||
|
||||
if (buflen < ms) {
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = ERANGE;
|
||||
*h_errnop = NETDB_INTERNAL;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
@@ -321,6 +326,7 @@ enum nss_status _nss_myhostname_gethostbyname3_r(
|
||||
af = AF_INET;
|
||||
|
||||
if (!IN_SET(af, AF_INET, AF_INET6)) {
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = EAFNOSUPPORT;
|
||||
*h_errnop = NO_DATA;
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
@@ -343,6 +349,7 @@ enum nss_status _nss_myhostname_gethostbyname3_r(
|
||||
} else {
|
||||
hn = gethostname_malloc();
|
||||
if (!hn) {
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = ENOMEM;
|
||||
*h_errnop = NO_RECOVERY;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
@@ -362,6 +369,8 @@ enum nss_status _nss_myhostname_gethostbyname3_r(
|
||||
local_address_ipv4 = LOCALADDRESS_IPV4;
|
||||
}
|
||||
|
||||
UNPROTECT_ERRNO;
|
||||
|
||||
return fill_in_hostent(
|
||||
canonical, additional,
|
||||
af,
|
||||
@@ -401,12 +410,14 @@ enum nss_status _nss_myhostname_gethostbyaddr2_r(
|
||||
assert(h_errnop);
|
||||
|
||||
if (!IN_SET(af, AF_INET, AF_INET6)) {
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = EAFNOSUPPORT;
|
||||
*h_errnop = NO_DATA;
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
}
|
||||
|
||||
if (len != FAMILY_ADDRESS_SIZE(af)) {
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = EINVAL;
|
||||
*h_errnop = NO_RECOVERY;
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
@@ -461,6 +472,7 @@ found:
|
||||
if (!canonical || additional_from_hostname) {
|
||||
hn = gethostname_malloc();
|
||||
if (!hn) {
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = ENOMEM;
|
||||
*h_errnop = NO_RECOVERY;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
@@ -472,6 +484,7 @@ found:
|
||||
additional = hn;
|
||||
}
|
||||
|
||||
UNPROTECT_ERRNO;
|
||||
return fill_in_hostent(
|
||||
canonical, additional,
|
||||
af,
|
||||
|
||||
@@ -153,6 +153,7 @@ enum nss_status _nss_mymachines_gethostbyname4_r(
|
||||
l = strlen(name);
|
||||
ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * c;
|
||||
if (buflen < ms) {
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = ERANGE;
|
||||
*h_errnop = NETDB_INTERNAL;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
@@ -227,6 +228,7 @@ enum nss_status _nss_mymachines_gethostbyname4_r(
|
||||
return NSS_STATUS_SUCCESS;
|
||||
|
||||
fail:
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = -r;
|
||||
*h_errnop = NO_DATA;
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
@@ -313,6 +315,7 @@ enum nss_status _nss_mymachines_gethostbyname3_r(
|
||||
ms = ALIGN(l+1) + c * ALIGN(alen) + (c+2) * sizeof(char*);
|
||||
|
||||
if (buflen < ms) {
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = ERANGE;
|
||||
*h_errnop = NETDB_INTERNAL;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
@@ -396,6 +399,7 @@ enum nss_status _nss_mymachines_gethostbyname3_r(
|
||||
return NSS_STATUS_SUCCESS;
|
||||
|
||||
fail:
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = -r;
|
||||
*h_errnop = NO_DATA;
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
@@ -484,6 +488,7 @@ enum nss_status _nss_mymachines_getpwnam_r(
|
||||
|
||||
l = strlen(name);
|
||||
if (buflen < l+1) {
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = ERANGE;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
}
|
||||
@@ -501,6 +506,7 @@ enum nss_status _nss_mymachines_getpwnam_r(
|
||||
return NSS_STATUS_SUCCESS;
|
||||
|
||||
fail:
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = -r;
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
}
|
||||
@@ -564,6 +570,7 @@ enum nss_status _nss_mymachines_getpwuid_r(
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
|
||||
if (snprintf(buffer, buflen, "vu-%s-" UID_FMT, machine, (uid_t) mapped) >= (int) buflen) {
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = ERANGE;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
}
|
||||
@@ -579,6 +586,7 @@ enum nss_status _nss_mymachines_getpwuid_r(
|
||||
return NSS_STATUS_SUCCESS;
|
||||
|
||||
fail:
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = -r;
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
}
|
||||
@@ -662,6 +670,7 @@ enum nss_status _nss_mymachines_getgrnam_r(
|
||||
|
||||
l = sizeof(char*) + strlen(name) + 1;
|
||||
if (buflen < l) {
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = ERANGE;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
}
|
||||
@@ -677,6 +686,7 @@ enum nss_status _nss_mymachines_getgrnam_r(
|
||||
return NSS_STATUS_SUCCESS;
|
||||
|
||||
fail:
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = -r;
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
}
|
||||
@@ -740,12 +750,14 @@ enum nss_status _nss_mymachines_getgrgid_r(
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
|
||||
if (buflen < sizeof(char*) + 1) {
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = ERANGE;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
}
|
||||
|
||||
memzero(buffer, sizeof(char*));
|
||||
if (snprintf(buffer + sizeof(char*), buflen - sizeof(char*), "vg-%s-" GID_FMT, machine, (gid_t) mapped) >= (int) buflen) {
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = ERANGE;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
}
|
||||
@@ -758,6 +770,7 @@ enum nss_status _nss_mymachines_getgrgid_r(
|
||||
return NSS_STATUS_SUCCESS;
|
||||
|
||||
fail:
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = -r;
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
}
|
||||
|
||||
@@ -186,6 +186,7 @@ enum nss_status _nss_resolve_gethostbyname4_r(
|
||||
l = strlen(canonical);
|
||||
ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * c;
|
||||
if (buflen < ms) {
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = ERANGE;
|
||||
*h_errnop = NETDB_INTERNAL;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
@@ -267,6 +268,7 @@ enum nss_status _nss_resolve_gethostbyname4_r(
|
||||
return NSS_STATUS_SUCCESS;
|
||||
|
||||
fail:
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = -r;
|
||||
*h_errnop = NO_RECOVERY;
|
||||
return ret;
|
||||
@@ -364,6 +366,7 @@ enum nss_status _nss_resolve_gethostbyname3_r(
|
||||
ms = ALIGN(l+1) + c * ALIGN(alen) + (c+2) * sizeof(char*);
|
||||
|
||||
if (buflen < ms) {
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = ERANGE;
|
||||
*h_errnop = NETDB_INTERNAL;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
@@ -455,6 +458,7 @@ enum nss_status _nss_resolve_gethostbyname3_r(
|
||||
return NSS_STATUS_SUCCESS;
|
||||
|
||||
fail:
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = -r;
|
||||
*h_errnop = NO_RECOVERY;
|
||||
return ret;
|
||||
@@ -492,12 +496,14 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
|
||||
assert(h_errnop);
|
||||
|
||||
if (!IN_SET(af, AF_INET, AF_INET6)) {
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = EAFNOSUPPORT;
|
||||
*h_errnop = NO_DATA;
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
}
|
||||
|
||||
if (len != FAMILY_ADDRESS_SIZE(af)) {
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = EINVAL;
|
||||
*h_errnop = NO_RECOVERY;
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
@@ -576,6 +582,7 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
|
||||
c * sizeof(char*); /* pointers to aliases, plus trailing NULL */
|
||||
|
||||
if (buflen < ms) {
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = ERANGE;
|
||||
*h_errnop = NETDB_INTERNAL;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
@@ -636,6 +643,7 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
|
||||
return NSS_STATUS_SUCCESS;
|
||||
|
||||
fail:
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = -r;
|
||||
*h_errnop = NO_RECOVERY;
|
||||
return ret;
|
||||
|
||||
@@ -210,6 +210,7 @@ enum nss_status _nss_systemd_getpwnam_r(
|
||||
|
||||
l = strlen(name);
|
||||
if (buflen < l+1) {
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = ERANGE;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
}
|
||||
@@ -227,6 +228,7 @@ enum nss_status _nss_systemd_getpwnam_r(
|
||||
return NSS_STATUS_SUCCESS;
|
||||
|
||||
fail:
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = -r;
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
}
|
||||
@@ -310,6 +312,7 @@ enum nss_status _nss_systemd_getpwuid_r(
|
||||
|
||||
l = strlen(translated) + 1;
|
||||
if (buflen < l) {
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = ERANGE;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
}
|
||||
@@ -327,6 +330,7 @@ enum nss_status _nss_systemd_getpwuid_r(
|
||||
return NSS_STATUS_SUCCESS;
|
||||
|
||||
fail:
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = -r;
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
}
|
||||
@@ -408,6 +412,7 @@ enum nss_status _nss_systemd_getgrnam_r(
|
||||
|
||||
l = sizeof(char*) + strlen(name) + 1;
|
||||
if (buflen < l) {
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = ERANGE;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
}
|
||||
@@ -423,6 +428,7 @@ enum nss_status _nss_systemd_getgrnam_r(
|
||||
return NSS_STATUS_SUCCESS;
|
||||
|
||||
fail:
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = -r;
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
}
|
||||
@@ -506,6 +512,7 @@ enum nss_status _nss_systemd_getgrgid_r(
|
||||
|
||||
l = sizeof(char*) + strlen(translated) + 1;
|
||||
if (buflen < l) {
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = ERANGE;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
}
|
||||
@@ -521,6 +528,7 @@ enum nss_status _nss_systemd_getgrgid_r(
|
||||
return NSS_STATUS_SUCCESS;
|
||||
|
||||
fail:
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = -r;
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
}
|
||||
@@ -740,6 +748,7 @@ enum nss_status _nss_systemd_getpwent_r(struct passwd *result, char *buffer, siz
|
||||
LIST_FOREACH(entries, p, getpwent_data.position) {
|
||||
len = strlen(p->name) + 1;
|
||||
if (buflen < len) {
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = ERANGE;
|
||||
ret = NSS_STATUS_TRYAGAIN;
|
||||
goto finalize;
|
||||
@@ -791,6 +800,7 @@ enum nss_status _nss_systemd_getgrent_r(struct group *result, char *buffer, size
|
||||
LIST_FOREACH(entries, p, getgrent_data.position) {
|
||||
len = sizeof(char*) + strlen(p->name) + 1;
|
||||
if (buflen < len) {
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = ERANGE;
|
||||
ret = NSS_STATUS_TRYAGAIN;
|
||||
goto finalize;
|
||||
|
||||
@@ -361,11 +361,11 @@ static void test_unlink_noerrno(void) {
|
||||
|
||||
{
|
||||
PROTECT_ERRNO;
|
||||
errno = -42;
|
||||
errno = 42;
|
||||
assert_se(unlink_noerrno(name) >= 0);
|
||||
assert_se(errno == -42);
|
||||
assert_se(errno == 42);
|
||||
assert_se(unlink_noerrno(name) < 0);
|
||||
assert_se(errno == -42);
|
||||
assert_se(errno == 42);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -213,6 +213,30 @@ static void test_protect_errno(void) {
|
||||
assert_se(errno == 12);
|
||||
}
|
||||
|
||||
static void test_unprotect_errno_inner_function(void) {
|
||||
PROTECT_ERRNO;
|
||||
|
||||
errno = 2222;
|
||||
}
|
||||
|
||||
static void test_unprotect_errno(void) {
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
errno = 4711;
|
||||
|
||||
PROTECT_ERRNO;
|
||||
|
||||
errno = 815;
|
||||
|
||||
UNPROTECT_ERRNO;
|
||||
|
||||
assert_se(errno == 4711);
|
||||
|
||||
test_unprotect_errno_inner_function();
|
||||
|
||||
assert_se(errno == 4711);
|
||||
}
|
||||
|
||||
static void test_in_set(void) {
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
@@ -383,6 +407,7 @@ int main(int argc, char *argv[]) {
|
||||
test_div_round_up();
|
||||
test_u64log2();
|
||||
test_protect_errno();
|
||||
test_unprotect_errno();
|
||||
test_in_set();
|
||||
test_log2i();
|
||||
test_eqzero();
|
||||
|
||||
Reference in New Issue
Block a user