RPC: Limit getProgramAccounts memcpy filter string to 128 bytes (bp #15483) (#15490)

* Limit getProgramAccounts memcpy filter string to 128 bytes

(cherry picked from commit 65f1afe5e1)

* Limit the number of getProgramAccounts filters

(cherry picked from commit 4b0114b991)

Co-authored-by: Michael Vines <mvines@gmail.com>
This commit is contained in:
mergify[bot]
2021-02-23 19:57:46 +00:00
committed by GitHub
parent e5bb1597a4
commit e255c85bef
4 changed files with 56 additions and 10 deletions

View File

@ -16,10 +16,15 @@ impl RpcFilterType {
match encoding { match encoding {
MemcmpEncoding::Binary => { MemcmpEncoding::Binary => {
let MemcmpEncodedBytes::Binary(bytes) = &compare.bytes; let MemcmpEncodedBytes::Binary(bytes) = &compare.bytes;
bs58::decode(&bytes)
.into_vec() if bytes.len() > 128 {
.map(|_| ()) Err(RpcFilterError::Base58DataTooLarge)
.map_err(|e| e.into()) } else {
bs58::decode(&bytes)
.into_vec()
.map(|_| ())
.map_err(|e| e.into())
}
} }
} }
} }
@ -27,10 +32,12 @@ impl RpcFilterType {
} }
} }
#[derive(Error, Debug)] #[derive(Error, PartialEq, Debug)]
pub enum RpcFilterError { pub enum RpcFilterError {
#[error("bs58 decode error")] #[error("bs58 decode error")]
DecodeError(#[from] bs58::decode::Error), DecodeError(#[from] bs58::decode::Error),
#[error("encoded binary (base 58) data should be less than 129 bytes")]
Base58DataTooLarge,
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
@ -140,4 +147,36 @@ mod tests {
} }
.bytes_match(&data)); .bytes_match(&data));
} }
#[test]
fn test_verify_memcmp() {
let base58_bytes = "\
1111111111111111111111111111111111111111111111111111111111111111\
1111111111111111111111111111111111111111111111111111111111111111";
assert_eq!(base58_bytes.len(), 128);
assert_eq!(
RpcFilterType::Memcmp(Memcmp {
offset: 0,
bytes: MemcmpEncodedBytes::Binary(base58_bytes.to_string()),
encoding: None,
})
.verify(),
Ok(())
);
let base58_bytes = "\
1111111111111111111111111111111111111111111111111111111111111111\
1111111111111111111111111111111111111111111111111111111111111111\
1";
assert_eq!(base58_bytes.len(), 129);
assert_eq!(
RpcFilterType::Memcmp(Memcmp {
offset: 0,
bytes: MemcmpEncodedBytes::Binary(base58_bytes.to_string()),
encoding: None,
})
.verify(),
Err(RpcFilterError::Base58DataTooLarge)
);
}
} }

View File

@ -127,6 +127,7 @@ pub const MAX_GET_CONFIRMED_BLOCKS_RANGE: u64 = 500_000;
pub const MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS2_LIMIT: usize = 1_000; pub const MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS2_LIMIT: usize = 1_000;
pub const MAX_MULTIPLE_ACCOUNTS: usize = 100; pub const MAX_MULTIPLE_ACCOUNTS: usize = 100;
pub const NUM_LARGEST_ACCOUNTS: usize = 20; pub const NUM_LARGEST_ACCOUNTS: usize = 20;
pub const MAX_GET_PROGRAM_ACCOUNT_FILTERS: usize = 4;
// Validators that are this number of slots behind are considered delinquent // Validators that are this number of slots behind are considered delinquent
pub const DELINQUENT_VALIDATOR_SLOT_DISTANCE: u64 = 128; pub const DELINQUENT_VALIDATOR_SLOT_DISTANCE: u64 = 128;

View File

@ -28,7 +28,7 @@ use solana_client::{
rpc_request::{ rpc_request::{
TokenAccountsFilter, DELINQUENT_VALIDATOR_SLOT_DISTANCE, MAX_GET_CONFIRMED_BLOCKS_RANGE, TokenAccountsFilter, DELINQUENT_VALIDATOR_SLOT_DISTANCE, MAX_GET_CONFIRMED_BLOCKS_RANGE,
MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS2_LIMIT, MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS2_LIMIT,
MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE, MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE, MAX_GET_PROGRAM_ACCOUNT_FILTERS,
MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS, MAX_MULTIPLE_ACCOUNTS, NUM_LARGEST_ACCOUNTS, MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS, MAX_MULTIPLE_ACCOUNTS, NUM_LARGEST_ACCOUNTS,
}, },
rpc_response::Response as RpcResponse, rpc_response::Response as RpcResponse,
@ -2223,6 +2223,12 @@ impl RpcSol for RpcSolImpl {
} else { } else {
(None, vec![]) (None, vec![])
}; };
if filters.len() > MAX_GET_PROGRAM_ACCOUNT_FILTERS {
return Err(Error::invalid_params(format!(
"Too many filters provided; max {}",
MAX_GET_PROGRAM_ACCOUNT_FILTERS
)));
}
for filter in &filters { for filter in &filters {
verify_filter(filter)?; verify_filter(filter)?;
} }

