[subset] Fixed out of bounds read when subsetting hdmx.

This commit is contained in:
Garret Rieger 2018-03-20 16:31:21 -07:00
parent e597436b99
commit 3531efdb4c
3 changed files with 47 additions and 6 deletions

View File

@ -43,12 +43,15 @@ struct DeviceRecord
struct SubsetView struct SubsetView
{ {
const DeviceRecord *source_device_record; const DeviceRecord *source_device_record;
unsigned int size_device_record;
hb_subset_plan_t *subset_plan; hb_subset_plan_t *subset_plan;
inline void init(const DeviceRecord *source_device_record, inline void init(const DeviceRecord *source_device_record,
unsigned int size_device_record,
hb_subset_plan_t *subset_plan) hb_subset_plan_t *subset_plan)
{ {
this->source_device_record = source_device_record; this->source_device_record = source_device_record;
this->size_device_record = size_device_record;
this->subset_plan = subset_plan; this->subset_plan = subset_plan;
} }
@ -57,11 +60,17 @@ struct DeviceRecord
return this->subset_plan->gids_to_retain_sorted.len; 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]; 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 @@ struct DeviceRecord
this->max_width.set (subset_view.source_device_record->max_width); this->max_width.set (subset_view.source_device_record->max_width);
for (unsigned int i = 0; i < subset_view.len(); i++) 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); return_trace (true);
} }
@ -133,9 +150,10 @@ struct hdmx
for (unsigned int i = 0; i < source_hdmx->num_records; i++) for (unsigned int i = 0; i < source_hdmx->num_records; i++)
{ {
DeviceRecord::SubsetView subset_view; 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); return_trace (true);

View File

@ -50,6 +50,28 @@ test_subset_hdmx_simple_subset (void)
hb_face_destroy (face_ac); hb_face_destroy (face_ac);
} }
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 static void
test_subset_hdmx_noop (void) test_subset_hdmx_noop (void)
{ {
@ -75,6 +97,7 @@ main (int argc, char **argv)
hb_test_init (&argc, &argv); hb_test_init (&argc, &argv);
hb_test_add (test_subset_hdmx_simple_subset); hb_test_add (test_subset_hdmx_simple_subset);
hb_test_add (test_subset_hdmx_invalid);
hb_test_add (test_subset_hdmx_noop); hb_test_add (test_subset_hdmx_noop);
return hb_test_run(); return hb_test_run();