From c1f45c302a820d2182443eb409df082ae48012ac Mon Sep 17 00:00:00 2001 From: Nick Briggs Date: Wed, 11 Sep 2024 15:59:42 -0700 Subject: [PATCH 1/2] Fix #1826 - emulator crash when too many versions of a file in a directory This is a preliminary fix to avoid a system crash (bus error/seg fault) when operating on a file with too many versions present in the directory. Initial fix is to report an error (EIO, SIMPLE-DEVICE-ERROR) when doing an operation that would result in an out-of-bounds access in the emulator. --- src/dsk.c | 50 ++++++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/src/dsk.c b/src/dsk.c index 516c0611..d0ccdcee 100644 --- a/src/dsk.c +++ b/src/dsk.c @@ -75,7 +75,7 @@ static int get_old(char *dir, FileName *varray, char *afile, char *vfile); static int get_oldest(char *dir, FileName *varray, char *afile, char *vfile); static int get_new(char *dir, FileName *varray, char *afile, char *vfile); static int get_old_new(char *dir, FileName *varray, char *afile, char *vfile); -static int get_version_array(char *dir, char *file, FileName *varray, CurrentVArray *cache); +static int get_version_array(char *dir, char *file, FileName varray[], CurrentVArray *cache); #ifdef DOS static void separate_drive(char *lfname, char *drive) @@ -2938,7 +2938,7 @@ static int make_directory(char *dir) /* */ /************************************************************************/ -static int get_version_array(char *dir, char *file, FileName *varray, CurrentVArray *cache) +static int get_version_array(char *dir, char *file, FileName varray[], CurrentVArray *cache) { #ifdef DOS @@ -2946,7 +2946,7 @@ static int get_version_array(char *dir, char *file, FileName *varray, CurrentVAr char old_file[MAXPATHLEN]; char name[MAXNAMLEN]; char ver[VERSIONLEN]; - FileName *svarray; + int varray_index = 0; struct find_t dirp; struct direct *dp; int rval, drive = 0, isslash = 0; @@ -2987,14 +2987,12 @@ static int get_version_array(char *dir, char *file, FileName *varray, CurrentVAr make_old_version(old_file, lcased_file); - svarray = varray; - TIMEOUT(res = _dos_findfirst(old_file, _A_NORMAL | _A_SUBDIR, &dirp)); if (res == 0) { strcpy(name, dirp.name); - strcpy(svarray->name, name); - svarray->version_no = 0; - svarray++; + strcpy(varray[varray_index].name, name); + varray[varray_index].version_no = 0; + varray_index++; } /*******************************/ @@ -3013,25 +3011,29 @@ static int get_version_array(char *dir, char *file, FileName *varray, CurrentVAr separate_version(name, ver, 1); DOWNCASE(name); - strcpy(svarray->name, dirp.name); + strcpy(varray[varray_index].name, dirp.name); if (*ver == '\0') { /* Versionless file */ - svarray->version_no = 1; + varray[varray_index].version_no = 1; } else { /* * separator_version guarantees ver is a numeric * string. */ - svarray->version_no = strtoul(ver, (char **)NULL, 10); + varray[varray_index].version_no = strtoul(ver, (char **)NULL, 10); } - svarray++; + varray_index++; + if (varray_index >= VERSIONARRAYLENGTH) { + /* how does the specific error get signalled in the DOS case? */ + return (0); + } } /* * The last entry of varray is indicated by setting LASTVERSIONARRAY into * version_no field. */ - svarray->version_no = LASTVERSIONARRAY; + varray[varray_index].version_no = LASTVERSIONARRAY; /* * If more than one files have been stored in varray, we store the name @@ -3040,7 +3042,7 @@ static int get_version_array(char *dir, char *file, FileName *varray, CurrentVAr if (!NoFileP(varray)) { strcpy(name, varray->name); separate_version(name, ver, 1); - strcpy(svarray->name, name); + strcpy(varray[varray_index].name, name); } return (1); @@ -3050,7 +3052,7 @@ static int get_version_array(char *dir, char *file, FileName *varray, CurrentVAr char lcased_file[MAXNAMLEN]; char name[MAXNAMLEN]; char ver[VERSIONLEN]; - FileName *svarray; + int varray_index = 0; DIR *dirp; struct dirent *dp; int rval; @@ -3095,7 +3097,7 @@ static int get_version_array(char *dir, char *file, FileName *varray, CurrentVAr return (0); } - for (S_TOUT(dp = readdir(dirp)), svarray = varray; dp != NULL || errno == EINTR; + for (S_TOUT(dp = readdir(dirp)); dp != NULL || errno == EINTR; errno = 0, S_TOUT(dp = readdir(dirp))) if (dp) { strcpy(name, dp->d_name); @@ -3105,25 +3107,29 @@ static int get_version_array(char *dir, char *file, FileName *varray, CurrentVAr /* * This file can be regarded as a same file in Lisp sense. */ - strcpy(svarray->name, dp->d_name); + strcpy(varray[varray_index].name, dp->d_name); if (*ver == '\0') { /* Versionless file */ - svarray->version_no = 0; + varray[varray_index].version_no = 0; } else { /* * separator_version guarantees ver is a numeric * string. */ - svarray->version_no = strtoul(ver, (char **)NULL, 10); + varray[varray_index].version_no = strtoul(ver, (char **)NULL, 10); + } + varray_index++; + if (varray_index >= VERSIONARRAYLENGTH) { + *Lisp_errno = EIO; + return (0); } - svarray++; } } /* * The last entry of varray is indicated by setting LASTVERSIONARRAY into * version_no field. */ - svarray->version_no = LASTVERSIONARRAY; + varray[varray_index].version_no = LASTVERSIONARRAY; /* * If more than one files have been stored in varray, we store the name @@ -3132,7 +3138,7 @@ static int get_version_array(char *dir, char *file, FileName *varray, CurrentVAr if (!NoFileP(varray)) { strcpy(name, varray->name); separate_version(name, ver, 1); - strcpy(svarray->name, name); + strcpy(varray[varray_index].name, name); } /* From 6fc4bb2f3659b0ae030e5de1583cae308c2bc151 Mon Sep 17 00:00:00 2001 From: Nick Briggs Date: Mon, 16 Sep 2024 17:46:39 -0700 Subject: [PATCH 2/2] Add comment noting that the DOS get_version_array code comes first. --- src/dsk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dsk.c b/src/dsk.c index d0ccdcee..dbe04155 100644 --- a/src/dsk.c +++ b/src/dsk.c @@ -2941,7 +2941,7 @@ static int make_directory(char *dir) static int get_version_array(char *dir, char *file, FileName varray[], CurrentVArray *cache) { #ifdef DOS - + /* DOS version-array builder */ char lcased_file[MAXPATHLEN]; char old_file[MAXPATHLEN]; char name[MAXNAMLEN];