The branch main has been updated by hrs:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=b60053fde1726ea047aadfbc0354b79e99d4a668

commit b60053fde1726ea047aadfbc0354b79e99d4a668
Author:     Hiroki Sato <h...@freebsd.org>
AuthorDate: 2025-06-12 18:16:18 +0000
Commit:     Hiroki Sato <h...@freebsd.org>
CommitDate: 2025-06-12 18:16:49 +0000

    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
---
 lib/libcasper/services/cap_net/cap_net.c | 55 ++++++++++++++++++++++----------
 1 file changed, 39 insertions(+), 16 deletions(-)

diff --git a/lib/libcasper/services/cap_net/cap_net.c 
b/lib/libcasper/services/cap_net/cap_net.c
index 40d18319ae28..5887fe3c407e 100644
--- a/lib/libcasper/services/cap_net/cap_net.c
+++ b/lib/libcasper/services/cap_net/cap_net.c
@@ -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 @@ out:
        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);
 }
 

Reply via email to