[PATCH] erl_call: fix multiple buffer overflows

Michael Santos <>
Sun Aug 22 00:40:25 CEST 2010


Check operations that can overflow, e.g.,

erl_call -sname $(perl -e 'print "x"x5000')
perl -e 'print "-module(", "x"x10000, ");"' | erl_call -m -r -sname foo
---
 lib/erl_interface/src/prog/erl_call.c |  132 +++++++++++++++++++++++----------
 1 files changed, 93 insertions(+), 39 deletions(-)

diff --git a/lib/erl_interface/src/prog/erl_call.c b/lib/erl_interface/src/prog/erl_call.c
index 93b84cb..7b8ba2c 100644
--- a/lib/erl_interface/src/prog/erl_call.c
+++ b/lib/erl_interface/src/prog/erl_call.c
@@ -123,6 +123,10 @@ static int do_connect(ei_cnode *ec, char *nodename, struct call_flags *flags);
 static int read_stdin(char **buf);
 static void split_apply_string(char *str, char **mod, 
 			       char **fun, char **args);
+static void* my_malloc(size_t size);
+static void* my_calloc(size_t nmemb, size_t size);
+static void* my_realloc(void *old, size_t size);
+static char* my_strdup(char *s);
 
 
 /***************************************************************************
@@ -132,7 +136,6 @@ static void split_apply_string(char *str, char **mod,
  ***************************************************************************/
 
 /* FIXME isn't VxWorks to handle arguments differently? */
-/* FIXME check errors from malloc */
 
 #if !defined(VXWORKS)
 int main(int argc, char *argv[])
@@ -165,8 +168,7 @@ int erl_call(int argc, char **argv)
 		usage_arg(progname, "-sname ");
 	    }
 
-	    flags.node = (char *) malloc(strlen(argv[i+1]) + 1);
-	    strcpy(flags.node, argv[i+1]);
+	    flags.node = my_strdup(argv[i+1]);
 	    i++;
 	    flags.use_long_name = 0;
 	} else if (strcmp(argv[i], "-name") == 0) {  /* -name NAME */
@@ -174,8 +176,7 @@ int erl_call(int argc, char **argv)
 		usage_arg(progname, "-name ");
 	    }
 
-	    flags.node = (char *) malloc(strlen(argv[i+1]) + 1);
-	    strcpy(flags.node, argv[i+1]);
+	    flags.node = my_strdup(argv[i+1]);
 	    i++;
 	    flags.use_long_name = 1;
 	} else {
@@ -210,16 +211,14 @@ int erl_call(int argc, char **argv)
 		    usage_arg(progname, "-c ");
 		}
 		flags.cookiep = 1;
-		flags.cookie = (char *) malloc(strlen(argv[i+1]) + 1);
-		strcpy(flags.cookie, argv[i+1]);
+		flags.cookie = my_strdup(argv[i+1]);
 		i++;
 		break;
 	    case 'n':
 		if (i+1 >= argc) {
 		    usage_arg(progname, "-n ");
 		}
-		flags.node = (char *) malloc(strlen(argv[i+1]) + 1);
-		strcpy(flags.node, argv[i+1]);
+		flags.node = my_strdup(argv[i+1]);
 		flags.use_long_name = 1;
 		i++;
 		break;
@@ -227,24 +226,21 @@ int erl_call(int argc, char **argv)
 		if (i+1 >= argc) {
 		    usage_arg(progname, "-h ");
 		}
-		flags.hidden = (char *) malloc(strlen(argv[i+1]) + 1);
-		strcpy(flags.hidden, argv[i+1]);
+		flags.hidden = my_strdup(argv[i+1]);
 		i++;
 		break;
 	    case 'x':
 		if (i+1 >= argc) {
 		    usage_arg(progname, "-x ");
 		}
-		flags.script = (char *) malloc(strlen(argv[i+1]) + 1);
-		strcpy(flags.script, argv[i+1]);
+		flags.script = my_strdup(argv[i+1]);
 		i++;
 		break;
 	    case 'a':
 		if (i+1 >= argc) {
 		    usage_arg(progname, "-a ");
 		}
-		flags.apply = (char *) malloc(strlen(argv[i+1]) + 1);
-		strcpy(flags.apply, argv[i+1]);
+		flags.apply = my_strdup(argv[i+1]);
 		i++;
 		break;
 	    case '?':
