Skip to content

Commit 78e8c8f

Browse files
committed
chroe: properly perform checksums on partition table arrays
Some partitioning tools like ones based on libparted (parted and GParted) don't wipe the entire GPT partition name field before writing new partition names. Additionally, it is not guaranteed to be properly zeroed since the UEFI specification does not clearly state that. Use a dedicated raw buffer holding the entire partition name field without any conversion for performing checksums and serializations. Signed-off-by: Xinhui Yang <[email protected]>
1 parent 7bd1432 commit 78e8c8f

File tree

1 file changed

+36
-16
lines changed

1 file changed

+36
-16
lines changed

src/lib.rs

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -378,24 +378,37 @@ impl GPTHeader {
378378

379379
/// A wrapper type for `String` that represents a partition's name.
380380
#[derive(Debug, Clone, PartialEq, Eq)]
381-
pub struct PartitionName(String);
381+
pub struct PartitionName {
382+
string: String,
383+
raw_buf: [u16; 36],
384+
}
382385

383386
impl PartitionName {
384387
/// Extracts a string slice containing the entire `PartitionName`.
385388
pub fn as_str(&self) -> &str {
386-
self.0.as_str()
389+
&self.string
387390
}
388391
}
389392

390393
impl std::fmt::Display for PartitionName {
391394
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
392-
write!(f, "{}", self.0)
395+
write!(f, "{}", &self.string)
393396
}
394397
}
395398

396399
impl From<&str> for PartitionName {
397400
fn from(value: &str) -> PartitionName {
398-
PartitionName(value.to_string())
401+
let utf16_converted: Vec<_> = value
402+
.encode_utf16()
403+
.chain([0].into_iter().cycle())
404+
.take(36)
405+
.collect();
406+
let mut raw_buf = [0; 36];
407+
raw_buf.copy_from_slice(&utf16_converted);
408+
PartitionName {
409+
string: value.to_string(),
410+
raw_buf,
411+
}
399412
}
400413
}
401414

@@ -412,18 +425,25 @@ impl<'de> Visitor<'de> for UTF16LEVisitor {
412425
where
413426
A: SeqAccess<'de>,
414427
{
415-
let mut v = Vec::new();
428+
let mut v: Vec<u16> = Vec::new();
429+
let mut raw_buf = [0; 36];
416430
let mut end = false;
417-
loop {
418-
match seq.next_element()? {
419-
Some(0) => end = true,
420-
Some(x) if !end => v.push(x),
421-
Some(_) => {}
422-
None => break,
431+
let mut iter = raw_buf.iter_mut();
432+
while let Some(x) = seq.next_element()? {
433+
if let Some(element) = iter.next() {
434+
if x == 0 {
435+
end = true;
436+
}
437+
if !end {
438+
v.push(x);
439+
}
440+
*element = x;
423441
}
424442
}
425-
426-
Ok(PartitionName(String::from_utf16_lossy(&v)))
443+
Ok(PartitionName {
444+
string: String::from_utf16_lossy(&v),
445+
raw_buf,
446+
})
427447
}
428448
}
429449

@@ -441,10 +461,10 @@ impl Serialize for PartitionName {
441461
where
442462
S: Serializer,
443463
{
444-
let s = self.0.encode_utf16();
464+
// Favor using the content in the raw buffer in case there is garbage left (used for the CRC)
445465
let mut seq = serializer.serialize_tuple(36)?;
446-
for x in s.chain([0].iter().cycle().cloned()).take(36) {
447-
seq.serialize_element(&x)?;
466+
for x in self.raw_buf {
467+
seq.serialize_element(&x.to_le_bytes())?;
448468
}
449469
seq.end()
450470
}

0 commit comments

Comments
 (0)