View File

@ -207,7 +207,7 @@ Returns all information associated with the account of provided Pubkey
fields: fields:
- (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment) - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
- `encoding: <string>` - encoding for Account data, either "base58" (*slow*), "base64", "base64+zstd", or "jsonParsed". - `encoding: <string>` - encoding for Account data, either "base58" (*slow*), "base64", "base64+zstd", or "jsonParsed".
"base58" is limited to Account data of less than 128 bytes. "base58" is limited to Account data of less than 129 bytes.
"base64" will return base64 encoded data for Account data of any size. "base64" will return base64 encoded data for Account data of any size.
"base64+zstd" compresses the Account data using [Zstandard](https://facebook.github.io/zstd/) and base64-encodes the result. "base64+zstd" compresses the Account data using [Zstandard](https://facebook.github.io/zstd/) and base64-encodes the result.
"jsonParsed" encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If "jsonParsed" is requested but a parser cannot be found, the field falls back to "base64" encoding, detectable when the `data` field is type `<string>`. "jsonParsed" encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If "jsonParsed" is requested but a parser cannot be found, the field falls back to "base64" encoding, detectable when the `data` field is type `<string>`.
@ -1649,7 +1649,7 @@ Returns the account information for a list of Pubkeys
- `<object>` - (optional) Configuration object containing the following optional fields: - `<object>` - (optional) Configuration object containing the following optional fields:
- (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment) - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
- `encoding: <string>` - encoding for Account data, either "base58" (*slow*), "base64", "base64+zstd", or "jsonParsed". - `encoding: <string>` - encoding for Account data, either "base58" (*slow*), "base64", "base64+zstd", or "jsonParsed".
"base58" is limited to Account data of less than 128 bytes. "base58" is limited to Account data of less than 129 bytes.
"base64" will return base64 encoded data for Account data of any size. "base64" will return base64 encoded data for Account data of any size.
"base64+zstd" compresses the Account data using [Zstandard](https://facebook.github.io/zstd/) and base64-encodes the result. "base64+zstd" compresses the Account data using [Zstandard](https://facebook.github.io/zstd/) and base64-encodes the result.
"jsonParsed" encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If "jsonParsed" is requested but a parser cannot be found, the field falls back to "base64" encoding, detectable when the `data` field is type `<string>`. "jsonParsed" encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If "jsonParsed" is requested but a parser cannot be found, the field falls back to "base64" encoding, detectable when the `data` field is type `<string>`.
@ -1796,7 +1796,7 @@ Returns all accounts owned by the provided program Pubkey
- `<object>` - (optional) Configuration object containing the following optional fields: - `<object>` - (optional) Configuration object containing the following optional fields:
- (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment) - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
- `encoding: <string>` - encoding for Account data, either "base58" (*slow*), "base64", "base64+zstd", or "jsonParsed". - `encoding: <string>` - encoding for Account data, either "base58" (*slow*), "base64", "base64+zstd", or "jsonParsed".
"base58" is limited to Account data of less than 128 bytes. "base58" is limited to Account data of less than 129 bytes.
"base64" will return base64 encoded data for Account data of any size. "base64" will return base64 encoded data for Account data of any size.
"base64+zstd" compresses the Account data using [Zstandard](https://facebook.github.io/zstd/) and base64-encodes the result. "base64+zstd" compresses the Account data using [Zstandard](https://facebook.github.io/zstd/) and base64-encodes the result.
"jsonParsed" encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If "jsonParsed" is requested but a parser cannot be found, the field falls back to "base64" encoding, detectable when the `data` field is type `<string>`. "jsonParsed" encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If "jsonParsed" is requested but a parser cannot be found, the field falls back to "base64" encoding, detectable when the `data` field is type `<string>`.
@ -1806,7 +1806,7 @@ Returns all accounts owned by the provided program Pubkey
##### Filters: ##### Filters:
- `memcmp: <object>` - compares a provided series of bytes with program account data at a particular offset. Fields: - `memcmp: <object>` - compares a provided series of bytes with program account data at a particular offset. Fields:
- `offset: <usize>` - offset into program account data to start comparison - `offset: <usize>` - offset into program account data to start comparison
- `bytes: <string>` - data to match, as base-58 encoded string - `bytes: <string>` - data to match, as base-58 encoded string and limited to less than 129 bytes
- `dataSize: <u64>` - compares the program account data length with the provided data size - `dataSize: <u64>` - compares the program account data length with the provided data size