diff --git a/programs/bpf_loader/src/serialization.rs b/programs/bpf_loader/src/serialization.rs index f9cbc2e752c54d..de60231759c5e6 100644 --- a/programs/bpf_loader/src/serialization.rs +++ b/programs/bpf_loader/src/serialization.rs @@ -335,8 +335,13 @@ fn serialize_parameters_unaligned( s.write::(account.is_writable() as u8); let vm_key_addr = s.write_all(account.get_key().as_ref()); let vm_lamports_addr = s.write::(account.get_lamports().to_le()); - s.write::((account.get_data().len() as u64).to_le()); - let vm_data_addr = s.write_account(&mut account)?; + let vm_data_addr = if account.is_executable() { + s.write::(0u64.to_le()); + 0 + } else { + s.write::((account.get_data().len() as u64).to_le()); + s.write_account(&mut account)? + }; let vm_owner_addr = s.write_all(account.get_owner().as_ref()); s.write::(account.is_executable() as u8); s.write::((account.get_rent_epoch()).to_le()); @@ -389,7 +394,7 @@ pub fn deserialize_parameters_unaligned>( } start += size_of::() // lamports + size_of::(); // data length - if copy_account_data { + if copy_account_data && !borrowed_account.is_executable() { let data = buffer .get(start..start + pre_len) .ok_or(InstructionError::InvalidArgument)?; @@ -471,8 +476,13 @@ fn serialize_parameters_aligned( let vm_key_addr = s.write_all(borrowed_account.get_key().as_ref()); let vm_owner_addr = s.write_all(borrowed_account.get_owner().as_ref()); let vm_lamports_addr = s.write::(borrowed_account.get_lamports().to_le()); - s.write::((borrowed_account.get_data().len() as u64).to_le()); - let vm_data_addr = s.write_account(&mut borrowed_account)?; + let vm_data_addr = if borrowed_account.is_executable() { + s.write::(0u64.to_le()); + 0 + } else { + s.write::((borrowed_account.get_data().len() as u64).to_le()); + s.write_account(&mut borrowed_account)? + }; s.write::((borrowed_account.get_rent_epoch()).to_le()); accounts_metadata.push(SerializedAccountMetadata { original_data_len: borrowed_account.get_data().len(), @@ -535,11 +545,14 @@ pub fn deserialize_parameters_aligned>( borrowed_account.set_lamports(lamports)?; } start += size_of::(); // lamports - let post_len = LittleEndian::read_u64( + let mut post_len = LittleEndian::read_u64( buffer .get(start..) .ok_or(InstructionError::InvalidArgument)?, ) as usize; + if borrowed_account.is_executable() { + post_len = pre_len; + } start += size_of::(); // data length if post_len.saturating_sub(pre_len) > MAX_PERMITTED_DATA_INCREASE || post_len > MAX_PERMITTED_DATA_LENGTH as usize @@ -549,19 +562,21 @@ pub fn deserialize_parameters_aligned>( // The redundant check helps to avoid the expensive data comparison if we can let alignment_offset = (pre_len as *const u8).align_offset(BPF_ALIGN_OF_U128); if copy_account_data { - let data = buffer - .get(start..start + post_len) - .ok_or(InstructionError::InvalidArgument)?; - match borrowed_account - .can_data_be_resized(post_len) - .and_then(|_| borrowed_account.can_data_be_changed()) - { - Ok(()) => borrowed_account.set_data_from_slice(data)?, - Err(err) if borrowed_account.get_data() != data => return Err(err), - _ => {} + if !borrowed_account.is_executable() { + let data = buffer + .get(start..start + post_len) + .ok_or(InstructionError::InvalidArgument)?; + match borrowed_account + .can_data_be_resized(post_len) + .and_then(|_| borrowed_account.can_data_be_changed()) + { + Ok(()) => borrowed_account.set_data_from_slice(data)?, + Err(err) if borrowed_account.get_data() != data => return Err(err), + _ => {} + } + start += pre_len; // data } - start += pre_len; // data - } else { + } else if !borrowed_account.is_executable() { // See Serializer::write_account() as to why we have this // padding before the realloc region here. start += BPF_ALIGN_OF_U128.saturating_sub(alignment_offset);