From 920ed1f0a3dd9f0e206e3db6a5e109f0f6bee9f8 Mon Sep 17 00:00:00 2001
From: Gerhard Rieger <gerhard@dest-unreach.org>
Date: Thu, 16 Jan 2025 08:00:05 +0100
Subject: [PATCH] Fixed possible crash or fail of option ip-add-membership with
 two parameters

---
 CHANGES    |  5 +++++
 sycls.c    | 15 +++++++++++++++
 sycls.h    |  2 ++
 xio-exec.c |  3 ++-
 xio-ip.c   |  3 ++-
 xiolayer.c |  3 ++-
 xioopts.c  |  3 ++-
 7 files changed, 30 insertions(+), 4 deletions(-)

diff --git a/CHANGES b/CHANGES
index ee0315b..02e50c2 100644
--- a/CHANGES
+++ b/CHANGES
@@ -33,6 +33,10 @@ Corrections:
 	Thanks to Duncan Sands and others for reporting this issue and sending
 	the fix.
 
+	Option ip-add-membership with only two parameters crashed or failed
+	when malloc() does not initialize memory with zeros.
+	Thanks to Nicolas Cavallari for reporting and fixing this bug.
+
 Building:
 	Disabling certain features during configure could break build process.
 
@@ -50,6 +54,7 @@ Testing:
 	SOCKS5 addresses are no longer experimental.
 	Tests: SOCKS5CONNECT_TCP4 SOCKS5LISTEN_TCP4
 
+	Added a developer test that overwrites malloc'ed memory with non-zeros.
 
 ####################### V 1.8.0.2:
 
diff --git a/sycls.c b/sycls.c
index 900cee3..2fbed6f 100644
--- a/sycls.c
+++ b/sycls.c
@@ -1513,6 +1513,9 @@ void *Malloc(size_t size) {
       Error1("malloc("F_Zd"): out of memory", size);
       return NULL;
    }
+#if WITH_DEVTESTS
+   memset(result, 0x55, size);
+#endif /* WITH_DEVTESTS */
    return result;
 }
 
@@ -1540,6 +1543,18 @@ void *Realloc(void *ptr, size_t size) {
    return result;
 }
 
+/* Like Realloc(), but gets info about old size for overwrite test */
+void *Realloc3(void *ptr, size_t size, size_t oldsize) {
+   void *result = Realloc(ptr, size);
+   if (result == NULL)
+      return result;
+#if WITH_DEVTESTS
+   if (size > oldsize)
+      memset(result+oldsize, 0x55, size-oldsize);
+#endif /* WITH_DEVTESTS */
+   return result;
+}
+
 #if _WITH_TERMIOS
 int Tcgetattr(int fd, struct termios *termios_p) {
    int i, result, _errno;
diff --git a/sycls.h b/sycls.h
index 8f8ded5..fe9bb70 100644
--- a/sycls.h
+++ b/sycls.h
@@ -148,6 +148,7 @@ struct hostent *Getipnodebyname(const char *name, int af, int flags,
 void *Malloc(size_t size);
 void *Calloc(size_t nmemb, size_t size);
 void *Realloc(void *ptr, size_t size);
+void *Realloc3(void *ptr, size_t size, size_t oldsize);
 int Tcgetattr(int fd, struct termios *termios_p);
 int Tcsetattr(int fd, int optional_actions, struct termios *termios_p);
 char *Ttyname(int fd);
@@ -257,6 +258,7 @@ void Add_history(const char *string);
 #define Malloc(s) malloc(s)
 #define Calloc(n,s) calloc(n,s)
 #define Realloc(p,s) realloc(p,s)
+#define Realloc3(p,s,o) realloc(p,s)
 #define Tcgetattr(f,t) tcgetattr(f,t)
 #define Tcsetattr(f,o,t) tcsetattr(f,o,t)
 #define Ttyname(f) ttyname(f)
diff --git a/xio-exec.c b/xio-exec.c
index bed513c..303d429 100644
--- a/xio-exec.c
+++ b/xio-exec.c
@@ -84,7 +84,8 @@ static int xioopen_exec(
       while (*strp == ' ') {
 	 while (*++strp == ' ')  ;
 	 if ((pargc & 0x07) == 0) {
-	    pargv = Realloc(pargv, (pargc+8)*sizeof(char *));
+	    /*0 pargv = Realloc(pargv, (pargc+8)*sizeof(char *)); */
+	    pargv = Realloc3(pargv, (pargc+8)*sizeof(char *), pargc*sizeof(char *));
 	    if (pargv == NULL)  return STAT_RETRYLATER;
 	 }
 	 pargv[pargc++] = tokp;
diff --git a/xio-ip.c b/xio-ip.c
index 455ac47..308973b 100644
--- a/xio-ip.c
+++ b/xio-ip.c
@@ -1112,13 +1112,14 @@ int xiotype_ip_add_membership(
 		      opt->value2.u_string/*param2*/,
 		      opt->value3.u_string/*ifindex*/);
 	} else {
-		/*0 opt->value3.u_string = NULL; / * is NULL from init */
+		opt->value3.u_string = NULL; /* is not NULL from init! */
 		Info3("setting option \"%s\" to {\"%s\",\"%s\"}",
 		      ent->desc->defname,
 		      opt->value.u_string/*multiaddr*/,
 		      opt->value2.u_string/*param2*/);
 	}
 #else /* !HAVE_STRUCT_IP_MREQN */
+	opt->value3.u_string = NULL;
 	Info3("setting option \"%s\" to {\"%s\",\"%s\"}",
 	      ent->desc->defname,
 	      opt->value.u_string/*multiaddr*/,
diff --git a/xiolayer.c b/xiolayer.c
index 83b8839..a378293 100644
--- a/xiolayer.c
+++ b/xiolayer.c
@@ -48,7 +48,8 @@ int xio_chdir(
 		free(tmp_dir);
 		return -1;
 	}
-	*orig_dir = Realloc(*orig_dir, strlen(*orig_dir)+1);
+	/*0 *orig_dir = Realloc(*orig_dir, strlen(*orig_dir)+1); */
+	*orig_dir = Realloc3(*orig_dir, strlen(*orig_dir)+1, PATH_MAX);
 
 	if (Chdir(tmp_dir) < 0) {
 		Error2("chdir(\"%s\"): %s", tmp_dir, strerror(errno));
diff --git a/xioopts.c b/xioopts.c
index 81f1e53..a93a1b6 100644
--- a/xioopts.c
+++ b/xioopts.c
@@ -2768,7 +2768,8 @@ int parseopts_table(const char **a, groups_t groups, struct opt **opts,
 
       ++i;
       if ((i % 8) == 0) {
-	 *opts = Realloc(*opts, (i+8) * sizeof(struct opt));
+	 /*0 *opts = Realloc(*opts, (i+8) * sizeof(struct opt)); */
+	 *opts = Realloc3(*opts, (i+8) * sizeof(struct opt), i * sizeof(struct opt));
 	 if (*opts == NULL) {
 	    return -1;
 	 }