@@ -12,21 +12,43 @@ use {
1212 std:: collections:: BTreeSet ,
1313} ;
1414
15- // [Core BPF]: Locally-implemented
16- // `solana_sdk::program_utils::limited_deserialize`.
17- fn limited_deserialize < T > ( input : & [ u8 ] ) -> Result < T , ProgramError >
18- where
19- T : serde:: de:: DeserializeOwned ,
20- {
21- solana_program:: program_utils:: limited_deserialize (
22- input, 1232 , // [Core BPF]: See `solana_sdk::packet::PACKET_DATA_SIZE`
23- )
24- . map_err ( |_| ProgramError :: InvalidInstructionData )
15+ // [Core BPF]: The original Config builtin leverages the
16+ // `solana_sdk::program_utils::limited_deserialize` method to cap the length of
17+ // the input buffer at 1232 (`solana_sdk::packet::PACKET_DATA_SIZE`). As a
18+ // result, any input buffer larger than 1232 will abort deserialization and
19+ // return `InstructionError::InvalidInstructionData`.
20+ //
21+ // Howevever, since `ConfigKeys` contains a vector of `(Pubkey, bool)`, the
22+ // `limited_deserialize` method will still read the vector's length and attempt
23+ // to allocate a vector of the designated size. For extremely large length
24+ // values, this can cause the initial allocation of a large vector to exhuast
25+ // the BPF program's heap before deserialization can proceed.
26+ //
27+ // To mitigate this memory issue, the BPF version of the Config program has
28+ // been designed to "peek" the length value, and ensure it cannot allocate a
29+ // vector that would otherwise violate the input buffer length restriction of
30+ // 1232.
31+ //
32+ // Taking the maximum input length of 1232 and subtracting (up to) 3 bytes for
33+ // the `ShortU16`, then dividing that by the size of a `(Pubkey, bool)` entry
34+ // (33), we get a maximum vector size of 37. A `ShortU16` value for 37 fits in
35+ // just one byte (`[0x25]`), so this function can simply check the first
36+ // provided byte.
37+ fn safe_deserialize_config_keys ( input : & [ u8 ] ) -> Result < ConfigKeys , ProgramError > {
38+ match input. first ( ) {
39+ Some ( first_byte) if * first_byte <= 0x25 => {
40+ solana_program:: program_utils:: limited_deserialize :: < ConfigKeys > (
41+ input, 1232 , // [Core BPF]: See `solana_sdk::packet::PACKET_DATA_SIZE`
42+ )
43+ . map_err ( |_| ProgramError :: InvalidInstructionData )
44+ }
45+ _ => Err ( ProgramError :: InvalidInstructionData ) ,
46+ }
2547}
2648
2749/// Config program processor.
2850pub fn process ( program_id : & Pubkey , accounts : & [ AccountInfo ] , input : & [ u8 ] ) -> ProgramResult {
29- let key_list: ConfigKeys = limited_deserialize ( input) ?;
51+ let key_list = safe_deserialize_config_keys ( input) ?;
3052
3153 let mut accounts_iter = accounts. iter ( ) ;
3254 let config_account = next_account_info ( & mut accounts_iter) ?;
0 commit comments