Skip to content

Commit 0a4b340

Browse files
committed
Fix unportable use of getnameinfo() in pg_hba_file_rules view.
fill_hba_line() thought it could get away with passing sizeof(struct sockaddr_storage) rather than the actual addrlen previously returned by getaddrinfo(). While that appears to work on many platforms, it does not work on FreeBSD 11: you get back a failure, which leads to the view showing NULL for the address and netmask columns in all rows. The POSIX spec for getnameinfo() is pretty clearly on FreeBSD's side here: you should pass the actual address length. So it seems plausible that there are other platforms where this coding also fails, and we just hadn't noticed. Also, IMO the fact that getnameinfo() failure leads to a NULL output is pretty bogus in itself. Our pg_getnameinfo_all() wrapper is careful to emit "???" on failure, and we should use that in such cases. NULL should only be emitted in rows that don't have IP addresses. Per bug #16695 from Peter Vandivier. Back-patch to v10 where this code was added. Discussion: https://postgr.es/m/16695-a665558e2f630be7@postgresql.org
1 parent e1339bf commit 0a4b340

File tree

2 files changed

+27
-11
lines changed

2 files changed

+27
-11
lines changed

src/backend/libpq/hba.c

+21-10
Original file line numberDiff line numberDiff line change
@@ -1188,8 +1188,11 @@ parse_hba_line(TokenizedLine *tok_line, int elevel)
11881188

11891189
ret = pg_getaddrinfo_all(str, NULL, &hints, &gai_result);
11901190
if (ret == 0 && gai_result)
1191+
{
11911192
memcpy(&parsedline->addr, gai_result->ai_addr,
11921193
gai_result->ai_addrlen);
1194+
parsedline->addrlen = gai_result->ai_addrlen;
1195+
}
11931196
else if (ret == EAI_NONAME)
11941197
parsedline->hostname = str;
11951198
else
@@ -1238,6 +1241,7 @@ parse_hba_line(TokenizedLine *tok_line, int elevel)
12381241
token->string);
12391242
return NULL;
12401243
}
1244+
parsedline->masklen = parsedline->addrlen;
12411245
pfree(str);
12421246
}
12431247
else if (!parsedline->hostname)
@@ -1288,6 +1292,7 @@ parse_hba_line(TokenizedLine *tok_line, int elevel)
12881292

12891293
memcpy(&parsedline->mask, gai_result->ai_addr,
12901294
gai_result->ai_addrlen);
1295+
parsedline->masklen = gai_result->ai_addrlen;
12911296
pg_freeaddrinfo_all(hints.ai_family, gai_result);
12921297

12931298
if (parsedline->addr.ss_family != parsedline->mask.ss_family)
@@ -2538,20 +2543,26 @@ fill_hba_line(Tuplestorestate *tuple_store, TupleDesc tupdesc,
25382543
}
25392544
else
25402545
{
2541-
if (pg_getnameinfo_all(&hba->addr, sizeof(hba->addr),
2542-
buffer, sizeof(buffer),
2543-
NULL, 0,
2544-
NI_NUMERICHOST) == 0)
2546+
/*
2547+
* Note: if pg_getnameinfo_all fails, it'll set buffer to
2548+
* "???", which we want to return.
2549+
*/
2550+
if (hba->addrlen > 0)
25452551
{
2546-
clean_ipv6_addr(hba->addr.ss_family, buffer);
2552+
if (pg_getnameinfo_all(&hba->addr, hba->addrlen,
2553+
buffer, sizeof(buffer),
2554+
NULL, 0,
2555+
NI_NUMERICHOST) == 0)
2556+
clean_ipv6_addr(hba->addr.ss_family, buffer);
25472557
addrstr = pstrdup(buffer);
25482558
}
2549-
if (pg_getnameinfo_all(&hba->mask, sizeof(hba->mask),
2550-
buffer, sizeof(buffer),
2551-
NULL, 0,
2552-
NI_NUMERICHOST) == 0)
2559+
if (hba->masklen > 0)
25532560
{
2554-
clean_ipv6_addr(hba->mask.ss_family, buffer);
2561+
if (pg_getnameinfo_all(&hba->mask, hba->masklen,
2562+
buffer, sizeof(buffer),
2563+
NULL, 0,
2564+
NI_NUMERICHOST) == 0)
2565+
clean_ipv6_addr(hba->mask.ss_family, buffer);
25552566
maskstr = pstrdup(buffer);
25562567
}
25572568
}

src/include/libpq/hba.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ typedef enum UserAuth
4242
#define USER_AUTH_LAST uaPeer /* Must be last value of this enum */
4343
} UserAuth;
4444

45+
/*
46+
* Data structures representing pg_hba.conf entries
47+
*/
48+
4549
typedef enum IPCompareMethod
4650
{
4751
ipCmpMask,
@@ -75,11 +79,12 @@ typedef struct HbaLine
7579
List *databases;
7680
List *roles;
7781
struct sockaddr_storage addr;
82+
int addrlen; /* zero if we don't have a valid addr */
7883
struct sockaddr_storage mask;
84+
int masklen; /* zero if we don't have a valid mask */
7985
IPCompareMethod ip_cmp_method;
8086
char *hostname;
8187
UserAuth auth_method;
82-
8388
char *usermap;
8489
char *pamservice;
8590
bool pam_use_hostname;

0 commit comments

Comments
 (0)