So here's an elusive one that can be triggered every now and then by the
new regression test. Once an AgentX session is opened and we send an
invalid packet appl_agentx_recv() goes to appl_agentx_free(), since
there's no recovery. appl_agentx_free() tries to neatly close all
open sessions by sending a close-pdu, followed by calling
appl_agentx_send() directly.
However, if the socket has been closed in the meantime we hit
appl_agentx_send()'s error path, which also calls appl_agentx_free().
This in turn leads to use after free cases.

To fix this don't call appl_agentx_send() directly anymore, but just
schedule it via conn_wev. To make sure as much data as possible is
written out do a last unchecked courtesy flush before definitively
freeing the connection. Since appl_agentx_forceclose() arms conn_wev
move the event_del() calls down in appl_agentx_free().

Other calls of appl_agentx_send() should be fine, but just convert
all of them to be consistent and safe.

OK?

martijn@

Index: usr.sbin/snmpd/application_agentx.c
===================================================================
RCS file: /cvs/src/usr.sbin/snmpd/application_agentx.c,v
retrieving revision 1.12
diff -u -p -r1.12 application_agentx.c
--- usr.sbin/snmpd/application_agentx.c 24 Oct 2023 14:11:14 -0000      1.12
+++ usr.sbin/snmpd/application_agentx.c 26 Oct 2023 08:43:02 -0000
@@ -254,9 +254,6 @@ appl_agentx_free(struct appl_agentx_conn
 {
        struct appl_agentx_session *session;
 
-       event_del(&(conn->conn_rev));
-       event_del(&(conn->conn_wev));
-
        while ((session = TAILQ_FIRST(&(conn->conn_sessions))) != NULL) {
                if (conn->conn_ax == NULL)
                        appl_agentx_session_free(session);
@@ -265,7 +262,12 @@ appl_agentx_free(struct appl_agentx_conn
                            reason);
        }
 
+       event_del(&(conn->conn_rev));
+       event_del(&(conn->conn_wev));
+
        RB_REMOVE(appl_agentx_conns, &appl_agentx_conns, conn);
+       if (conn->conn_ax != NULL)
+               (void)ax_send(conn->conn_ax);
        ax_free(conn->conn_ax);
        if (conn->conn_backend)
                fatalx("AgentX(%"PRIu32"): disappeared unexpected",
@@ -419,7 +421,7 @@ appl_agentx_recv(int fd, short event, vo
                    pdu->ap_header.aph_transactionid,
                    pdu->ap_header.aph_packetid, smi_getticks(),
                    APPL_ERROR_NOERROR, 0, NULL, 0);
-               appl_agentx_send(-1, EV_WRITE, conn);
+               event_add(&(conn->conn_wev), NULL);
                break;
        case AX_PDU_TYPE_INDEXALLOCATE:
        case AX_PDU_TYPE_INDEXDEALLOCATE:
@@ -431,7 +433,7 @@ appl_agentx_recv(int fd, short event, vo
                    APPL_ERROR_PROCESSINGERROR, 1,
                    pdu->ap_payload.ap_vbl.ap_varbind,
                    pdu->ap_payload.ap_vbl.ap_nvarbind);
-               appl_agentx_send(-1, EV_WRITE, conn);
+               event_add(&(conn->conn_wev), NULL);
                break;
        case AX_PDU_TYPE_ADDAGENTCAPS:
        case AX_PDU_TYPE_REMOVEAGENTCAPS:
@@ -451,7 +453,7 @@ appl_agentx_recv(int fd, short event, vo
            pdu->ap_header.aph_transactionid,
            pdu->ap_header.aph_packetid, smi_getticks(),
            error, 0, NULL, 0);
-       appl_agentx_send(-1, EV_WRITE, conn);
+       event_add(&(conn->conn_wev), NULL);
        ax_pdu_free(pdu);
 
        if (session == NULL || error != APPL_ERROR_PARSEERROR)
@@ -560,13 +562,13 @@ appl_agentx_open(struct appl_agentx_conn
        ax_response(conn->conn_ax, session->sess_id,
            pdu->ap_header.aph_transactionid, pdu->ap_header.aph_packetid,
            smi_getticks(), APPL_ERROR_NOERROR, 0, NULL, 0);
-       appl_agentx_send(-1, EV_WRITE, conn);
+       event_add(&(conn->conn_wev), NULL);
 
        return;
  fail:
        ax_response(conn->conn_ax, 0, pdu->ap_header.aph_transactionid,
            pdu->ap_header.aph_packetid, 0, error, 0, NULL, 0);
-       appl_agentx_send(-1, EV_WRITE, conn);
+       event_add(&(conn->conn_wev), NULL);
        if (session != NULL)
                free(session->sess_descr.aos_string);
        free(session);
@@ -592,7 +594,7 @@ appl_agentx_close(struct appl_agentx_ses
        ax_response(conn->conn_ax, pdu->ap_header.aph_sessionid,
            pdu->ap_header.aph_transactionid, pdu->ap_header.aph_packetid,
            smi_getticks(), error, 0, NULL, 0);
-       appl_agentx_send(-1, EV_WRITE, conn);
+       event_add(&(conn->conn_wev), NULL);
        if (error == APPL_ERROR_NOERROR)
                return;
 
@@ -612,7 +614,7 @@ appl_agentx_forceclose(struct appl_backe
        session->sess_conn->conn_ax->ax_byteorder = session->sess_byteorder;
        ax_close(session->sess_conn->conn_ax, session->sess_id,
            (enum ax_close_reason) reason);
-       appl_agentx_send(-1, EV_WRITE, session->sess_conn);
+       event_add(&(session->sess_conn->conn_wev), NULL);
 
        strlcpy(name, session->sess_backend.ab_name, sizeof(name));
        appl_agentx_session_free(session);
@@ -671,7 +673,7 @@ appl_agentx_register(struct appl_agentx_
        ax_response(session->sess_conn->conn_ax, session->sess_id,
            pdu->ap_header.aph_transactionid, pdu->ap_header.aph_packetid,
            smi_getticks(), error, 0, NULL, 0);
-       appl_agentx_send(-1, EV_WRITE, session->sess_conn);
+       event_add(&(session->sess_conn->conn_wev), NULL);
 }
 
 void
@@ -698,7 +700,7 @@ appl_agentx_unregister(struct appl_agent
        ax_response(session->sess_conn->conn_ax, session->sess_id,
            pdu->ap_header.aph_transactionid, pdu->ap_header.aph_packetid,
            smi_getticks(), error, 0, NULL, 0);
-       appl_agentx_send(-1, EV_WRITE, session->sess_conn);
+       event_add(&(session->sess_conn->conn_wev), NULL);
 }
 
 #define AX_PDU_FLAG_INDEX (AX_PDU_FLAG_NEW_INDEX | AX_PDU_FLAG_ANY_INDEX)
@@ -748,7 +750,7 @@ appl_agentx_get(struct appl_backend *bac
            requestid, context, srl, nsr) == -1)
                appl_response(backend, requestid, APPL_ERROR_GENERR, 1, vblist);
        else
-               appl_agentx_send(-1, EV_WRITE, session->sess_conn);
+               event_add(&(session->sess_conn->conn_wev), NULL);
        free(srl);
        if (context != NULL)
                free(context->aos_string);
@@ -801,7 +803,7 @@ appl_agentx_getnext(struct appl_backend 
            requestid, context, srl, nsr) == -1)
                appl_response(backend, requestid, APPL_ERROR_GENERR, 1, vblist);
        else
-               appl_agentx_send(-1, EV_WRITE, session->sess_conn);
+               event_add(&(session->sess_conn->conn_wev), NULL);
        free(srl);
        if (context != NULL)
                free(context->aos_string);
Index: regress/usr.sbin/snmpd/Makefile
===================================================================
RCS file: /cvs/src/regress/usr.sbin/snmpd/Makefile,v
retrieving revision 1.5
diff -u -p -r1.5 Makefile
--- regress/usr.sbin/snmpd/Makefile     24 Oct 2023 14:34:40 -0000      1.5
+++ regress/usr.sbin/snmpd/Makefile     26 Oct 2023 08:43:02 -0000
@@ -51,6 +51,7 @@ AGENTX_TARGETS+=              agentx_ping_new_index
 AGENTX_TARGETS+=               agentx_ping_any_index
 AGENTX_TARGETS+=               agentx_ping_nbo_nnbo
 AGENTX_TARGETS+=               agentx_ping_nnbo_nbo
+AGENTX_TARGETS+=               agentx_ping_invalid_version_close
 AGENTX_TARGETS+=               agentx_close_notopen
 AGENTX_TARGETS+=               agentx_close_reasonother
 AGENTX_TARGETS+=               agentx_close_reasonparseerror
Index: regress/usr.sbin/snmpd/agentx.c
===================================================================
RCS file: /cvs/src/regress/usr.sbin/snmpd/agentx.c,v
retrieving revision 1.1
diff -u -p -r1.1 agentx.c
--- regress/usr.sbin/snmpd/agentx.c     24 Oct 2023 14:34:40 -0000      1.1
+++ regress/usr.sbin/snmpd/agentx.c     26 Oct 2023 08:43:02 -0000
@@ -706,6 +706,45 @@ agentx_ping_nnbo_nbo(void)
        close(s);
 }
 
+/*
+ * Test that everything continues running in double exception condition
+ */
+void
+agentx_ping_invalid_version_close(void)
+{
+       struct sockaddr_storage ss;
+       struct message msg = {};
+       struct sockaddr *sa = (struct sockaddr *)&ss;
+       socklen_t salen;
+       int snmp_s, ax_s;
+       uint32_t sessionid, packetid;
+       struct varbind varbind = {
+               .type = TYPE_NULL,
+               .name = OID_STRUCT(MIB_SUBAGENT_PING, 10, 0),
+       };
+       int32_t requestid;
+       char buf[1024];
+       size_t n;
+
+       ax_s = agentx_connect(axsocket);
+       sessionid = agentx_open(ax_s, 0, 0,
+           OID_ARG(MIB_SUBAGENT_PING, 10), __func__);
+       message_add_header(&msg, 0xFF, AGENTX_PING_PDU, INSTANCE_REGISTRATION,
+           sessionid, 0, packetid);
+
+       agentx_write(ax_s, &msg);
+       close(ax_s);
+
+       salen = snmp_resolve(SOCK_DGRAM, hostname, servname, sa);
+       snmp_s = snmp_connect(SOCK_DGRAM, sa, salen);
+       requestid = snmpv2_get(snmp_s, community, 0, &varbind, 1);
+
+       varbind.type = TYPE_NOSUCHOBJECT;
+
+       snmpv2_response_validate(snmp_s, 1000, community, requestid, 0, 0,
+           &varbind, 1);
+}
+
 void
 agentx_close_notopen(void)
 {
Index: regress/usr.sbin/snmpd/regress.h
===================================================================
RCS file: /cvs/src/regress/usr.sbin/snmpd/regress.h,v
retrieving revision 1.1
diff -u -p -r1.1 regress.h
--- regress/usr.sbin/snmpd/regress.h    24 Oct 2023 14:34:40 -0000      1.1
+++ regress/usr.sbin/snmpd/regress.h    26 Oct 2023 08:43:02 -0000
@@ -170,6 +170,7 @@ void agentx_ping_new_index(void);
 void agentx_ping_any_index(void);
 void agentx_ping_nbo_nnbo(void);
 void agentx_ping_nnbo_nbo(void);
+void agentx_ping_invalid_version_close(void);
 void agentx_close_notopen(void);
 void agentx_close_reasonother(void);
 void agentx_close_reasonparseerror(void);
Index: regress/usr.sbin/snmpd/snmpd_regress.c
===================================================================
RCS file: /cvs/src/regress/usr.sbin/snmpd/snmpd_regress.c,v
retrieving revision 1.1
diff -u -p -r1.1 snmpd_regress.c
--- regress/usr.sbin/snmpd/snmpd_regress.c      24 Oct 2023 14:34:40 -0000      
1.1
+++ regress/usr.sbin/snmpd/snmpd_regress.c      26 Oct 2023 08:43:02 -0000
@@ -36,6 +36,7 @@ const struct {
        { "agentx_ping_any_index", agentx_ping_any_index },
        { "agentx_ping_nbo_nnbo", agentx_ping_nbo_nnbo },
        { "agentx_ping_nnbo_nbo", agentx_ping_nnbo_nbo },
+       { "agentx_ping_invalid_version_close", 
agentx_ping_invalid_version_close },
        { "agentx_close_notopen", agentx_close_notopen },
        { "agentx_close_reasonother", agentx_close_reasonother },
        { "agentx_close_reasonparseerror", agentx_close_reasonparseerror },

Reply via email to