Fail secp256k1 if the instruction data looks incorrect (#19300)

This commit is contained in:
Jack May
2021-08-19 13:13:54 -07:00
committed by GitHub
parent f59a55be17
commit 3ec33e7d02
9 changed files with 74 additions and 12 deletions

View File

@ -199,6 +199,10 @@ pub mod versioned_tx_message_enabled {
solana_sdk::declare_id!("3KZZ6Ks1885aGBQ45fwRcPXVBCtzUvxhUTkwKMR41Tca");
}
pub mod libsecp256k1_fail_on_bad_count {
solana_sdk::declare_id!("8aXvSuopd1PUj7UhehfXJRg6619RHp8ZvwTyyJHdUYsj");
}
lazy_static! {
/// Map of feature identifiers to user-visible description
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
@ -243,6 +247,7 @@ lazy_static! {
(gate_large_block::id(), "validator checks block cost against max limit in realtime, reject if exceeds."),
(mem_overlap_fix::id(), "memory overlap fix"),
(versioned_tx_message_enabled::id(), "enable versioned transaction message processing"),
(libsecp256k1_fail_on_bad_count::id(), "Fail libsec256k1_verify if count appears wrong")
/*************** ADD NEW FEATURES HERE ***************/
]
.iter()

View File

@ -103,11 +103,18 @@ pub fn verify_eth_addresses(
data: &[u8],
instruction_datas: &[&[u8]],
libsecp256k1_0_5_upgrade_enabled: bool,
libsecp256k1_fail_on_bad_count: bool,
) -> Result<(), Secp256k1Error> {
if data.is_empty() {
return Err(Secp256k1Error::InvalidInstructionDataSize);
}
let count = data[0] as usize;
if libsecp256k1_fail_on_bad_count && count == 0 && data.len() > 1 {
// count is zero but the instruction data indicates that is probably not
// correct, fail the instruction to catch probable invalid secp256k1
// instruction construction.
return Err(Secp256k1Error::InvalidInstructionDataSize);
}
let expected_data_size = count
.saturating_mul(SIGNATURE_OFFSETS_SERIALIZED_SIZE)
.saturating_add(1);
@ -215,7 +222,7 @@ pub mod test {
let writer = std::io::Cursor::new(&mut instruction_data[1..]);
bincode::serialize_into(writer, &offsets).unwrap();
verify_eth_addresses(&instruction_data, &[&[0u8; 100]], false)
verify_eth_addresses(&instruction_data, &[&[0u8; 100]], false, true)
}
#[test]
@ -230,7 +237,7 @@ pub mod test {
instruction_data.truncate(instruction_data.len() - 1);
assert_eq!(
verify_eth_addresses(&instruction_data, &[&[0u8; 100]], false),
verify_eth_addresses(&instruction_data, &[&[0u8; 100]], false, true),
Err(Secp256k1Error::InvalidInstructionDataSize)
);
@ -346,4 +353,19 @@ pub mod test {
Err(Secp256k1Error::InvalidSignature)
);
}
#[test]
fn test_count_is_zero_but_sig_data_exists() {
solana_logger::setup();
let mut instruction_data = vec![0u8; DATA_START];
let offsets = SecpSignatureOffsets::default();
instruction_data[0] = 0;
let writer = std::io::Cursor::new(&mut instruction_data[1..]);
bincode::serialize_into(writer, &offsets).unwrap();
assert_eq!(
verify_eth_addresses(&instruction_data, &[&[0u8; 100]], false, true),
Err(Secp256k1Error::InvalidInstructionDataSize)
);
}
}

View File

@ -426,7 +426,11 @@ impl Transaction {
.collect()
}
pub fn verify_precompiles(&self, libsecp256k1_0_5_upgrade_enabled: bool) -> Result<()> {
pub fn verify_precompiles(
&self,
libsecp256k1_0_5_upgrade_enabled: bool,
libsecp256k1_fail_on_bad_count: bool,
) -> Result<()> {
for instruction in &self.message().instructions {
// The Transaction may not be sanitized at this point
if instruction.program_id_index as usize >= self.message().account_keys.len() {
@ -445,6 +449,7 @@ impl Transaction {
data,
&instruction_datas,
libsecp256k1_0_5_upgrade_enabled,
libsecp256k1_fail_on_bad_count,
);
e.map_err(|_| TransactionError::InvalidAccountIndex)?;
}

View File

@ -203,7 +203,11 @@ impl SanitizedTransaction {
}
/// Verify the encoded secp256k1 signatures in this transaction
pub fn verify_precompiles(&self, libsecp256k1_0_5_upgrade_enabled: bool) -> Result<()> {
pub fn verify_precompiles(
&self,
libsecp256k1_0_5_upgrade_enabled: bool,
libsecp256k1_fail_on_bad_count: bool,
) -> Result<()> {
for (program_id, instruction) in self.message.program_instructions_iter() {
if secp256k1_program::check_id(program_id) {
let instruction_datas: Vec<_> = self
@ -217,6 +221,7 @@ impl SanitizedTransaction {
data,
&instruction_datas,
libsecp256k1_0_5_upgrade_enabled,
libsecp256k1_fail_on_bad_count,
);
e.map_err(|_| TransactionError::InvalidAccountIndex)?;
}