mirror of
https://github.com/mimblewimble/grin-wallet.git
synced 2025-02-01 08:51:09 +03:00
Check Slatepack file size before loading contents (#495)
Check Slatepack file size is within valid range before loading contents into memory Co-authored-by: Nym Seddon <unseddd@shh.xyz>
This commit is contained in:
parent
b58322fdda
commit
f29fc9352f
5 changed files with 119 additions and 9 deletions
|
@ -13,11 +13,11 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
/// Slatepack Output 'plugin' implementation
|
/// Slatepack Output 'plugin' implementation
|
||||||
use std::fs::File;
|
use std::fs::{metadata, File};
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::libwallet::{Error, ErrorKind, Slate, Slatepack, SlatepackBin, Slatepacker};
|
use crate::libwallet::{slatepack, Error, ErrorKind, Slate, Slatepack, SlatepackBin, Slatepacker};
|
||||||
use crate::{SlateGetter, SlatePutter};
|
use crate::{SlateGetter, SlatePutter};
|
||||||
use grin_wallet_util::byte_ser;
|
use grin_wallet_util::byte_ser;
|
||||||
|
|
||||||
|
@ -39,6 +39,17 @@ impl<'a> PathToSlatepack<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_slatepack_file_contents(&self) -> Result<Vec<u8>, Error> {
|
pub fn get_slatepack_file_contents(&self) -> Result<Vec<u8>, Error> {
|
||||||
|
let metadata = metadata(&self.pathbuf)?;
|
||||||
|
let len = metadata.len();
|
||||||
|
let min_len = slatepack::min_size();
|
||||||
|
let max_len = slatepack::max_size();
|
||||||
|
if len < min_len || len > max_len {
|
||||||
|
let msg = format!(
|
||||||
|
"Data is invalid length: {} | min: {}, max: {} |",
|
||||||
|
len, min_len, max_len
|
||||||
|
);
|
||||||
|
return Err(ErrorKind::SlatepackDeser(msg).into());
|
||||||
|
}
|
||||||
let mut pub_tx_f = File::open(&self.pathbuf)?;
|
let mut pub_tx_f = File::open(&self.pathbuf)?;
|
||||||
let mut data = Vec::new();
|
let mut data = Vec::new();
|
||||||
pub_tx_f.read_to_end(&mut data)?;
|
pub_tx_f.read_to_end(&mut data)?;
|
||||||
|
@ -84,3 +95,85 @@ impl<'a> SlateGetter for PathToSlatepack<'a> {
|
||||||
Ok((self.packer.get_slate(&slatepack)?, true))
|
Ok((self.packer.get_slate(&slatepack)?, true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
use grin_wallet_util::grin_core::global;
|
||||||
|
|
||||||
|
fn clean_output_dir(test_dir: &str) {
|
||||||
|
let _ = fs::remove_dir_all(test_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup(test_dir: &str) {
|
||||||
|
clean_output_dir(test_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
const SLATEPACK_DIR: &'static str = "target/test_output/slatepack";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pathbuf_get_file_contents() {
|
||||||
|
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
|
||||||
|
setup(SLATEPACK_DIR);
|
||||||
|
|
||||||
|
fs::create_dir_all(SLATEPACK_DIR).unwrap();
|
||||||
|
let sp_path = PathBuf::from(SLATEPACK_DIR).join("pack_file");
|
||||||
|
|
||||||
|
// set Slatepack file to minimum allowable size
|
||||||
|
{
|
||||||
|
let f = File::create(sp_path.clone()).unwrap();
|
||||||
|
f.set_len(slatepack::min_size()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let args = slatepack::SlatepackerArgs {
|
||||||
|
sender: None,
|
||||||
|
recipients: vec![],
|
||||||
|
dec_key: None,
|
||||||
|
};
|
||||||
|
let packer = Slatepacker::new(args);
|
||||||
|
|
||||||
|
let mut pack_path = PathToSlatepack::new(sp_path.clone(), &packer, true);
|
||||||
|
assert!(pack_path.get_slatepack_file_contents().is_ok());
|
||||||
|
|
||||||
|
pack_path = PathToSlatepack::new(sp_path.clone(), &packer, false);
|
||||||
|
assert!(pack_path.get_slatepack_file_contents().is_ok());
|
||||||
|
|
||||||
|
// set Slatepack file to maximum allowable size
|
||||||
|
{
|
||||||
|
let f = File::create(sp_path.clone()).unwrap();
|
||||||
|
f.set_len(slatepack::max_size()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pack_path = PathToSlatepack::new(sp_path.clone(), &packer, true);
|
||||||
|
assert!(pack_path.get_slatepack_file_contents().is_ok());
|
||||||
|
|
||||||
|
pack_path = PathToSlatepack::new(sp_path.clone(), &packer, false);
|
||||||
|
assert!(pack_path.get_slatepack_file_contents().is_ok());
|
||||||
|
|
||||||
|
// set Slatepack file below minimum allowable size
|
||||||
|
{
|
||||||
|
let f = File::create(sp_path.clone()).unwrap();
|
||||||
|
f.set_len(slatepack::min_size() - 1).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pack_path = PathToSlatepack::new(sp_path.clone(), &packer, true);
|
||||||
|
assert!(pack_path.get_slatepack_file_contents().is_err());
|
||||||
|
|
||||||
|
pack_path = PathToSlatepack::new(sp_path.clone(), &packer, false);
|
||||||
|
assert!(pack_path.get_slatepack_file_contents().is_err());
|
||||||
|
|
||||||
|
// set Slatepack file above maximum allowable size
|
||||||
|
{
|
||||||
|
let f = File::create(sp_path.clone()).unwrap();
|
||||||
|
f.set_len(slatepack::max_size() + 1).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pack_path = PathToSlatepack::new(sp_path.clone(), &packer, true);
|
||||||
|
assert!(pack_path.get_slatepack_file_contents().is_err());
|
||||||
|
|
||||||
|
pack_path = PathToSlatepack::new(sp_path.clone(), &packer, false);
|
||||||
|
assert!(pack_path.get_slatepack_file_contents().is_err());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ mod error;
|
||||||
mod internal;
|
mod internal;
|
||||||
mod slate;
|
mod slate;
|
||||||
pub mod slate_versions;
|
pub mod slate_versions;
|
||||||
mod slatepack;
|
pub mod slatepack;
|
||||||
mod types;
|
mod types;
|
||||||
|
|
||||||
pub use crate::error::{Error, ErrorKind};
|
pub use crate::error::{Error, ErrorKind};
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
// Finally add armor framing and space/newline formatting as desired
|
// Finally add armor framing and space/newline formatting as desired
|
||||||
|
|
||||||
use crate::{Error, ErrorKind};
|
use crate::{Error, ErrorKind};
|
||||||
use grin_wallet_util::byte_ser;
|
use grin_wallet_util::{byte_ser, grin_core::global::max_tx_weight};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest, Sha256};
|
||||||
use std::str;
|
use std::str;
|
||||||
|
@ -33,6 +33,20 @@ pub static HEADER: &str = "BEGINSLATEPACK.";
|
||||||
static FOOTER: &str = ". ENDSLATEPACK.";
|
static FOOTER: &str = ". ENDSLATEPACK.";
|
||||||
const WORD_LENGTH: usize = 15;
|
const WORD_LENGTH: usize = 15;
|
||||||
const WORDS_PER_LINE: usize = 200;
|
const WORDS_PER_LINE: usize = 200;
|
||||||
|
const WEIGHT_RATIO: u64 = 32;
|
||||||
|
|
||||||
|
/// Maximum size for an armored Slatepack file
|
||||||
|
pub fn max_size() -> u64 {
|
||||||
|
max_tx_weight()
|
||||||
|
.saturating_mul(WEIGHT_RATIO)
|
||||||
|
.saturating_add(HEADER.len() as u64)
|
||||||
|
.saturating_add(FOOTER.len() as u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Minimum size for an armored Slatepack file or stream
|
||||||
|
pub fn min_size() -> u64 {
|
||||||
|
HEADER.len() as u64
|
||||||
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref HEADER_REGEX: Regex =
|
static ref HEADER_REGEX: Regex =
|
||||||
|
|
|
@ -12,12 +12,14 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
//! Functions and types for handling Slatepack transactions
|
||||||
|
|
||||||
mod address;
|
mod address;
|
||||||
mod armor;
|
mod armor;
|
||||||
mod packer;
|
mod packer;
|
||||||
mod types;
|
mod types;
|
||||||
|
|
||||||
pub use self::address::SlatepackAddress;
|
pub use self::address::SlatepackAddress;
|
||||||
pub use self::armor::SlatepackArmor;
|
pub use self::armor::{max_size, min_size, SlatepackArmor};
|
||||||
pub use self::packer::{Slatepacker, SlatepackerArgs};
|
pub use self::packer::{Slatepacker, SlatepackerArgs};
|
||||||
pub use self::types::{Slatepack, SlatepackBin};
|
pub use self::types::{Slatepack, SlatepackBin};
|
||||||
|
|
|
@ -16,11 +16,11 @@ use std::convert::TryFrom;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
use super::armor::HEADER;
|
use super::armor::HEADER;
|
||||||
use crate::{Error, ErrorKind};
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Slate, SlateVersion, Slatepack, SlatepackAddress, SlatepackArmor, SlatepackBin,
|
slatepack, Slate, SlateVersion, Slatepack, SlatepackAddress, SlatepackArmor, SlatepackBin,
|
||||||
VersionedBinSlate, VersionedSlate,
|
VersionedBinSlate, VersionedSlate,
|
||||||
};
|
};
|
||||||
|
use crate::{Error, ErrorKind};
|
||||||
|
|
||||||
use grin_wallet_util::byte_ser;
|
use grin_wallet_util::byte_ser;
|
||||||
|
|
||||||
|
@ -50,8 +50,9 @@ impl<'a> Slatepacker<'a> {
|
||||||
/// return slatepack
|
/// return slatepack
|
||||||
pub fn deser_slatepack(&self, data: &[u8], decrypt: bool) -> Result<Slatepack, Error> {
|
pub fn deser_slatepack(&self, data: &[u8], decrypt: bool) -> Result<Slatepack, Error> {
|
||||||
// check if data is armored, if so, remove and continue
|
// check if data is armored, if so, remove and continue
|
||||||
if data.len() < super::armor::HEADER.len() {
|
let data_len = data.len() as u64;
|
||||||
let msg = format!("Data too short");
|
if data_len < slatepack::min_size() || data_len > slatepack::max_size() {
|
||||||
|
let msg = format!("Data invalid length");
|
||||||
return Err(ErrorKind::SlatepackDeser(msg).into());
|
return Err(ErrorKind::SlatepackDeser(msg).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue