Skip to content

Commit 65d8446

Browse files
gr4yha7rnbguy
andauthored
fix(ibc-clients/tendermint): disallow empty proof-specs and empty depth range in proof-specs (#1104)
* fix: disallow empty proof-specs and empty depth range in proof-specs * chore: add changelog entry * nits * test: add unit test * chore: use default option (none) * avoid new var * nit in changelog * rm redundant clone * propagate errors * proof depth is unsigned * use impl method --------- Co-authored-by: Ranadeep Biswas <mail@rnbguy.at> Co-authored-by: Rano | Ranadeep <ranadeep@informal.systems>
1 parent 6dd3c64 commit 65d8446

File tree

5 files changed

+52
-7
lines changed

5 files changed

+52
-7
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
- [ibc-client-tendermint-types] Check ics23 proof specs for empty depth range.
2+
([\#1100](https://github.com/cosmos/ibc-rs/issues/1100))

ibc-clients/ics07-tendermint/types/src/client_state.rs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -176,12 +176,8 @@ impl ClientState {
176176
});
177177
}
178178

179-
// Disallow empty proof-specs
180-
if self.proof_specs.is_empty() {
181-
return Err(Error::Validation {
182-
reason: "ClientState proof-specs cannot be empty".to_string(),
183-
});
184-
}
179+
// Sanity checks on client proof specs
180+
self.proof_specs.validate()?;
185181

186182
// `upgrade_path` itself may be empty, but if not then each key must be non-empty
187183
for (idx, key) in self.upgrade_path.iter().enumerate() {
@@ -565,7 +561,21 @@ mod tests {
565561
Test {
566562
name: "Invalid (empty) proof specs".to_string(),
567563
params: ClientStateParams {
568-
proof_specs: ProofSpecs::from(Vec::<Ics23ProofSpec>::new()),
564+
proof_specs: Vec::<Ics23ProofSpec>::new().into(),
565+
..default_params.clone()
566+
},
567+
want_pass: false,
568+
},
569+
Test {
570+
name: "Invalid (empty) proof specs depth range".to_string(),
571+
params: ClientStateParams {
572+
proof_specs: vec![Ics23ProofSpec {
573+
leaf_spec: None,
574+
inner_spec: None,
575+
min_depth: 2,
576+
max_depth: 1,
577+
prehash_key_before_comparison: false,
578+
}].into(),
569579
..default_params
570580
},
571581
want_pass: false,

ibc-clients/ics07-tendermint/types/src/error.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use core::time::Duration;
55
use displaydoc::Display;
66
use ibc_core_client_types::error::ClientError;
77
use ibc_core_client_types::Height;
8+
use ibc_core_commitment_types::error::CommitmentError;
89
use ibc_core_host_types::error::IdentifierError;
910
use ibc_core_host_types::identifiers::ClientId;
1011
use ibc_primitives::prelude::*;
@@ -35,6 +36,8 @@ pub enum Error {
3536
MissingSignedHeader,
3637
/// invalid header, failed basic validation: `{reason}`
3738
Validation { reason: String },
39+
/// invalid client proof specs: `{0}`
40+
InvalidProofSpec(CommitmentError),
3841
/// invalid raw client state: `{reason}`
3942
InvalidRawClientState { reason: String },
4043
/// missing validator set
@@ -119,6 +122,12 @@ impl From<IdentifierError> for Error {
119122
}
120123
}
121124

125+
impl From<CommitmentError> for Error {
126+
fn from(e: CommitmentError) -> Self {
127+
Self::InvalidProofSpec(e)
128+
}
129+
}
130+
122131
pub trait IntoResult<T, E> {
123132
fn into_result(self) -> Result<T, E>;
124133
}

ibc-core/ics23-commitment/types/src/error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ pub enum CommitmentError {
1313
EmptyMerkleRoot,
1414
/// empty verified value
1515
EmptyVerifiedValue,
16+
/// empty proof specs
17+
EmptyProofSpecs,
18+
/// invalid depth range: [{0}, {1}]
19+
InvalidDepthRange(i32, i32),
1620
/// mismatch between the number of proofs with that of specs
1721
NumberOfSpecsMismatch,
1822
/// mismatch between the number of proofs with that of keys

ibc-core/ics23-commitment/types/src/specs.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
33
use ibc_primitives::prelude::*;
44
use ibc_proto::ics23::{InnerSpec as RawInnerSpec, LeafOp as RawLeafOp, ProofSpec as RawProofSpec};
5+
6+
use crate::error::CommitmentError;
57
/// An array of proof specifications.
68
///
79
/// This type encapsulates different types of proof specifications, mostly predefined, e.g., for
@@ -23,6 +25,24 @@ impl ProofSpecs {
2325
pub fn is_empty(&self) -> bool {
2426
self.0.is_empty()
2527
}
28+
29+
pub fn validate(&self) -> Result<(), CommitmentError> {
30+
if self.is_empty() {
31+
return Err(CommitmentError::EmptyProofSpecs);
32+
}
33+
for proof_spec in &self.0 {
34+
if proof_spec.0.max_depth < proof_spec.0.min_depth
35+
|| proof_spec.0.min_depth < 0
36+
|| proof_spec.0.max_depth < 0
37+
{
38+
return Err(CommitmentError::InvalidDepthRange(
39+
proof_spec.0.min_depth,
40+
proof_spec.0.max_depth,
41+
));
42+
}
43+
}
44+
Ok(())
45+
}
2646
}
2747

2848
impl Default for ProofSpecs {

0 commit comments

Comments
 (0)