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