mirror of
https://github.com/openembedded/meta-openembedded.git
synced 2026-11-13 03:37:15 +00:00
net-snmp: fix CVE-2026-89147
This patch applies the upstream fix [1] for CVE-2026-89147 as shown in the advisory identifying the fix [2]. [1] https://github.com/net-snmp/net-snmp/commit/ad843e83da1c229847ae7884dc08311fad680389 [2] https://ubuntu.com/security/CVE-2026-89147 Signed-off-by: Darsh Kelaiya <dkelaiya@cisco.com> Signed-off-by: Anuj Mittal <anuj.mittal@oss.qualcomm.com>
This commit is contained in:
1 parent
aa6d99fed0
commit
4202adbfe6
2 files changed
+400
No files matched your search
@@ -0,0 +1,399 @@
|
||||
From 6d5668341de9d91f0e4e9d71e36f4141fdb9a528 Mon Sep 17 00:00:00 2001
|
||||
From: Bart Van Assche <bvanassche@acm.org>
|
||||
Date: Mon, 14 Sep 2026 10:19:57 -0700
|
||||
Subject: [PATCH] snmpd: SMUX: Make accepted peer connection handshake
|
||||
non-blocking
|
||||
|
||||
When accepting a new SMUX connection, smux_accept() previously executed
|
||||
a synchronous, blocking recvfrom() in the main daemon loop to read the
|
||||
initial OpenPDU before authenticating the peer. If an unauthenticated
|
||||
client connected and sent no data, the entire snmpd process blocked,
|
||||
preventing all SNMP request processing (CVE-2026-89147 / Issue #1134).
|
||||
|
||||
Make the SMUX connection acceptance and authentication asynchronous:
|
||||
- Set accepted SMUX peer sockets to non-blocking mode immediately upon
|
||||
accept() in smux_accept() and return the socket to the select loop
|
||||
without performing any synchronous read.
|
||||
- In smux_process(), check whether the peer is authenticated. If not yet
|
||||
authenticated, read and parse the OpenPDU non-blockingly when the
|
||||
socket becomes readable, authenticating the peer and processing any
|
||||
subsequent PDUs in the buffer.
|
||||
- Register a 5-second one-shot alarm on accepted connections to close
|
||||
and clean up unauthenticated sockets that fail to complete the
|
||||
handshake in time.
|
||||
- In smux_peer_cleanup(), only decrement npeers if the connection was
|
||||
an authenticated peer.
|
||||
|
||||
Fixes: https://github.com/net-snmp/net-snmp/issues/1134
|
||||
Fixes: ee0daa3b7bcd ("- (smux.c, smux.h): Patch from Nick Amato: - completely re-written smux modules.")
|
||||
|
||||
CVE: CVE-2026-89147
|
||||
Upstream-Status: Backport [https://github.com/net-snmp/net-snmp/commit/ad843e83da1c229847ae7884dc08311fad680389]
|
||||
|
||||
Backport Changes:
|
||||
- Retain int sockets, -1 errors, and the older accept() check.
|
||||
- Use %d because 5.9.5.2 lacks NETSNMP_FMT_SKT.
|
||||
- Omit netsnmp_set_tcp_nodelay(), absent in 5.9.5.2.
|
||||
- Include snmpSocketBaseDomain.h for the nonblocking helper.
|
||||
|
||||
(cherry picked from commit ad843e83da1c229847ae7884dc08311fad680389)
|
||||
Signed-off-by: Darsh Kelaiya <dkelaiya@cisco.com>
|
||||
---
|
||||
agent/mibgroup/smux/smux.c | 245 +++++++++++++++++++++----------------
|
||||
1 file changed, 141 insertions(+), 104 deletions(-)
|
||||
|
||||
diff --git a/agent/mibgroup/smux/smux.c b/agent/mibgroup/smux/smux.c
|
||||
index 078c4c6fa..5778f3590 100644
|
||||
--- a/agent/mibgroup/smux/smux.c
|
||||
+++ b/agent/mibgroup/smux/smux.c
|
||||
@@ -64,6 +64,7 @@
|
||||
#include <net-snmp/net-snmp-includes.h>
|
||||
#include <net-snmp/agent/net-snmp-agent-includes.h>
|
||||
#include <net-snmp/library/tools.h>
|
||||
+#include <net-snmp/library/snmpSocketBaseDomain.h>
|
||||
|
||||
#include "smux.h"
|
||||
#include "snmpd.h"
|
||||
@@ -92,6 +93,8 @@ static void smux_send_close(int, int);
|
||||
static void smux_list_detach(smux_reg **, smux_reg *);
|
||||
static void smux_replace_active(smux_reg *, smux_reg *);
|
||||
static void smux_peer_cleanup(int);
|
||||
+static int smux_peer_is_authenticated(int);
|
||||
+static void smux_auth_timeout_cb(unsigned int, void *);
|
||||
static int smux_auth_peer(oid *, size_t, char *, int);
|
||||
static int smux_build(u_char, long, oid *,
|
||||
size_t *, u_char, u_char *, size_t, u_char *,
|
||||
@@ -623,138 +626,175 @@ var_smux_write(int action,
|
||||
}
|
||||
|
||||
|
||||
+static int
|
||||
+smux_peer_is_authenticated(int sd)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0; i < nauths; i++)
|
||||
+ if (Auths[i]->sa_active_fd == sd)
|
||||
+ return 1;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+smux_auth_timeout_cb(unsigned int clientreg, void *clientarg)
|
||||
+{
|
||||
+ int fd = (int)(uintptr_t)clientarg;
|
||||
+ int i, found = 0;
|
||||
+
|
||||
+ for (i = 0; i < smux_snmp_select_list_get_length(); i++) {
|
||||
+ if (smux_snmp_select_list_get_SD_from_List(i) == fd) {
|
||||
+ found = 1;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ if (found && !smux_peer_is_authenticated(fd)) {
|
||||
+ DEBUGMSGTL(("smux",
|
||||
+ "[smux_auth_timeout] closing idle unauthenticated fd %d\n", fd));
|
||||
+ close(fd);
|
||||
+ smux_snmp_select_list_del(fd);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
int
|
||||
smux_accept(int sd)
|
||||
{
|
||||
- u_char data[SMUXMAXPKTSIZE], *ptr, type;
|
||||
struct sockaddr_in in_socket;
|
||||
- struct timeval tv;
|
||||
- int fail, fd;
|
||||
+ int fd;
|
||||
socklen_t alen;
|
||||
- int length;
|
||||
- size_t len;
|
||||
|
||||
alen = sizeof(struct sockaddr_in);
|
||||
- /*
|
||||
- * this may be too high
|
||||
- */
|
||||
- tv.tv_sec = 5;
|
||||
- tv.tv_usec = 0;
|
||||
|
||||
/*
|
||||
* connection request
|
||||
*/
|
||||
DEBUGMSGTL(("smux", "[smux_accept] Calling accept()\n"));
|
||||
errno = 0;
|
||||
- if ((fd = (int) accept(sd, (struct sockaddr *) &in_socket, &alen)) < 0) {
|
||||
+ fd = accept(sd, (struct sockaddr *) &in_socket, &alen);
|
||||
+ if (fd < 0) {
|
||||
snmp_log_perror("[smux_accept] accept failed");
|
||||
return -1;
|
||||
- } else {
|
||||
- DEBUGMSGTL(("smux", "[smux_accept] accepted fd %d from %s:%d\n",
|
||||
- fd, inet_ntoa(in_socket.sin_addr),
|
||||
- ntohs(in_socket.sin_port)));
|
||||
- if (npeers + 1 == SMUXMAXPEERS) {
|
||||
- snmp_log(LOG_ERR,
|
||||
- "[smux_accept] denied peer on fd %d, limit %d reached",
|
||||
- fd, SMUXMAXPEERS);
|
||||
- close(fd);
|
||||
- return -1;
|
||||
- }
|
||||
+ }
|
||||
+
|
||||
+ netsnmp_set_non_blocking_mode(fd, TRUE);
|
||||
+ DEBUGMSGTL(("smux", "[smux_accept] accepted fd %d from %s:%d\n",
|
||||
+ fd, inet_ntoa(in_socket.sin_addr),
|
||||
+ ntohs(in_socket.sin_port)));
|
||||
+ if (npeers + 1 == SMUXMAXPEERS) {
|
||||
+ snmp_log(LOG_ERR,
|
||||
+ "[smux_accept] denied peer on fd %d, limit %d reached",
|
||||
+ fd, SMUXMAXPEERS);
|
||||
+ close(fd);
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ snmp_alarm_register(5, 0, smux_auth_timeout_cb, (void *)(intptr_t)fd);
|
||||
+
|
||||
+ return fd;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+smux_process(int sock)
|
||||
+{
|
||||
+ int length, tmp_length;
|
||||
+ u_char data[SMUXMAXPKTSIZE];
|
||||
+ u_char type, *ptr;
|
||||
+ size_t packet_len, len;
|
||||
+ int fail;
|
||||
|
||||
+ if (!smux_peer_is_authenticated(sock)) {
|
||||
/*
|
||||
- * now block for an OpenPDU
|
||||
+ * Unauthenticated peer: read OpenPDU non-blockingly.
|
||||
*/
|
||||
- do
|
||||
- {
|
||||
- length = recvfrom(fd, (char *) data, SMUXMAXPKTSIZE, 0, NULL, NULL);
|
||||
- }
|
||||
- while((length == -1) && ((errno == EINTR) || (errno == EAGAIN)));
|
||||
+ do {
|
||||
+ length = recvfrom(sock, (char *) data, SMUXMAXPKTSIZE, 0, NULL, NULL);
|
||||
+ } while (length == -1 && errno == EINTR);
|
||||
|
||||
- if (length <= 0) {
|
||||
+ if (length < 0) {
|
||||
+ if (errno == EAGAIN ||
|
||||
+ (EAGAIN != EWOULDBLOCK && errno == EWOULDBLOCK))
|
||||
+ return 0;
|
||||
DEBUGMSGTL(("smux",
|
||||
- "[smux_accept] peer on fd %d died or timed out\n",
|
||||
- fd));
|
||||
- close(fd);
|
||||
+ "[smux_process] recvfrom failed on unauthenticated fd %d\n", sock));
|
||||
+ close(sock);
|
||||
+ return -1;
|
||||
+ }
|
||||
+ if (length == 0) {
|
||||
+ DEBUGMSGTL(("smux",
|
||||
+ "[smux_process] peer on fd %d closed connection before auth\n", sock));
|
||||
+ close(sock);
|
||||
return -1;
|
||||
}
|
||||
+
|
||||
/*
|
||||
- * try to authorize him
|
||||
+ * Try to authorize peer.
|
||||
*/
|
||||
ptr = data;
|
||||
len = length;
|
||||
if ((ptr = asn_parse_header(ptr, &len, &type)) == NULL) {
|
||||
- smux_send_close(fd, SMUXC_PACKETFORMAT);
|
||||
- close(fd);
|
||||
- DEBUGMSGTL(("smux", "[smux_accept] peer on %d sent bad open", fd));
|
||||
+ smux_send_close(sock, SMUXC_PACKETFORMAT);
|
||||
+ close(sock);
|
||||
+ DEBUGMSGTL(("smux",
|
||||
+ "[smux_process] peer on %d sent bad open\n",
|
||||
+ sock));
|
||||
return -1;
|
||||
} else if (type != (u_char) SMUX_OPEN) {
|
||||
- smux_send_close(fd, SMUXC_PROTOCOLERROR);
|
||||
- close(fd);
|
||||
+ smux_send_close(sock, SMUXC_PROTOCOLERROR);
|
||||
+ close(sock);
|
||||
DEBUGMSGTL(("smux",
|
||||
- "[smux_accept] peer on %d did not send open: (%d)\n",
|
||||
- fd, type));
|
||||
+ "[smux_process] peer on %d did not send open: (%d)\n",
|
||||
+ sock, type));
|
||||
return -1;
|
||||
}
|
||||
- ptr = smux_open_process(fd, ptr, &len, &fail);
|
||||
+ ptr = smux_open_process(sock, ptr, &len, &fail);
|
||||
if (fail) {
|
||||
- smux_send_close(fd, SMUXC_AUTHENTICATIONFAILURE);
|
||||
- close(fd);
|
||||
+ smux_send_close(sock, SMUXC_AUTHENTICATIONFAILURE);
|
||||
+ close(sock);
|
||||
DEBUGMSGTL(("smux",
|
||||
- "[smux_accept] peer on %d failed authentication\n",
|
||||
- fd));
|
||||
+ "[smux_process] peer on %d failed authentication\n",
|
||||
+ sock));
|
||||
return -1;
|
||||
}
|
||||
|
||||
- /*
|
||||
- * he's OK
|
||||
- */
|
||||
-#ifdef SO_RCVTIMEO
|
||||
- if (setsockopt
|
||||
- (fd, SOL_SOCKET, SO_RCVTIMEO, (void *) &tv, sizeof(tv)) < 0) {
|
||||
- DEBUGMSGTL(("smux",
|
||||
- "[smux_accept] setsockopt(SO_RCVTIMEO) failed fd %d\n",
|
||||
- fd));
|
||||
- snmp_log_perror("smux_accept: setsockopt SO_RCVTIMEO");
|
||||
- }
|
||||
-#endif
|
||||
npeers++;
|
||||
- DEBUGMSGTL(("smux", "[smux_accept] fd %d\n", fd));
|
||||
+ DEBUGMSGTL(("smux", "[smux_process] authenticated peer on fd %d\n", sock));
|
||||
|
||||
/*
|
||||
- * Process other PDUs already read, e.g. a registerRequest.
|
||||
+ * Process other PDUs already read, e.g. a registerRequest.
|
||||
*/
|
||||
len = length - (ptr - data);
|
||||
- if (smux_pdu_process(fd, ptr, len) < 0) {
|
||||
- /*
|
||||
- * Easy come, easy go. Clean-up is already done.
|
||||
- */
|
||||
- return -1;
|
||||
+ if (len > 0) {
|
||||
+ if (smux_pdu_process(sock, ptr, len) < 0) {
|
||||
+ return -1;
|
||||
+ }
|
||||
}
|
||||
+ return 0;
|
||||
}
|
||||
- return fd;
|
||||
-}
|
||||
|
||||
-int
|
||||
-smux_process(int fd)
|
||||
-{
|
||||
- int length, tmp_length;
|
||||
- u_char data[SMUXMAXPKTSIZE];
|
||||
- u_char type, *ptr;
|
||||
- size_t packet_len;
|
||||
-
|
||||
- do
|
||||
- {
|
||||
- length = recvfrom(fd, (char *) data, SMUXMAXPKTSIZE, MSG_PEEK, NULL,
|
||||
+ /*
|
||||
+ * Authenticated peer: process incoming data.
|
||||
+ */
|
||||
+ do {
|
||||
+ length = recvfrom(sock, (char *) data, SMUXMAXPKTSIZE, MSG_PEEK, NULL,
|
||||
NULL);
|
||||
- }
|
||||
- while((length == -1) && ((errno == EINTR) || (errno == EAGAIN)));
|
||||
+ } while (length == -1 && errno == EINTR);
|
||||
|
||||
- if (length <= 0)
|
||||
- {
|
||||
- if (length < 0)
|
||||
- snmp_log_perror("[smux_process] peek failed");
|
||||
- smux_peer_cleanup(fd);
|
||||
- return -1;
|
||||
+ if (length < 0) {
|
||||
+ if (errno == EAGAIN ||
|
||||
+ (EAGAIN != EWOULDBLOCK && errno == EWOULDBLOCK))
|
||||
+ return 0;
|
||||
+ snmp_log_perror("[smux_process] peek failed");
|
||||
+ smux_peer_cleanup(sock);
|
||||
+ return -1;
|
||||
+ }
|
||||
+ if (length == 0) {
|
||||
+ DEBUGMSGTL(("smux",
|
||||
+ "[smux_process] peer on fd %d died or disconnected\n",
|
||||
+ sock));
|
||||
+ smux_peer_cleanup(sock);
|
||||
+ return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -762,10 +802,12 @@ smux_process(int fd)
|
||||
*/
|
||||
packet_len = length;
|
||||
ptr = asn_parse_header(data, &packet_len, &type);
|
||||
- if (ptr == NULL)
|
||||
+ if (ptr == NULL) {
|
||||
+ smux_peer_cleanup(sock);
|
||||
return -1;
|
||||
+ }
|
||||
packet_len += (ptr - data);
|
||||
- if (length > packet_len) {
|
||||
+ if ((size_t)length > packet_len) {
|
||||
/*
|
||||
* set length to receive only the first packet
|
||||
*/
|
||||
@@ -773,26 +815,24 @@ smux_process(int fd)
|
||||
}
|
||||
|
||||
tmp_length = length;
|
||||
- do
|
||||
- {
|
||||
+ do {
|
||||
length = tmp_length;
|
||||
- length = recvfrom(fd, (char *) data, length, 0, NULL, NULL);
|
||||
- }
|
||||
- while((length == -1) && ((errno == EINTR) || (errno == EAGAIN)));
|
||||
+ length = recvfrom(sock, (char *) data, length, 0, NULL, NULL);
|
||||
+ } while (length == -1 && errno == EINTR);
|
||||
|
||||
if (length <= 0) {
|
||||
- /*
|
||||
- * the peer went away, close this descriptor
|
||||
- * * and delete it from the list
|
||||
- */
|
||||
+ if (length < 0 &&
|
||||
+ (errno == EAGAIN ||
|
||||
+ (EAGAIN != EWOULDBLOCK && errno == EWOULDBLOCK)))
|
||||
+ return 0;
|
||||
DEBUGMSGTL(("smux",
|
||||
"[smux_process] peer on fd %d died or timed out\n",
|
||||
- fd));
|
||||
- smux_peer_cleanup(fd);
|
||||
+ sock));
|
||||
+ smux_peer_cleanup(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
- return smux_pdu_process(fd, data, length);
|
||||
+ return smux_pdu_process(sock, data, length);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -1907,11 +1947,6 @@ smux_peer_cleanup(int sd)
|
||||
}
|
||||
}
|
||||
|
||||
- /*
|
||||
- * decrement the peer count
|
||||
- */
|
||||
- npeers--;
|
||||
-
|
||||
/*
|
||||
* make his auth available again
|
||||
*/
|
||||
@@ -1922,6 +1957,8 @@ smux_peer_cleanup(int sd)
|
||||
snprint_objid(oid_name, sizeof(oid_name), Auths[i]->sa_oid,
|
||||
Auths[i]->sa_oid_len);
|
||||
DEBUGMSGTL(("smux", "peer disconnected: %s\n", oid_name));
|
||||
+ if (npeers > 0)
|
||||
+ npeers--;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ SRC_URI = "${SOURCEFORGE_MIRROR}/net-snmp/net-snmp-${PV}.tar.gz \
|
||||
file://0010-net-snmp-Reproducibility-Don-t-check-build-host-for.patch \
|
||||
file://0011-ac_add_search_path.m4-keep-consistent-between-32bit-.patch \
|
||||
file://netsnmp-swinst-crash.patch \
|
||||
file://CVE-2026-89147.patch \
|
||||
"
|
||||
SRC_URI[sha256sum] = "16707719f833184a4b72835dac359ae188123b06b5e42817c00790d7dc1384bf"
|
||||
|
||||
|
||||
Reference in new issue
Block a user