Skip to content
This repository was archived by the owner on Mar 11, 2025. It is now read-only.

Commit aaabce2

Browse files
authored
token-2022: Return errors for malformed extension data (#3762)
1 parent d331f47 commit aaabce2

File tree

1 file changed

+42
-3
lines changed
  • token/program-2022/src/extension

1 file changed

+42
-3
lines changed

token/program-2022/src/extension/mod.rs

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,20 +133,29 @@ fn get_extension_types(tlv_data: &[u8]) -> Result<Vec<ExtensionType>, ProgramErr
133133
let mut start_index = 0;
134134
while start_index < tlv_data.len() {
135135
let tlv_indices = get_tlv_indices(start_index);
136-
if tlv_data.len() < tlv_indices.value_start {
137-
return Ok(extension_types);
136+
if tlv_data.len() < tlv_indices.length_start {
137+
// not enough bytes to store the type, malformed
138+
return Err(ProgramError::InvalidAccountData);
138139
}
139140
let extension_type =
140141
ExtensionType::try_from(&tlv_data[tlv_indices.type_start..tlv_indices.length_start])?;
141142
if extension_type == ExtensionType::Uninitialized {
142143
return Ok(extension_types);
143144
} else {
145+
if tlv_data.len() < tlv_indices.value_start {
146+
// not enough bytes to store the length, malformed
147+
return Err(ProgramError::InvalidAccountData);
148+
}
144149
extension_types.push(extension_type);
145150
let length = pod_from_bytes::<Length>(
146151
&tlv_data[tlv_indices.length_start..tlv_indices.value_start],
147152
)?;
148153

149154
let value_end_index = tlv_indices.value_start.saturating_add(usize::from(*length));
155+
if value_end_index > tlv_data.len() {
156+
// value blows past the size of the slice, malformed
157+
return Err(ProgramError::InvalidAccountData);
158+
}
150159
start_index = value_end_index;
151160
}
152161
}
@@ -953,6 +962,27 @@ mod test {
953962
);
954963
}
955964

965+
#[test]
966+
fn get_extension_types_with_opaque_buffer() {
967+
// incorrect due to the length
968+
assert_eq!(
969+
get_extension_types(&[1, 0, 1, 1]).unwrap_err(),
970+
ProgramError::InvalidAccountData,
971+
);
972+
// incorrect due to the huge enum number
973+
assert_eq!(
974+
get_extension_types(&[0, 1, 0, 0]).unwrap_err(),
975+
ProgramError::InvalidAccountData,
976+
);
977+
// correct due to the good enum number and zero length
978+
assert_eq!(
979+
get_extension_types(&[1, 0, 0, 0]).unwrap(),
980+
vec![ExtensionType::try_from(1).unwrap()]
981+
);
982+
// correct since it's just uninitialized data at the end
983+
assert_eq!(get_extension_types(&[0, 0]).unwrap(), vec![]);
984+
}
985+
956986
#[test]
957987
fn mint_with_extension_pack_unpack() {
958988
let mint_size = ExtensionType::get_account_len::<Mint>(&[
@@ -1586,12 +1616,21 @@ mod test {
15861616
let err = StateWithExtensionsMut::<Mint>::unpack_uninitialized(&mut buffer).unwrap_err();
15871617
assert_eq!(err, ProgramError::InvalidAccountData);
15881618

1589-
let mut buffer = vec![0; BASE_ACCOUNT_LENGTH + 2];
1619+
// ok since there are two bytes for the type, which is `Uninitialized`
1620+
let mut buffer = vec![0; BASE_ACCOUNT_LENGTH + 3];
15901621
let mut state = StateWithExtensionsMut::<Mint>::unpack_uninitialized(&mut buffer).unwrap();
15911622
let err = state.get_extension_mut::<MintCloseAuthority>().unwrap_err();
15921623
assert_eq!(err, ProgramError::InvalidAccountData);
15931624

15941625
assert_eq!(state.get_extension_types().unwrap(), vec![]);
1626+
1627+
// malformed since there aren't too bytes for the type
1628+
let mut buffer = vec![0; BASE_ACCOUNT_LENGTH + 2];
1629+
let state = StateWithExtensionsMut::<Mint>::unpack_uninitialized(&mut buffer).unwrap();
1630+
assert_eq!(
1631+
state.get_extension_types().unwrap_err(),
1632+
ProgramError::InvalidAccountData
1633+
);
15951634
}
15961635

15971636
#[test]

0 commit comments

Comments
 (0)