gbranden pushed a commit to branch master
in repository groff.

commit 3315594545f224698b312bedfb19dec379110611
Author: G. Branden Robinson <[email protected]>
AuthorDate: Wed Sep 30 02:13:48 2026 -0500

    [hpftodit]: Fix Savannah #68684.
    
    * src/utils/hpftodit/hpftodit.cpp (output_font_name): Heavily revise to
      more carefully validate TFM input file and manage memory.  Fatally
      error out upon reading a font name length claimed by the file that is
      absurd, avoiding unpredictable, input-driven heap memory allocation.
      Zero out the heap-allocated buffer immediately.  Fatally error out
      upon reading a font name that starts with whitespace character.
      Rewrite trailing whitespace-stripping loop to avoid overwriting and
      backwards-overreading the buffer.
    
    Fixes <https://savannah.gnu.org/bugs/?68684>.  Thanks to Pavol Sloboda
    for the report and a reproducer.  Problem appears to date back to commit
    65a386ebce, 2003-12-27.
---
 ChangeLog                       | 16 ++++++++++++
 src/utils/hpftodit/hpftodit.cpp | 54 +++++++++++++++++++++++++++++++++--------
 2 files changed, 60 insertions(+), 10 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 52fbcef91..73469b9aa 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2026-09-30  G. Branden Robinson <[email protected]>
+
+       * src/utils/hpftodit/hpftodit.cpp (output_font_name): Heavily
+       revise to more carefully validate TFM input file and manage
+       memory.  Fatally error out upon reading a font name length
+       claimed by the file that is absurd, avoiding unpredictable,
+       input-driven heap memory allocation.  Zero out the
+       heap-allocated buffer immediately.  Fatally error out upon
+       reading a font name that starts with whitespace character.
+       Rewrite trailing whitespace-stripping loop to avoid overwriting
+       and backwards-overreading the buffer.
+
+       Fixes <https://savannah.gnu.org/bugs/?68684>.  Thanks to Pavol
+       Sloboda for the report and a reproducer.  Problem appears to
+       date back to commit 65a386ebce, 2003-12-27.
+
 2026-09-30  G. Branden Robinson <[email protected]>
 
        [hpftodit]: Regression-test Savannah #68684.
diff --git a/src/utils/hpftodit/hpftodit.cpp b/src/utils/hpftodit/hpftodit.cpp
index f247d5d79..1f3ddb10d 100644
--- a/src/utils/hpftodit/hpftodit.cpp
+++ b/src/utils/hpftodit/hpftodit.cpp
@@ -1,4 +1,5 @@
 /* Copyright 1994-2004 Free Software Foundation, Inc.
+                  2026 G. Branden Robinson
 
 Written by James Clark ([email protected])
 
@@ -581,6 +582,20 @@ require_tag(tag_type t)
 }
 
 // put a human-readable font name in the file
+//
+// This algorithm seems to conform to a "Format 16" "typeface string
+// segment".  The font "name" is packed into 4 bytes, such that it is
+// either 4 8-bit characters or a 32-bit offset to a 17-byte
+// fixed-width field later in the file that is padded with spaces on the
+// right-hand side and ends with a null terminator.
+//
+// Possibly the short 4-byte names can be RHS space-padded as well, but
+// I have no specimens that do so.  We assume they can be.
+//
+// See:
+// https://developers.hp.com/system/files/attachments/
+//   PCL%20Implementors%20Guide-10-downloading%20fonts.pdf
+// --GBR
 static void
 output_font_name(File &f)
 {
@@ -589,7 +604,15 @@ output_font_name(File &f)
   if (!tag_info(font_name_tag).present)
     return;
   int count = tag_info(font_name_tag).count;
-  char *font_name = new char[count];
+  if (count < 1)
+    fatal("TFM file claims bogus font name length of %1", count);
+  if (count > 17)
+    fatal("TFM file claims oversized font name length of %1", count);
+  // The font name may be fixed-width, but our string isn't.
+  size_t font_name_size = count + 1 /* '\0' */;
+  // C++03: new char[count]();
+  char *font_name = new char[font_name_size];
+  (void) memset(font_name, 0, font_name_size * sizeof(char));
 
   if (count > 4) {     // value is a file offset to the string
     f.seek(tag_info(font_name_tag).value);
@@ -598,15 +621,26 @@ output_font_name(File &f)
     while (--n)
       *p++ = f.get_byte();
   }
-  else                 // orig_value contains the string
-    sprintf(font_name, "%.*s",
-           count, tag_info(font_name_tag).orig_value);
-
-  // remove any trailing space
-  p = font_name + count - 1;
-  while (csspace(*--p))
-    ;
-  *(p + 1) = '\0';
+  // otherwise orig_value contains the string
+  else {
+    if (csspace(*(tag_info(font_name_tag).orig_value)))
+      fatal("font name cannot start with a whitespace character");
+    snprintf(font_name, font_name_size, "%s",
+            tag_info(font_name_tag).orig_value);
+  }
+
+  // Remove any trailing whitespace characters.
+  p = font_name + count;
+  // First, skip over any trailing nulls.
+  while ((p > font_name) && ('\0' == *p))
+    p--;
+  while (p > font_name) {
+    if (csspace(*p))
+      *p = '\0';
+    else
+      break;
+    p--;
+  }
   printf("# %s\n", font_name);
   delete[] font_name;
 }

_______________________________________________
groff-commit mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/groff-commit

Reply via email to