libcasper: Fix inconsistent error codes of cap_get{addr,name}info()

The get{addr,name}info(3) API is designed to return an API-specific error
code that is independent of errno.  The cap_get{addr,name}info() functions
returned either an errno or API-specific error code inconsistently.
This change fixes this mismatch.

When the API returns an errno, the return value itself is set to
EAI_SYSTEM and errno is set depending on the actual error.  So, usually
this API is called in the following form:

    error = getnameinfo(...);
    if (error == EAI_SYSTEM)
        perror("getnameinfo");
    else if (error)
        errx(1, "getnameinfo: %s", gai_strerror(error);

If the above getnameinfo() call is replaced with cap_getnameinfo(),
it breaks the error handling.  For example, the cap_get{addr,name}info()
functions can return ENOTCAPABLE.

This change simply adds "errno", in addition to "error", to the nvlout and
cap_get{addr,name}info() restores the errno if the error code is EAI_SYSTEM.

Reviewed by:	oshogbo
Differential Revision:	https://reviews.freebsd.org/D45859
This commit is contained in:
Hiroki Sato
2025-06-13 03:16:18 +09:00
parent 6501b68ffb
commit b60053fde1
+39 -16
View File
@@ -288,7 +288,7 @@ cap_getaddrinfo(cap_channel_t *chan, const char *hostname, const char *servname,
const nvlist_t *nvlai;
char nvlname[64];
nvlist_t *nvl;
int error, n;
int error, serrno, n;
nvl = nvlist_create(0);
nvlist_add_string(nvl, "cmd", "getaddrinfo");
@@ -311,7 +311,9 @@ cap_getaddrinfo(cap_channel_t *chan, const char *hostname, const char *servname,
return (EAI_MEMORY);
if (nvlist_get_number(nvl, "error") != 0) {
error = (int)nvlist_get_number(nvl, "error");
serrno = dnvlist_get_number(nvl, "errno", 0);
nvlist_destroy(nvl);
errno = (error == EAI_SYSTEM) ? serrno : 0;
return (error);
}
@@ -350,7 +352,7 @@ cap_getnameinfo(cap_channel_t *chan, const struct sockaddr *sa, socklen_t salen,
char *host, size_t hostlen, char *serv, size_t servlen, int flags)
{
nvlist_t *nvl;
int error;
int error, serrno;
nvl = nvlist_create(0);
nvlist_add_string(nvl, "cmd", "getnameinfo");
@@ -363,7 +365,9 @@ cap_getnameinfo(cap_channel_t *chan, const struct sockaddr *sa, socklen_t salen,
return (EAI_MEMORY);
if (nvlist_get_number(nvl, "error") != 0) {
error = (int)nvlist_get_number(nvl, "error");
serrno = dnvlist_get_number(nvl, "errno", 0);
nvlist_destroy(nvl);
errno = (error == EAI_SYSTEM) ? serrno : 0;
return (error);
}
@@ -858,19 +862,21 @@ net_getnameinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
char *host, *serv;
size_t sabinsize, hostlen, servlen;
socklen_t salen;
int error, flags;
int error, serrno, flags;
const nvlist_t *funclimit;
if (!net_allowed_mode(limits, CAPNET_ADDR2NAME))
return (ENOTCAPABLE);
host = serv = NULL;
if (!net_allowed_mode(limits, CAPNET_ADDR2NAME)) {
serrno = ENOTCAPABLE;
error = EAI_SYSTEM;
goto out;
}
funclimit = NULL;
if (limits != NULL) {
funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_ADDR2NAME,
NULL);
}
error = 0;
host = serv = NULL;
memset(&sast, 0, sizeof(sast));
hostlen = (size_t)nvlist_get_number(nvlin, "hostlen");
@@ -897,7 +903,8 @@ net_getnameinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
goto out;
}
if (!net_allowed_bsaddr(funclimit, sabin, sabinsize)) {
error = ENOTCAPABLE;
serrno = ENOTCAPABLE;
error = EAI_SYSTEM;
goto out;
}
@@ -913,7 +920,8 @@ net_getnameinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
}
if (!net_allowed_family(funclimit, (int)sast.ss_family)) {
error = ENOTCAPABLE;
serrno = ENOTCAPABLE;
error = EAI_SYSTEM;
goto out;
}
@@ -921,6 +929,7 @@ net_getnameinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
error = getnameinfo((struct sockaddr *)&sast, salen, host, hostlen,
serv, servlen, flags);
serrno = errno;
if (error != 0)
goto out;
@@ -932,6 +941,8 @@ net_getnameinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
if (error != 0) {
free(host);
free(serv);
if (error == EAI_SYSTEM)
nvlist_add_number(nvlout, "errno", serrno);
}
return (error);
}
@@ -961,12 +972,15 @@ net_getaddrinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
char nvlname[64];
nvlist_t *elem;
unsigned int ii;
int error, family, n;
int error, serrno, family, n;
const nvlist_t *funclimit;
bool dnscache;
if (!net_allowed_mode(limits, CAPNET_NAME2ADDR))
return (ENOTCAPABLE);
if (!net_allowed_mode(limits, CAPNET_NAME2ADDR)) {
serrno = ENOTCAPABLE;
error = EAI_SYSTEM;
goto out;
}
dnscache = net_allowed_mode(limits, CAPNET_CONNECTDNS);
funclimit = NULL;
if (limits != NULL) {
@@ -996,11 +1010,18 @@ net_getaddrinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
family = AF_UNSPEC;
}
if (!net_allowed_family(funclimit, family))
return (ENOTCAPABLE);
if (!net_allowed_hosts(funclimit, hostname, servname))
return (ENOTCAPABLE);
if (!net_allowed_family(funclimit, family)) {
errno = ENOTCAPABLE;
error = EAI_SYSTEM;
goto out;
}
if (!net_allowed_hosts(funclimit, hostname, servname)) {
errno = ENOTCAPABLE;
error = EAI_SYSTEM;
goto out;
}
error = getaddrinfo(hostname, servname, hintsp, &res);
serrno = errno;
if (error != 0) {
goto out;
}
@@ -1019,6 +1040,8 @@ net_getaddrinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
freeaddrinfo(res);
error = 0;
out:
if (error == EAI_SYSTEM)
nvlist_add_number(nvlout, "errno", serrno);
return (error);
}