The branch releng/15.0 has been updated by markj:

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

commit e4781e4e6d88f73d6fe266eb520c240a343fafcf
Author:     Dag-Erling Smørgrav <[email protected]>
AuthorDate: 2026-02-07 14:38:34 +0000
Commit:     Mark Johnston <[email protected]>
CommitDate: 2026-02-09 17:54:29 +0000

    blocklistd: Fix multiple bugs
    
    * Fix file descriptor leak in the server
    
    * Fix race between parent and child in popenve()
    
    * Don't assume fdopen() can't fail
    
    Approved by:    so
    Security:       FreeBSD-SA-26:03.blocklistd
    Security:       CVE-2026-2261
---
 contrib/blocklist/bin/blacklistd.c |  8 +++--
 contrib/blocklist/bin/blocklistd.c |  8 +++--
 contrib/blocklist/port/popenve.c   | 61 ++++++++++++++++++++------------------
 3 files changed, 42 insertions(+), 35 deletions(-)

diff --git a/contrib/blocklist/bin/blacklistd.c 
b/contrib/blocklist/bin/blacklistd.c
index cb6ce6578d9c..6021e70f214c 100644
--- a/contrib/blocklist/bin/blacklistd.c
+++ b/contrib/blocklist/bin/blacklistd.c
@@ -191,7 +191,7 @@ process(bl_t bl)
        }
 
        if (getremoteaddress(bi, &rss, &rsl) == -1)
-               return;
+               goto out;
 
        if (debug || bi->bi_msg[0]) {
                sockaddr_snprintf(rbuf, sizeof(rbuf), "%a:%p", (void *)&rss);
@@ -204,12 +204,12 @@ process(bl_t bl)
 
        if (conf_find(bi->bi_fd, bi->bi_uid, &rss, &c) == NULL) {
                (*lfun)(LOG_DEBUG, "no rule matched");
-               return;
+               goto out;
        }
 
 
        if (state_get(state, &c, &dbi) == -1)
-               return;
+               goto out;
 
        if (debug) {
                char b1[128], b2[128];
@@ -269,6 +269,8 @@ process(bl_t bl)
        state_put(state, &c, &dbi);
 
 out:
+       close(bi->bi_fd);
+
        if (debug) {
                char b1[128], b2[128];
                (*lfun)(LOG_DEBUG, "%s: final db state for %s: count=%d/%d "
diff --git a/contrib/blocklist/bin/blocklistd.c 
b/contrib/blocklist/bin/blocklistd.c
index 47c145c7aae1..ffa2ff2d74a6 100644
--- a/contrib/blocklist/bin/blocklistd.c
+++ b/contrib/blocklist/bin/blocklistd.c
@@ -191,7 +191,7 @@ process(bl_t bl)
        }
 
        if (getremoteaddress(bi, &rss, &rsl) == -1)
-               return;
+               goto out;
 
        if (debug || bi->bi_msg[0]) {
                sockaddr_snprintf(rbuf, sizeof(rbuf), "%a:%p", (void *)&rss);
@@ -204,12 +204,12 @@ process(bl_t bl)
 
        if (conf_find(bi->bi_fd, bi->bi_uid, &rss, &c) == NULL) {
                (*lfun)(LOG_DEBUG, "no rule matched");
-               return;
+               goto out;
        }
 
 
        if (state_get(state, &c, &dbi) == -1)
-               return;
+               goto out;
 
        if (debug) {
                char b1[128], b2[128];
@@ -269,6 +269,8 @@ process(bl_t bl)
        state_put(state, &c, &dbi);
 
 out:
+       close(bi->bi_fd);
+
        if (debug) {
                char b1[128], b2[128];
                (*lfun)(LOG_DEBUG, "%s: final db state for %s: count=%d/%d "
diff --git a/contrib/blocklist/port/popenve.c b/contrib/blocklist/port/popenve.c
index bdff8cdc1de4..e80058a8599a 100644
--- a/contrib/blocklist/port/popenve.c
+++ b/contrib/blocklist/port/popenve.c
@@ -111,11 +111,25 @@ pdes_get(int *pdes, const char **type)
 #endif
        }
 
-       if ((cur = malloc(sizeof(*cur))) != NULL)
-               return cur;
+       if ((cur = malloc(sizeof(*cur))) != NULL) {
+               if (**type == 'r') {
+                       cur->fp = fdopen(pdes[0], *type);
+#ifdef _REENTRANT
+                       cur->fd = pdes[0];
+#endif
+               } else {
+                       cur->fp = fdopen(pdes[1], *type);
+#ifdef _REENTRANT
+                       cur->fd = pdes[1];
+#endif
+               }
+               if (cur->fp != NULL)
+                       return cur;
+       }
        serrno = errno;
        (void)close(pdes[0]);
        (void)close(pdes[1]);
+       free(cur);
        errno = serrno;
        return NULL;
 }
@@ -125,16 +139,6 @@ pdes_child(int *pdes, const char *type)
 {
        struct pid *old;
 
-       /* POSIX.2 B.3.2.2 "popen() shall ensure that any streams
-          from previous popen() calls that remain open in the 
-          parent process are closed in the new child process. */
-       for (old = pidlist; old; old = old->next)
-#ifdef _REENTRANT
-               (void)close(old->fd); /* don't allow a flush */
-#else
-               (void)close(fileno(old->fp)); /* don't allow a flush */
-#endif
-
        if (type[0] == 'r') {
                (void)close(pdes[0]);
                if (pdes[1] != STDOUT_FILENO) {
@@ -150,31 +154,30 @@ pdes_child(int *pdes, const char *type)
                        (void)close(pdes[0]);
                }
        }
+
+       /* POSIX.2 B.3.2.2 "popen() shall ensure that any streams
+          from previous popen() calls that remain open in the
+          parent process are closed in the new child process. */
+       for (old = pidlist; old; old = old->next) {
+#ifdef _REENTRANT
+               (void)close(old->fd); /* don't allow a flush */
+#else
+               (void)close(fileno(old->fp)); /* don't allow a flush */
+#endif
+       }
 }
 
 static void
 pdes_parent(int *pdes, struct pid *cur, pid_t pid, const char *type)
 {
-       FILE *iop;
-
-       /* Parent; assume fdopen can't fail. */
-       if (*type == 'r') {
-               iop = fdopen(pdes[0], type);
-#ifdef _REENTRANT
-               cur->fd = pdes[0];
-#endif
+       /* Parent */
+       if (*type == 'r')
                (void)close(pdes[1]);
-       } else {
-               iop = fdopen(pdes[1], type);
-#ifdef _REENTRANT
-               cur->fd = pdes[1];
-#endif
+       else
                (void)close(pdes[0]);
-       }
 
        /* Link into list of file descriptors. */
-       cur->fp = iop;
-       cur->pid =  pid;
+       cur->pid = pid;
        cur->next = pidlist;
        pidlist = cur;
 }
@@ -200,7 +203,7 @@ popenve(const char *cmd, char *const *argv, char *const 
*envp, const char *type)
 #ifdef _REENTRANT
        (void)rwlock_rdlock(&pidlist_lock);
 #endif
-       switch (pid = vfork()) {
+       switch (pid = fork()) {
        case -1:                        /* Error. */
                serrno = errno;
 #ifdef _REENTRANT

Reply via email to