From 1d8a59049ce2ad217edfb717b8743e5ba8cfb409 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Fri, 30 Jul 2021 13:45:03 -0400 Subject: [PATCH] Added sanity checks to the GDS dump from GDS_FILE pointers. Since it is easy to subvert the process by updating GDS without updating the pointers, it is trivial to end up with bad GDS output. The sanity checks confirm that the position pointed to is a complete structure (check begin and end records), and that it has the same name as the cell (this is not a requirement, as there are reasons one might want to point to data from a structure of a different name, but a warning will be printed). --- VERSION | 2 +- calma/CalmaWrite.c | 74 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 70 insertions(+), 6 deletions(-) diff --git a/VERSION b/VERSION index 41adeaf4..8b7418d9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.193 +8.3.194 diff --git a/calma/CalmaWrite.c b/calma/CalmaWrite.c index c4eb4127..7ee0fe5a 100644 --- a/calma/CalmaWrite.c +++ b/calma/CalmaWrite.c @@ -928,7 +928,7 @@ calmaProcessDef(def, outf, do_library) { char *buffer, *offptr, *retfilename; size_t defsize, numbytes; - off_t cellstart, cellend; + off_t cellstart, cellend, structstart; dlong cval; FILE *fi; @@ -1002,33 +1002,97 @@ calmaProcessDef(def, outf, do_library) sscanf(offptr, "%"DLONG_PREFIX"d", &cval); cellstart = (off_t)cval; - fseek(fi, cellstart, SEEK_SET); + + /* GDS_START has been defined as the start of data after the cell */ + /* structure name. However, a sanity check is wise, so move back */ + /* that far and make sure the structure name is there. */ + structstart = cellstart - (off_t)(strlen(def->cd_name)); + if (strlen(def->cd_name) & 0x1) structstart--; + structstart -= 2; + + fseek(fi, structstart, SEEK_SET); + + /* Read the structure name and check against the CellDef name */ + defsize = (size_t)(cellstart - structstart); + buffer = (char *)mallocMagic(defsize + 1); + numbytes = fread(buffer, sizeof(char), (size_t)defsize, fi); + if (numbytes == defsize) + { + buffer[defsize] = '\0'; + if (buffer[0] != 0x06 || buffer[1] != 0x06) + { + TxError("Calma output error: Structure name not found" + " at GDS file position %"DLONG_PREFIX"d\n", cellstart); + TxError("Calma output error: Can't write cell from vendor GDS." + " Using magic's internal definition\n"); + isReadOnly = FALSE; + } + else if (strcmp(&buffer[2], def->cd_name)) + { + TxError("Calma output warning: Structure definition has name" + " %s but cell definition has name %s.\n", + &buffer[2], def->cd_name); + TxError("The structure definition will be given the cell name.\n"); + } + } + else + { + TxError("Calma output error: Can't read cell from vendor GDS." + " Using magic's internal definition\n"); + isReadOnly = FALSE; + } if (cellend < cellstart) /* Sanity check */ { TxError("Calma output error: Bad vendor GDS file reference!\n"); isReadOnly = FALSE; } - else + else if (isReadOnly) { + /* Important note: mallocMagic() is limited to size integer. */ + /* This will fail on a structure larger than ~2GB. */ + defsize = (size_t)(cellend - cellstart); buffer = (char *)mallocMagic(defsize); numbytes = fread(buffer, sizeof(char), (size_t)defsize, fi); + if (numbytes == defsize) { - numbytes = fwrite(buffer, sizeof(char), (size_t)defsize, outf); - if (numbytes <= 0) + /* Sanity check: buffer must end with a structure */ + /* definition end (record 0x07). */ + + if (buffer[defsize - 4] != 0x00 || + buffer[defsize - 3] != 0x04 || + buffer[defsize - 2] != 0x07 || + buffer[defsize - 1] != 0x00) { + TxError("Calma output error: Structure end definition not found" + " at GDS file position %"DLONG_PREFIX"d\n", cellend); TxError("Calma output error: Can't write cell from vendor GDS." " Using magic's internal definition\n"); isReadOnly = FALSE; } + else + { + numbytes = fwrite(buffer, sizeof(char), (size_t)defsize, outf); + if (numbytes <= 0) + { + TxError("Calma output error: Can't write cell from " + "vendor GDS. Using magic's internal " + "definition\n"); + isReadOnly = FALSE; + } + } } else { TxError("Calma output error: Can't read cell from vendor GDS." " Using magic's internal definition\n"); + + /* Additional information as to why data did not match */ + TxError("Size of data requested: %"DLONG_PREFIX"d", defsize); + TxError("Length of data read: %"DLONG_PREFIX"d", numbytes); isReadOnly = FALSE; } freeMagic(buffer);