[subset] Fixed out of bounds read when subsetting hdmx.
diff --git a/src/hb-ot-hdmx-table.hh b/src/hb-ot-hdmx-table.hh
index f08fe39..8df9957 100644
--- a/src/hb-ot-hdmx-table.hh
+++ b/src/hb-ot-hdmx-table.hh
@@ -43,12 +43,15 @@
struct SubsetView
{
const DeviceRecord *source_device_record;
+ unsigned int size_device_record;
hb_subset_plan_t *subset_plan;
inline void init(const DeviceRecord *source_device_record,
+ unsigned int size_device_record,
hb_subset_plan_t *subset_plan)
{
this->source_device_record = source_device_record;
+ this->size_device_record = size_device_record;
this->subset_plan = subset_plan;
}
@@ -57,11 +60,17 @@
return this->subset_plan->gids_to_retain_sorted.len;
}
- inline const HBUINT8& operator [] (unsigned int i) const
+ inline const HBUINT8* operator [] (unsigned int i) const
{
- if (unlikely (i >= len())) return Null(HBUINT8);
+ if (unlikely (i >= len())) return nullptr;
hb_codepoint_t gid = this->subset_plan->gids_to_retain_sorted [i];
- return this->source_device_record->widths[gid];
+
+ const HBUINT8* width = &(this->source_device_record->widths[gid]);
+
+ if (width < ((const HBUINT8 *) this->source_device_record) + size_device_record)
+ return width;
+ else
+ return nullptr;
}
};
@@ -85,7 +94,15 @@
this->max_width.set (subset_view.source_device_record->max_width);
for (unsigned int i = 0; i < subset_view.len(); i++)
- widths[i].set (subset_view[i]);
+ {
+ const HBUINT8 *width = subset_view[i];
+ if (!width)
+ {
+ DEBUG_MSG(SUBSET, nullptr, "HDMX width for new gid %d is missing.", i);
+ return_trace (false);
+ }
+ widths[i].set (*width);
+ }
return_trace (true);
}
@@ -133,9 +150,10 @@
for (unsigned int i = 0; i < source_hdmx->num_records; i++)
{
DeviceRecord::SubsetView subset_view;
- subset_view.init (&(*source_hdmx)[i], plan);
+ subset_view.init (&(*source_hdmx)[i], source_hdmx->size_device_record, plan);
- c->start_embed<DeviceRecord> ()->serialize (c, subset_view);
+ if (!c->start_embed<DeviceRecord> ()->serialize (c, subset_view))
+ return_trace (false);
}
return_trace (true);
diff --git a/test/api/fonts/crash-ccc61c92d589f895174cdef6ff2e3b20e9999a1a b/test/api/fonts/crash-ccc61c92d589f895174cdef6ff2e3b20e9999a1a
new file mode 100644
index 0000000..1af243e
--- /dev/null
+++ b/test/api/fonts/crash-ccc61c92d589f895174cdef6ff2e3b20e9999a1a
Binary files differ
diff --git a/test/api/test-subset-hdmx.c b/test/api/test-subset-hdmx.c
index 609ee06..dd20b2a 100644
--- a/test/api/test-subset-hdmx.c
+++ b/test/api/test-subset-hdmx.c
@@ -51,6 +51,28 @@
}
static void
+test_subset_hdmx_invalid (void)
+{
+ hb_face_t *face = hb_subset_test_open_font("fonts/crash-ccc61c92d589f895174cdef6ff2e3b20e9999a1a");
+
+ hb_subset_input_t *input = hb_subset_input_create_or_fail ();
+ hb_set_t *codepoints = hb_subset_input_unicode_set (input);
+ hb_set_add (codepoints, 'a');
+ hb_set_add (codepoints, 'b');
+ hb_set_add (codepoints, 'c');
+
+ hb_subset_profile_t *profile = hb_subset_profile_create();
+ hb_face_t *subset = hb_subset (face, profile, input);
+ g_assert (subset);
+ g_assert (subset == hb_face_get_empty ());
+
+ hb_subset_input_destroy (input);
+ hb_subset_profile_destroy (profile);
+ hb_face_destroy (subset);
+ hb_face_destroy (face);
+}
+
+static void
test_subset_hdmx_noop (void)
{
hb_face_t *face_abc = hb_subset_test_open_font("fonts/Roboto-Regular.abc.ttf");
@@ -75,6 +97,7 @@
hb_test_init (&argc, &argv);
hb_test_add (test_subset_hdmx_simple_subset);
+ hb_test_add (test_subset_hdmx_invalid);
hb_test_add (test_subset_hdmx_noop);
return hb_test_run();