git: e4781e4e6d88 - releng/15.0 - blocklistd: Fix multiple bugs
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 10 Feb 2026 17:56:11 UTC
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 <des@FreeBSD.org>
AuthorDate: 2026-02-07 14:38:34 +0000
Commit: Mark Johnston <markj@FreeBSD.org>
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