From cf6d1faf367b47c79ded23afc0d3fd3f38abfaea Mon Sep 17 00:00:00 2001
From: Patrik Nyblom <pan@erlang.org>
Date: Mon, 27 Aug 2012 17:55:50 +0200
Subject: Teach VM not to dump core on long pathnames

Long input paths (longer than MAX_PATH) would get copied
into a buffer of size MAX_PATH for read_link and altname
in efile_drv.
Also fixed misuse of size_t parameter as wchar_t *
string length in win_efile:efile_readlink.
---
 erts/emulator/drivers/common/efile_drv.c | 12 +++++++++---
 erts/emulator/drivers/win32/win_efile.c  |  5 +++--
 lib/kernel/test/file_SUITE.erl           |  1 +
 3 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c
index f24098025e..912f5d3d8b 100644
--- a/erts/emulator/drivers/common/efile_drv.c
+++ b/erts/emulator/drivers/common/efile_drv.c
@@ -206,6 +206,9 @@ dt_private *get_dt_private(int);
 #  define KEY(desc) (&(desc)->key)
 #endif
 
+#ifndef MAX
+#  define MAX(x, y) (((x) > (y)) ? (x) : (y))
+#endif
 
 #ifdef FILENAMES_16BIT
 #ifdef USE_VM_PROBES
@@ -2848,8 +2851,9 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count)
 
     case FILE_READLINK:
 	{
-	    d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + RESBUFSIZE + 1);
-	
+	    d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + 
+			      MAX(RESBUFSIZE, (FILENAME_BYTELEN(name) +  
+					       FILENAME_CHARSIZE))  + 1);
 	    FILENAME_COPY(d->b, name);
 #ifdef USE_VM_PROBES
 	    dt_s1 = d->b;
@@ -2864,7 +2868,9 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count)
 
     case FILE_ALTNAME:
 	{
-	    d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + RESBUFSIZE + 1);
+	     d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + 
+			       MAX(RESBUFSIZE, (FILENAME_BYTELEN(name) +  
+						FILENAME_CHARSIZE))  + 1);
 	    FILENAME_COPY(d->b, name);
 #ifdef USE_VM_PROBES
 	    dt_s1 = d->b;
diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c
index 606fa1d7de..a3a5944245 100644
--- a/erts/emulator/drivers/win32/win_efile.c
+++ b/erts/emulator/drivers/win32/win_efile.c
@@ -897,7 +897,8 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo,
 	     we should be able to find its target */
 	    WCHAR target_name[_MAX_PATH];
 	    if (efile_readlink(errInfo, (char *) name, 
-			       (char *) target_name,256) == 1) {
+			       (char *) target_name, 
+			       _MAX_PATH * sizeof(WCHAR)) == 1) {
 		FindClose(findhandle);
 		return efile_fileinfo(errInfo, pInfo,
 				      (char *) target_name, info_for_link);
@@ -1386,7 +1387,7 @@ efile_readlink(Efile_error* errInfo, char* name, char* buffer, size_t size)
 		HANDLE h = CreateFileW(wname, GENERIC_READ, 0,NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
 		int len;
 		if(h != INVALID_HANDLE_VALUE) {
-		    success = pGetFinalPathNameByHandle(h, wbuffer, size,0);
+		    success = pGetFinalPathNameByHandle(h, wbuffer, size / sizeof(WCHAR),0);
 		    /* GetFinalPathNameByHandle prepends path with "\\?\": */
 		    len = wcslen(wbuffer);
 		    wmemmove(wbuffer,wbuffer+4,len-3);
diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl
index 2b6af7e1fb..848db06e82 100644
--- a/lib/kernel/test/file_SUITE.erl
+++ b/lib/kernel/test/file_SUITE.erl
@@ -2358,6 +2358,7 @@ symlinks(doc) -> "Test operations on symbolic links (for Unix).";
 symlinks(suite) -> [];
 symlinks(Config) when is_list(Config) ->
     ?line Dog = test_server:timetrap(test_server:seconds(10)),
+    ?line {error, _} = ?FILE_MODULE:read_link(lists:duplicate(10000,$a)),
     ?line RootDir = ?config(priv_dir, Config),
     ?line NewDir = filename:join(RootDir, 
 				 atom_to_list(?MODULE)
-- 
cgit v1.2.3