core: Handle PlaceObject tags with malformed clip actions

Some SWFs in the wild have PlaceObject tags with ending ClipActions
that are 2 bytes instead of the required 4 bytes (see #2899).
Swallow the error in this case so that the tag can run.
This commit is contained in:
Mike Welsh 2021-02-02 16:46:58 -08:00
parent 8fc37f364f
commit 47f0f980b8
4 changed files with 14 additions and 7 deletions

View File

@ -318,6 +318,7 @@ swf_tests! {
(bitmap_data, "avm1/bitmap_data", 1), (bitmap_data, "avm1/bitmap_data", 1),
(bitmap_data_noise, "avm1/bitmap_data_noise", 1), (bitmap_data_noise, "avm1/bitmap_data_noise", 1),
(array_call_method, "avm1/array_call_method", 1), (array_call_method, "avm1/array_call_method", 1),
(bad_placeobject_clipaction, "avm1/bad_placeobject_clipaction", 2),
(bad_swf_tag_past_eof, "avm1/bad_swf_tag_past_eof", 1), (bad_swf_tag_past_eof, "avm1/bad_swf_tag_past_eof", 1),
(sound, "avm1/sound", 1), (sound, "avm1/sound", 1),
(action_to_integer, "avm1/action_to_integer", 1), (action_to_integer, "avm1/action_to_integer", 1),

View File

@ -0,0 +1,2 @@
Load
EnterFrame

View File

@ -2175,7 +2175,14 @@ impl<'a> Reader<'a> {
event_list.set(ClipEventFlag::LOAD, flags & 0b0000_0001 != 0); event_list.set(ClipEventFlag::LOAD, flags & 0b0000_0001 != 0);
if self.version > 5 { if self.version > 5 {
let flags = self.read_u8()?; // There are SWFs in the wild with malformed final ClipActions that is only two bytes
// instead of four bytes (see #2899). Handle this gracefully to allow the tag to run.
// TODO: We may need a more general way to handle truncated tags, since this has
// occurred in a few different places.
// Allow for only two bytes in the clip action tag.
let flags = self.read_u8().unwrap_or_default();
let flags2 = self.read_u8().unwrap_or_default();
let _ = self.read_u8();
event_list.set(ClipEventFlag::DRAG_OVER, flags & 0b1000_0000 != 0); event_list.set(ClipEventFlag::DRAG_OVER, flags & 0b1000_0000 != 0);
event_list.set(ClipEventFlag::ROLL_OUT, flags & 0b0100_0000 != 0); event_list.set(ClipEventFlag::ROLL_OUT, flags & 0b0100_0000 != 0);
event_list.set(ClipEventFlag::ROLL_OVER, flags & 0b0010_0000 != 0); event_list.set(ClipEventFlag::ROLL_OVER, flags & 0b0010_0000 != 0);
@ -2185,14 +2192,11 @@ impl<'a> Reader<'a> {
event_list.set(ClipEventFlag::INITIALIZE, flags & 0b0000_0010 != 0); event_list.set(ClipEventFlag::INITIALIZE, flags & 0b0000_0010 != 0);
event_list.set(ClipEventFlag::DATA, flags & 0b0000_0001 != 0); event_list.set(ClipEventFlag::DATA, flags & 0b0000_0001 != 0);
let flags = self.read_u8()?;
// Construct was only added in SWF7, but it's not version-gated; // Construct was only added in SWF7, but it's not version-gated;
// Construct events will still fire in SWF6 in a v7+ player. (#1424) // Construct events will still fire in SWF6 in a v7+ player. (#1424)
event_list.set(ClipEventFlag::CONSTRUCT, flags & 0b0000_0100 != 0); event_list.set(ClipEventFlag::CONSTRUCT, flags2 & 0b0000_0100 != 0);
event_list.set(ClipEventFlag::KEY_PRESS, flags & 0b0000_0010 != 0); event_list.set(ClipEventFlag::KEY_PRESS, flags2 & 0b0000_0010 != 0);
event_list.set(ClipEventFlag::DRAG_OUT, flags & 0b0000_0001 != 0); event_list.set(ClipEventFlag::DRAG_OUT, flags2 & 0b0000_0001 != 0);
self.read_u8()?;
} else { } else {
// SWF19 pp. 48-50: For SWFv5, the ClipEventFlags only had 2 bytes of flags, // SWF19 pp. 48-50: For SWFv5, the ClipEventFlags only had 2 bytes of flags,
// with the 2nd byte reserved (all 0). // with the 2nd byte reserved (all 0).