Skip to content

Commit 5b80c1b

Browse files
Audit Fixes #1 (#1293)
* address runtime panics * default pubkey not allowed as admin * add checks for ownership * fix typo * standardize data.len check * linting * update transfer conditions * lint --------- Co-authored-by: Vladimir <[email protected]>
1 parent 1456366 commit 5b80c1b

File tree

6 files changed

+55
-8
lines changed

6 files changed

+55
-8
lines changed

contracts/programs/data-feeds-cache/src/error.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,7 @@ pub enum DataCacheError {
7272

7373
#[msg("failed legacy write")]
7474
FailedLegacyWrite,
75+
76+
#[msg("Invalid proposed owner")]
77+
InvalidProposedOwner,
7578
}

contracts/programs/data-feeds-cache/src/lib.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ pub mod data_feeds_cache {
7171
}
7272

7373
pub fn set_feed_admin(ctx: Context<SetFeedAdmin>, admin: Pubkey, is_admin: bool) -> Result<()> {
74+
require_keys_neq!(admin, Pubkey::default(), DataCacheError::InvalidAddress);
75+
7476
let mut state = ctx.accounts.state.load_mut()?;
7577
let mut changed = false;
7678

@@ -101,8 +103,14 @@ pub mod data_feeds_cache {
101103
proposed_owner: Pubkey,
102104
) -> Result<()> {
103105
let state = &mut ctx.accounts.state.load_mut()?;
104-
state.proposed_owner = proposed_owner;
106+
require!(
107+
proposed_owner != Pubkey::default()
108+
&& proposed_owner != state.owner
109+
&& proposed_owner != state.proposed_owner,
110+
DataCacheError::InvalidProposedOwner
111+
);
105112

113+
state.proposed_owner = proposed_owner;
106114
emit!(OwnershipTransfer {
107115
current_owner: state.owner,
108116
proposed_owner
@@ -689,6 +697,12 @@ pub mod data_feeds_cache {
689697
delete_permission_accounts.append(&mut temp_candidates_deletion)
690698
}
691699

700+
require_eq!(
701+
delete_permission_accounts.len(),
702+
delete_permission_account_infos.len(),
703+
DataCacheError::ArrayLengthMismatch
704+
);
705+
692706
for (i, permission_account) in delete_permission_accounts.iter().enumerate() {
693707
let curr_permission_account_info = &delete_permission_account_infos[i];
694708

@@ -1047,6 +1061,12 @@ pub mod data_feeds_cache {
10471061
ctx: Context<'_, '_, 'info, 'info, QueryValues<'info>>,
10481062
data_ids: Vec<[u8; 16]>,
10491063
) -> Result<Vec<DecimalReport>> {
1064+
require_eq!(
1065+
data_ids.len(),
1066+
ctx.remaining_accounts.len(),
1067+
DataCacheError::ArrayLengthMismatch
1068+
);
1069+
10501070
let mut reports = Vec::new();
10511071

10521072
for (i, data_id) in data_ids.iter().enumerate() {

contracts/programs/keystone-forwarder/src/context.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
use crate::common::ANCHOR_DISCRIMINATOR;
22
use crate::error::AuthError;
33
use crate::state::{ExecutionState, ForwarderState, OraclesConfig};
4-
use crate::utils::{extract_config_id, extract_raw_report, extract_transmission_id, get_config_id};
4+
use crate::utils::{
5+
extract_config_id, extract_raw_report, extract_transmission_id, get_config_id, report_size_ok,
6+
};
7+
use crate::ForwarderError;
58
use anchor_lang::prelude::*;
69

710
#[derive(Accounts)]
@@ -99,6 +102,7 @@ pub struct Report<'info> {
99102

100103
#[account(
101104
mut,
105+
constraint = report_size_ok(&data) @ ForwarderError::InvalidReport,
102106
seeds = [b"config", state.key().as_ref(), &extract_config_id(extract_raw_report(&data))],
103107
bump
104108
)]
@@ -114,6 +118,7 @@ pub struct Report<'info> {
114118
// it is dependent on the state.key(), a predetermined bump, workflow execution id, config_id, report_id
115119
#[account(
116120
init_if_needed,
121+
constraint = report_size_ok(&data) @ ForwarderError::InvalidReport,
117122
payer = transmitter,
118123
space = ANCHOR_DISCRIMINATOR + ExecutionState::INIT_SPACE,
119124
seeds = [

contracts/programs/keystone-forwarder/src/error.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ pub enum AuthError {
2222

2323
#[error_code]
2424
pub enum ForwarderError {
25+
#[msg("Invalid proposed owner")]
26+
InvalidProposedOwner,
27+
2528
#[msg("Signers exceed max limit")]
2629
ExcessSigners,
2730

contracts/programs/keystone-forwarder/src/lib.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ declare_id!("whV7Q5pi17hPPyaPksToDw1nMx6Lh8qmNWKFaLRQ4wz");
2525
pub mod keystone_forwarder {
2626
use anchor_lang::solana_program::{instruction::Instruction, program::invoke_signed};
2727

28+
use crate::utils::report_size_ok;
29+
2830
use super::*;
2931

3032
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
@@ -52,11 +54,17 @@ pub mod keystone_forwarder {
5254
proposed_owner: Pubkey,
5355
) -> Result<()> {
5456
let state = &mut ctx.accounts.state;
55-
let state_current_owner = state.owner;
57+
require!(
58+
proposed_owner != Pubkey::default()
59+
&& proposed_owner != state.owner
60+
&& proposed_owner != state.proposed_owner,
61+
ForwarderError::InvalidProposedOwner
62+
);
63+
5664
state.proposed_owner = proposed_owner;
5765

5866
emit!(OwnershipTransfer {
59-
current_owner: state_current_owner,
67+
current_owner: state.owner,
6068
proposed_owner: state.proposed_owner
6169
});
6270

@@ -114,10 +122,9 @@ pub mod keystone_forwarder {
114122
ctx: Context<'_, '_, '_, 'info, Report<'info>>,
115123
data: Vec<u8>,
116124
) -> Result<()> {
117-
let num_signatures = data[0] as usize;
118-
let min_data_size = 1 + num_signatures * SIGNATURE_LEN + REPORT_CONTEXT_LEN;
125+
require!(report_size_ok(&data), ForwarderError::InvalidReport);
119126

120-
require_gt!(data.len(), min_data_size, ForwarderError::InvalidReport);
127+
let num_signatures = data[0] as usize;
121128

122129
// get config
123130
let oracles_config = ctx.accounts.oracles_config.load()?;

contracts/programs/keystone-forwarder/src/utils.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
11
use anchor_lang::prelude::Pubkey;
22
use anchor_lang::solana_program::hash;
33

4-
use crate::common::{REPORT_CONTEXT_LEN, SIGNATURE_LEN};
4+
use crate::common::{METADATA_LENGTH, REPORT_CONTEXT_LEN, SIGNATURE_LEN};
55

66
pub fn get_config_id(don_id: u32, config_version: u32) -> u64 {
77
((don_id as u64) << 32) | (config_version as u64)
88
}
99

10+
pub fn report_size_ok(data: &[u8]) -> bool {
11+
if !data.is_empty() {
12+
let num_signatures = data[0] as usize;
13+
data.len() > 1 + num_signatures * SIGNATURE_LEN + METADATA_LENGTH + REPORT_CONTEXT_LEN
14+
} else {
15+
false
16+
}
17+
}
18+
1019
// data = len_signatures (1) | signatures (N*65) | raw_report (M) | report_context (96)
1120
pub fn extract_raw_report(data: &[u8]) -> &[u8] {
1221
let num_signatures = data[0] as usize;

0 commit comments

Comments
 (0)