fix(dd): ensure full block writes to handle partial writes to slow pipes #8750
+0
−0
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
https://download.virtualbox.org/virtualbox/7.2.2/ -> VBoxGuestAdditions_7.2.2.iso
Partial Write Bug in
uutils dd
The partial write bug in
uutils dd
occurs when writing large blocks to a pipe with a slow reader, resulting in truncated output (as seen with0+1 records out
and mismatched MD5 sums). The key area of interest is howdd
handles writing data to the output destination.In dd.rs, the write_block method of the Output struct (lines 864-883) is responsible for writing a block of data to the destination.
Issue Identified
The current implementation retries writing if the write operation is interrupted (
io::ErrorKind::Interrupted
), which is correct. However, it does not handle the case where a partial write occurs (i.e., wlen < chunk[base_idx..].len()) without being interrupted. When writing to a pipe with a slow reader, the kernel may return a partial write (less than the requested amount) without an error, and the code exits the loop if!self.settings.iflags.fullblock
is true. Sinceiflags.fullblock
is typically not set for output operations (it's meant for input), the loop exits after the first partial write, leading to truncated output.Root Cause
The condition
if (base_idx >= full_len) || !self.settings.iflags.fullblock
means that unlessfullblock
is set (which it often isn't for output), the function returns after the first write attempt, even if only part of the data was written. This mimics the behavior we observed in tests whereuutils dd
does not retry to write the remaining data, causing the0+1 records out
and mismatched byte counts/MD5 sums.Proposed Fix
To fix the partial write issue, we need to ensure that write_block continues to retry writing until the entire block is written or an error occurs, regardless of the
fullblock
flag. Thefullblock
flag should only apply to input operations, not output. Here's how we can modify the code:!self.settings.iflags.fullblock
condition from the loop exit criteria in write_block.base_idx >= full_len
or a non-interrupted error occurs.This change ensures that
uutils dd
matches the behavior of GNUdd
in handling partial writes to slow pipes, preventing data truncation.related
https://bugs.launchpad.net/ubuntu/+source/makeself/+bug/2125535
VirtualBox/virtualbox#226 (comment)
megastep/makeself@51e7299
I wanted to hear your opinion before adding some tests
this was my dirty hack
test result: ok. 3685 passed; 0 failed; 34 ignored; 0 measured; 0 filtered out; finished in 15.55s
@sylvestre