I remade a patch for latest FedoraCore user(net-snmp-5.2.1-9.rpm)
Thanks!
-nagata
Tsuyoshi Nagata wrote:
>This is the 2nd patch for fixing snmp_free_session(session) problem.
>
>double free was born by follows.
>snmp_free_session() frees session.
>clear_callbacks() frees session.
>
>And, I send SPEC file for RHEL4 user.
>
>PLEASE discard my dirty
>[net-snmp-5.1.2-agentx_register_callbacks_entry.patch] .
>It fix this clear_callback problem, but this 2 patch helps much better.
>
>NG:net-snmp-5.1.2-agentx_register_callbacks_entry.patch <- My previous work.
>OK:net-snmp-5.1.2-clear_callback3.patch <- Robert's _remove_duplicates
>patch for 5.1.2
>OK:net-snmp-5.1.2-free_session.patch <- fix snmp_free_session() free
>problem.
>
>
>
>Thanks .
>-Nagata
>
>
>
diff -Naurp net-snmp-5.2.1/snmplib/callback.c
net-snmp-5.2.1.n/snmplib/callback.c
--- net-snmp-5.2.1/snmplib/callback.c 2004-09-22 06:59:41.000000000 +0900
+++ net-snmp-5.2.1.n/snmplib/callback.c 2005-04-18 11:54:29.264199931 +0900
@@ -45,6 +45,10 @@
#include <net-snmp/library/callback.h>
#include <net-snmp/library/snmp_api.h>
+
+static void _remove_duplicates(void *ptr, int x, int y);
+
+
static struct snmp_gen_callback
*thecallbacks[MAX_CALLBACK_IDS][MAX_CALLBACK_SUBIDS];
@@ -335,11 +339,34 @@ snmp_unregister_callback(int major, int
return count;
}
+static void
+_remove_duplicates(void *ptr, int x, int y)
+{
+ struct snmp_gen_callback *scp = NULL, *next = NULL;
+ int i,j;
+ for (i=x; i < MAX_CALLBACK_IDS; i++) {
+ for (j=y; j < MAX_CALLBACK_SUBIDS; j++) {
+ scp = thecallbacks[i][j];
+ while (scp != NULL) {
+ next=scp->next;
+ if ((NULL != scp->sc_callback) &&
+ (scp->sc_client_arg != NULL) &&
+ (scp->sc_client_arg == ptr)) {
+ DEBUGMSGTL(("callback", "duplicate client arg\n"));
+ scp->sc_client_arg = NULL;
+ }
+ scp = next;
+ }
+ }
+ }
+}
+
void
clear_callback(void)
{
unsigned int i = 0, j = 0;
struct snmp_gen_callback *scp = NULL, *next = NULL;
+ void *tmp_arg;
if(++_lock > 1) {
snmp_log(LOG_WARNING,
@@ -352,8 +379,23 @@ clear_callback(void)
scp = thecallbacks[i][j];
while (scp != NULL) {
next = scp->next;
+ /*
+ * if there is a client arg, check for duplicates
+ * and then free it.
+ */
if ((NULL != scp->sc_callback) && (scp->sc_client_arg != NULL))
- SNMP_FREE(scp->sc_client_arg);
+ (scp->sc_client_arg != NULL)) {
+ /*
+ * save the client arg, then set it to null so that it
+ * won't look like a duplicate, then check for duplicates
+ * starting at the current i,j (earlier dups should have
+ * already been found) and free the pointer.
+ */
+ tmp_arg = scp->sc_client_arg;
+ scp->sc_client_arg = NULL;
+ _remove_duplicates(tmp_arg, i, j);
+ free(tmp_arg);
+ }
SNMP_FREE(scp);
scp = next;
}
diff -Naurp net-snmp-5.2.1/include/net-snmp/library/callback.h
net-snmp-5.2.1.n/include/net-snmp/library/callback.h
--- net-snmp-5.2.1/include/net-snmp/library/callback.h 2003-07-14
03:19:23.000000000 +0900
+++ net-snmp-5.2.1.n/include/net-snmp/library/callback.h 2005-04-18
11:57:45.778254111 +0900
@@ -57,6 +57,7 @@ extern "C" {
SNMPCallback * new_callback,
void *arg, int matchargs);
void clear_callback (void);
+ void clear_callback_session (void *session);
struct snmp_gen_callback *snmp_callback_list(int major, int minor);
#ifdef __cplusplus
diff -Naurp net-snmp-5.2.1/snmplib/callback.c
net-snmp-5.2.1.n/snmplib/callback.c
--- net-snmp-5.2.1/snmplib/callback.c 2005-04-18 11:58:50.121568379 +0900
+++ net-snmp-5.2.1.n/snmplib/callback.c 2005-04-18 11:57:45.779230326 +0900
@@ -405,6 +405,14 @@ clear_callback(void)
--_lock;
}
+void
+clear_callback_session(void*session)
+{
+
+ _remove_duplicates(session, 0, 0);
+
+}
+
struct snmp_gen_callback *
snmp_callback_list(int major, int minor)
{
diff -Naurp net-snmp-5.2.1/snmplib/snmp_api.c
net-snmp-5.2.1.n/snmplib/snmp_api.c
--- net-snmp-5.2.1/snmplib/snmp_api.c 2005-04-18 11:58:27.494854499 +0900
+++ net-snmp-5.2.1.n/snmplib/snmp_api.c 2005-04-18 11:57:45.785087617 +0900
@@ -1784,6 +1784,8 @@ snmp_free_session(netsnmp_session * s)
SNMP_FREE(s->securityName);
SNMP_FREE(s->securityAuthProto);
SNMP_FREE(s->securityPrivProto);
+ /* session information already frees in snmp_shutdown. */
+ clear_callback_session(s);
free((char *) s);
}
}