@@ -304,8 +300,7 @@ int erl_call(int argc, char **argv)
     if (flags.hidden == NULL) {
       /* As default we are  */
       i = flags.randomp ? (time(NULL) % 997) : 17;
-      /* FIXME allocates to small !!! */
-      flags.hidden = (char *) malloc(3 + 2 ); /* c17 or cXYZ */
+      flags.hidden = (char *) my_malloc(10 + 2 ); /* c17 or cXYZ */
 #if defined(VXWORKS)
       sprintf(flags.hidden, "c%d",
 	  i < 0 ?  (int) taskIdSelf() : i);
@@ -330,17 +325,24 @@ int erl_call(int argc, char **argv)
       initWinSock();
 #endif
 
-      gethostname(h_hostname, EI_MAXHOSTNAMELEN);
+      if (gethostname(h_hostname, EI_MAXHOSTNAMELEN) < 0) {
+	  fprintf(stderr,"erl_call: failed to get host name: %d\n", errno);
+	  exit(1);
+      }
       if ((hp = ei_gethostbyname(h_hostname)) == 0) {
 	  fprintf(stderr,"erl_call: can't resolve hostname %s\n", h_hostname);
 	  exit(1);
       }
-      /* If shortnames cut of the name at first '.' */
+      /* If shortnames, cut off the name at first '.' */
       if (flags.use_long_name == 0 && (ct = strchr(hp->h_name, '.')) != NULL) {
 	  *ct = '\0';
       }
-      strcpy(h_hostname, hp->h_name);
+      strncpy(h_hostname, hp->h_name, EI_MAXHOSTNAMELEN);
       memcpy(&h_ipadr.s_addr, *hp->h_addr_list, sizeof(struct in_addr));
+      if (strlen(h_alivename) + strlen(h_hostname) + 2 > sizeof(h_nodename)) {
+	  fprintf(stderr,"erl_call: hostname too long: %s\n", h_hostname);
+	  exit(1);
+      }
       sprintf(h_nodename, "%s@%s", h_alivename, h_hostname);
       
       if (ei_connect_xinit(&ec, h_hostname, h_alivename, h_nodename,
@@ -368,11 +370,15 @@ int erl_call(int argc, char **argv)
 	fprintf(stderr,"erl_call: can't get_hostent(%s)\n", host);
 	exit(1);
     }
-    /* If shortnames cut of the name at first '.' */
+    /* If shortnames, cut off the name at first '.' */
     if (flags.use_long_name == 0 && (ct = strchr(hp->h_name, '.')) != NULL) {
 	*ct = '\0';
     }
-    strcpy(host_name, hp->h_name);
+    strncpy(host_name, hp->h_name, EI_MAXHOSTNAMELEN);
+    if (strlen(flags.node) + strlen(host_name) + 2 > sizeof(nodename)) {
+	fprintf(stderr,"erl_call: nodename too long: %s\n", flags.node);
+	exit(1);
+    }
     sprintf(nodename, "%s@%s", flags.node, host_name);
 
     /* 
@@ -401,7 +407,7 @@ int erl_call(int argc, char **argv)
 
 	ei_encode_empty_list(NULL, &i);
 
-	p = (char *)malloc(i);
+	p = (char *)my_malloc(i);
 	i = 0;		/* Reset */
 	  
 	ei_encode_empty_list(p, &i);
@@ -426,6 +432,10 @@ int erl_call(int argc, char **argv)
     if (flags.modp && (modname != NULL)) {
       char fname[256];
 
+      if (strlen(modname) + 4 + 1 > sizeof(fname)) {
+      fprintf(stderr,"erl_call: module name too long: %s\n", modname);
+      exit(1);
+      }
       strcpy(fname, modname);
       strcat(fname, ".erl");
 
@@ -443,7 +453,7 @@ int erl_call(int argc, char **argv)
 	  ei_encode_binary(NULL, &i, module, modsize);
 	  ei_encode_empty_list(NULL, &i);
 
-	  p = (char *)malloc(i);
+	  p = (char *)my_malloc(i);
 	  i = 0;		/* Reset */
 	  
 	  ei_encode_list_header(p, &i, 2);
@@ -476,7 +486,7 @@ int erl_call(int argc, char **argv)
 	  ei_encode_empty_list(NULL, &i);
 	  ei_encode_empty_list(NULL, &i);
 
-	  p = (char *)malloc(i);
+	  p = (char *)my_malloc(i);
 	  i = 0;		/* Reset */
 	  
 	  ei_encode_list_header(p, &i, 2);
@@ -521,7 +531,7 @@ int erl_call(int argc, char **argv)
 	  ei_encode_binary(NULL, &i, evalbuf, len);
 	  ei_encode_empty_list(NULL, &i);
 
-	  p = (char *)malloc(i);
+	  p = (char *)my_malloc(i);
 	  i = 0;		/* Reset */
 	  
 	  ei_encode_list_header(p, &i, 1);
@@ -719,32 +729,28 @@ static void split_apply_string(char *str,
 
   EAT(str);
   len = str-begin;
-  *mod = (char *) calloc(len + 1, sizeof(char));
+  *mod = (char *) my_calloc(len + 1, sizeof(char));
   memcpy(*mod, begin, len);
 
   SKIP_SPACE(str);
   if (*str == '\0') {
-    *fun = (char *) calloc(strlen(start)+1, sizeof(char));
-    strcpy(*fun, start);
-    *args = (char *) calloc(strlen(empty_list)+1, sizeof(char));
-    strcpy(*args, empty_list);
+    *fun = my_strdup(start);
+    *args = my_strdup(empty_list);
     return;
   }
   begin = str;
   EAT(str);
   len = str-begin;
-  *fun = (char *) calloc(len + 1, sizeof(char));
+  *fun = (char *) my_calloc(len + 1, sizeof(char));
   memcpy(*fun, begin, len);
 
   SKIP_SPACE(str);
   if (*str == '\0') {
-    *args = (char *) calloc(strlen(empty_list)+1, sizeof(char));
-    strcpy(*args, empty_list);
+    *args = my_strdup(empty_list);
     return;
   }
 
-  *args = (char *) calloc(strlen(str) + 1, sizeof(char));
-  strcpy(*args, str);
+  *args = my_strdup(str);
   
   return;
 
@@ -760,7 +766,7 @@ static int read_stdin(char **buf)
     int bsize = BUFSIZ;
     int len = 0;
     int i;
-    char *tmp = (char *) malloc(bsize);
+    char *tmp = (char *) my_malloc(bsize);
 
     while (1) {
 	if ((i = read(0, &tmp[len], bsize-len)) < 0) {
@@ -772,7 +778,7 @@ static int read_stdin(char **buf)
 	    len += i;
 	    if ((len+50) > bsize) {
 		bsize = len * 2;
-		tmp = (char *) realloc(tmp, bsize);
+		tmp = (char *) my_realloc(tmp, bsize);
 	    } else {
 		continue;
 	    }
@@ -809,7 +815,7 @@ static int get_module(char **mbuf, char **mname)
       }
     } /* while */
     i = tmp - start;
-    *mname = (char *) calloc(i+1, sizeof(char));
+    *mname = (char *) my_calloc(i+1, sizeof(char));
     memcpy(*mname, start, i);
   }
   if (*mbuf)
@@ -905,3 +911,51 @@ static void initWinSock(void)
     }
 }
 #endif
+
+
+/***************************************************************************
+ *
+ *  Utility functions
+ *
+ ***************************************************************************/
+
+static void* my_malloc(size_t size)
+{
+    void *p = malloc(size);
+    if (p == NULL) {
+        fprintf(stderr,"erl_call: insufficient memory\n");
+        exit(1);
+    }
+    return p;
+}
+
+static void* my_calloc(size_t nmemb, size_t size)
+{
+    void *p = calloc(nmemb, size);
+    if (p == NULL) {
+        fprintf(stderr,"erl_call: insufficient memory\n");
+        exit(1);
+    }
+    return p;
+}
+
+static void* my_realloc(void *old, size_t size)
+{
+    void *p = realloc(old, size);
+    if (!p) {
+        fprintf(stderr, "erl_call: cannot reallocate %u bytes of memory from %p\n",
+                (unsigned) size, old);
+        exit (1);
+    }
+    return p;
+}
+
+static char* my_strdup(char *s)
+{   
+    char *p = strdup(s);
+    if (p == NULL) {
+        fprintf(stderr,"erl_call: insufficient memory\n");
+        exit(1);
+    }
+    return p;
+}
-- 
1.7.0.4



More information about the erlang-patches mailing list