[PATCH 2/8] erlc: prevent buffer overflows

Michael Santos <>
Sat Oct 2 01:55:17 CEST 2010


Check buffer operations and increase the size of the buffer used for
holding command line arguments, since the "-D" switch will be expanded
into 3 arguments when passed to erl.
---
 erts/etc/common/Makefile.in |    2 +-
 erts/etc/common/erlc.c      |   12 +++++++++---
 erts/test/erlc_SUITE.erl    |   16 ++++++++++++++--
 3 files changed, 24 insertions(+), 6 deletions(-)

diff --git a/erts/etc/common/Makefile.in b/erts/etc/common/Makefile.in
index 333390b..fe7d7b4 100644
--- a/erts/etc/common/Makefile.in
+++ b/erts/etc/common/Makefile.in
@@ -327,7 +327,7 @@ $(OBJDIR)/$(ERLEXEC).o: $(ERLEXECDIR)/$(ERLEXEC).c
 	$(CC) -I$(EMUDIR) $(CFLAGS) -o $@ -c $(ERLEXECDIR)/$(ERLEXEC).c
 endif
 $(BINDIR)/@: $(OBJDIR)/erlc.o
-	$(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/erlc.o -L$(OBJDIR) $(LIBS)
+	$(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/erlc.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS)
 
 $(OBJDIR)/erlc.o: erlc.c
 	$(CC) $(CFLAGS) -o $@ -c erlc.c
diff --git a/erts/etc/common/erlc.c b/erts/etc/common/erlc.c
index 09aca19..b59453a 100644
--- a/erts/etc/common/erlc.c
+++ b/erts/etc/common/erlc.c
@@ -160,6 +160,9 @@ main(int argc, char** argv)
     env = get_env("ERLC_EMULATOR");
     emulator = env ? env : get_default_emulator(argv[0]);
 
+    if (strlen(emulator) >= MAXPATHLEN)
+        error("Value of environment variable ERLC_EMULATOR is too large");
+
     /*
      * Allocate the argv vector to be used for arguments to Erlang.
      * Arrange for starting to pushing information in the middle of
@@ -170,7 +173,7 @@ main(int argc, char** argv)
      * base of the eargv vector, and move it up later.
      */
 
-    eargv_size = argc*4+100;
+    eargv_size = argc*6+100;
     eargv_base = (char **) emalloc(eargv_size*sizeof(char*));
     eargv = eargv_base;
     eargc = 0;
@@ -419,7 +422,7 @@ process_opt(int* pArgc, char*** pArgv, int offset)
 static void
 push_words(char* src)
 {
-    char sbuf[1024];
+    char sbuf[MAXPATHLEN];
     char* dst;
 
     dst = sbuf;
@@ -595,7 +598,7 @@ error(char* format, ...)
     va_list ap;
     
     va_start(ap, format);
-    vsprintf(sbuf, format, ap);
+    erts_vsnprintf(sbuf, sizeof(sbuf), format, ap);
     va_end(ap);
     fprintf(stderr, "erlc: %s\n", sbuf);
     exit(1);
@@ -624,6 +627,9 @@ get_default_emulator(char* progname)
     char sbuf[MAXPATHLEN];
     char* s;
 
+    if (strlen(progname) >= sizeof(sbuf))
+        return ERL_NAME;
+
     strcpy(sbuf, progname);
     for (s = sbuf+strlen(sbuf); s >= sbuf; s--) {
 	if (IS_DIRSEP(*s)) {
diff --git a/erts/test/erlc_SUITE.erl b/erts/test/erlc_SUITE.erl
index 437f020..4797f78 100644
--- a/erts/test/erlc_SUITE.erl
+++ b/erts/test/erlc_SUITE.erl
@@ -21,13 +21,13 @@
 %% Tests the erlc command by compiling various types of files.
 
 -export([all/1, compile_erl/1, compile_yecc/1, compile_script/1,
-	 compile_mib/1, good_citizen/1, deep_cwd/1]).
+	 compile_mib/1, good_citizen/1, deep_cwd/1, arg_overflow/1]).
 
 -include_lib("test_server/include/test_server.hrl").
 
 all(suite) ->
     [compile_erl, compile_yecc, compile_script, compile_mib,
-     good_citizen, deep_cwd].
+     good_citizen, deep_cwd, arg_overflow].
 
 %% Copy from erlc_SUITE_data/include/erl_test.hrl.
 
@@ -189,6 +189,18 @@ deep_cwd_1(PrivDir) ->
     ?line true = filelib:is_file("test.beam"),
     ok.
 
+%% Test that a large number of command line switches does not
+%% overflow the argument buffer
+arg_overflow(Config) when is_list(Config) ->
+    ?line {SrcDir, _OutDir, Cmd} = get_cmd(Config),
+    ?line FileName = filename:join(SrcDir, "erl_test_ok.erl"),
+    ?line Args = lists:flatten([ ["-D", integer_to_list(N), "=1 "] ||
+            N <- lists:seq(1,10000) ]),
+    ?line run(Config, Cmd, FileName, Args,
+	      ["Warning: function foo/0 is unused\$",
+	       "_OK_"]),
+    ok.
+
 erlc() ->
     case os:find_executable("erlc") of
 	false ->
-- 
1.7.0.4



More information about the erlang-patches mailing list