Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

Sanitize AppendVec's file_size #7373

Merged
merged 11 commits into from
Jan 6, 2020

Conversation

ryoqun
Copy link
Contributor

@ryoqun ryoqun commented Dec 9, 2019

Problem

Creation and restoration of AppendVec is not secure with regard to size of mmap.
Currently, validators can easily be panic!-ed just by putting empty (0-sized) appendvec file or very large sparse appendvec file. The former is forbidden by the specs of mmap and the later will cause panics depending on system configuration/load.

Summary of Changes

  • cap the maximum mmaped appendvec size to 16GiB. This effectively limits the maximum account data size to roughly 8GiB (half of 16GB according to current AppendVec capacity reservation policy) with plenty of margin to the hotly debated limit on the individual account sizes (ref: put limit on account data length #7320).
  • minor runtime behavior change and code cleanup along wide the above.

Part of #7167

@@ -21,6 +21,8 @@ macro_rules! align_up {
};
}

const MAXIMUM_APPEND_VEC_FILE_SIZE: usize = 16 * 1024 * 1024 * 1024; // 16 GiB
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be much lower considering it seems AccountsDB never increases its .file_size from DEFAULT_FILE_SIZE.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't increase, it may allocate a larger one than default if the store account is larger than the default file size.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for confirmation, then maybe we could lower to be close in relation to #7320.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now, I think this is fine as it is now because we can assume the running system will have at least 16GB RAM as per the doc and we can be relieved we'll never be tripped by the limit at that high number depending on current AccountDB's behavior and its possible future changes.

Or, could this be lower, say, a half?: 8GB

runtime/src/append_vec.rs Outdated Show resolved Hide resolved
fn visit_bytes<E>(self, data: &[u8]) -> std::result::Result<Self::Value, E>
where
E: serde::de::Error,
{
use serde::de::Error;
let mut rd = Cursor::new(&data[..]);
let current_len: usize = deserialize_from(&mut rd).map_err(Error::custom)?;
let map = MmapMut::map_anon(1).map_err(|e| Error::custom(e.to_string()))?;
Ok(AppendVec {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved this logic to newly created fn new_empty_map. I can't live with this code. ;)

map,
append_offset: Mutex::new(current_len),
current_len: AtomicUsize::new(current_len),
file_size: current_len as u64,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NOTE: I changed this behavior because this looked just a wrong thing. New code started to initialize this correctly with actual file size.

Or is this intentional to make appencvecs read-only?

@@ -451,6 +490,47 @@ pub mod tests {
}
}

#[test]
#[should_panic(expected = "too small file size 0 for AppendVec")]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know those should_panics are rather ugly. I'll brush up once this PR's direction is affirmed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other uses are fixed by now. Only this will remain as this is testing a panic from ::new().

fn sanitize_mmap_size(size: usize) -> io::Result<()> {
if size == 0 {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know these Errors are not welcomed as explicitly mentioned by #6446.

@ryoqun ryoqun changed the title [wip] Sanitize append vec offset [wip] Sanitize AppendVec's file_size Dec 9, 2019
@@ -174,14 +208,27 @@ impl AppendVec {

#[allow(clippy::mutex_atomic)]
pub fn set_file<P: AsRef<Path>>(&mut self, path: P) -> io::Result<()> {
self.path = path.as_ref().to_path_buf();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only update self.path in an atomic way if everything went successful here.

let map = unsafe { MmapMut::map_mut(&data)? };

self.file_size = file_size;
Copy link
Contributor Author

@ryoqun ryoqun Dec 9, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update file_size correctly, will be used later PRs to check the sum of contained accounts doesn't exceed this and moreover exactly matches to the current_len.

Copy link
Contributor Author

@ryoqun ryoqun Dec 19, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update file_size correctly, will be used later PRs to check the sum of contained acconts doesn't exceed this and moreover exactly matches to the current_len.

As promised by 2 weeks ago's myself, this is done by this and this.

@codecov
Copy link

codecov bot commented Dec 9, 2019

Codecov Report

Merging #7373 into master will decrease coverage by 9.8%.
The diff coverage is 64.4%.

@@           Coverage Diff            @@
##           master   #7373     +/-   ##
========================================
- Coverage    68.7%   58.9%   -9.9%     
========================================
  Files         244     244             
  Lines       56028   64972   +8944     
========================================
- Hits        38530   38309    -221     
- Misses      17498   26663   +9165

@@ -96,6 +98,8 @@ impl AppendVec {
}
}

AppendVec::sanitize_mmap_size(size).unwrap();
Copy link
Contributor Author

@ryoqun ryoqun Dec 9, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, unwrap()ing here just because considering this is under the supertubes milestone and there isn't enough time to do large refactoring (would mean Bank.store() starts to fail). There are many other security issues to be fixed for snapshot for the milesone.

I'm pretty sure this code (=AppendVec::new) isn't touched by the snapshot deserialization code path at all.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this above if create {

@ryoqun
Copy link
Contributor Author

ryoqun commented Dec 9, 2019

@sakridge @mvines Could you take a look? Of course, you can do in your spare time possibly after the ongoing super fun time has passed. :)

@@ -138,6 +143,35 @@ impl AppendVec {
}
}

#[allow(clippy::mutex_atomic)]
pub fn new_empty_map(current_len: usize) -> Self {
let map = MmapMut::map_anon(1).expect("failed to map the data file");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error handling is made more critical rather undesirably from Err to just move the code here. But combined with this consideration, this can be tolerated to avoid large refactoring. :) And this mmap will almost never fail.

let file_size = std::fs::metadata(&path)?.len();
assert!(current_len <= file_size as usize);

AppendVec::sanitize_mmap_size(file_size as usize)?;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Notice the ?; Now we're correctly propagating this error up to the snapshot deserializing code.

runtime/src/append_vec.rs Outdated Show resolved Hide resolved
@sakridge
Copy link
Contributor

sakridge commented Dec 9, 2019

Overall it looks pretty good to me.

runtime/src/append_vec.rs Outdated Show resolved Hide resolved
@ryoqun
Copy link
Contributor Author

ryoqun commented Dec 12, 2019

@mvines pinging for your first impression of this PR. Especially this introduces another fixed/constant cluster-wide-common hard limit in the snapshot area :)

@stale
Copy link

stale bot commented Dec 19, 2019

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

@stale stale bot added the stale [bot only] Added to stale content; results in auto-close after a week. label Dec 19, 2019
@stale stale bot removed the stale [bot only] Added to stale content; results in auto-close after a week. label Dec 19, 2019
@ryoqun ryoqun changed the title [wip] Sanitize AppendVec's file_size Sanitize AppendVec's file_size Dec 19, 2019
@ryoqun ryoqun marked this pull request as ready for review December 19, 2019 10:30
@ryoqun
Copy link
Contributor Author

ryoqun commented Dec 19, 2019

Another round of brush up and I think this PR isn't draft anymore with good confidence. :)

@sakridge @mvines Could you review this again for being merged?

@ryoqun ryoqun requested review from sakridge and mvines December 19, 2019 10:32
@stale
Copy link

stale bot commented Dec 31, 2019

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

@stale stale bot added the stale [bot only] Added to stale content; results in auto-close after a week. label Dec 31, 2019
@ryoqun ryoqun removed the stale [bot only] Added to stale content; results in auto-close after a week. label Jan 6, 2020
Copy link
Contributor

@sakridge sakridge left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@ryoqun ryoqun merged commit 58e6d4a into solana-labs:master Jan 6, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants