cubelinux: an addressed image is readable without a log
merged_digest answered "no log" before it looked at the layout, so a bare v3/v4 image fell through to the packed walk — which starts at the v2 header length and reads index entries as record frames. A bare addressed image with no log beside it therefore read as a one-record store with an empty value. An addressed image is a complete store on its own: its index holds every record and says where each one is, so a log is an addition rather than a requirement. A packed image is not, which is why "no log" still means what it meant for v1/v2. Found by verify-image-read the moment userspace started writing v4: while every userspace image was v2 the fallback happened to be the right walk. The kernel's own v4 images always had a log header beside them, so no other gate could have caught it.
This commit is contained in:
@@ -1047,7 +1047,17 @@ fn build_merged(image: &[u8], log: &[u8], header: &Header) -> Result<(Merged, u6
|
|||||||
/// to it. Returns `Err("no-log")` when there is none, so the caller can fall back to reading
|
/// to it. Returns `Err("no-log")` when there is none, so the caller can fall back to reading
|
||||||
/// the image by itself.
|
/// the image by itself.
|
||||||
fn merged_digest(image: &[u8], log: &[u8], header: &Header) -> Result<Line, &'static str> {
|
fn merged_digest(image: &[u8], log: &[u8], header: &Header) -> Result<Line, &'static str> {
|
||||||
if log.len() < WAL_HEADER_LEN || &log[0..4] != WAL_MAGIC {
|
// An addressed image is a complete store on its own: its index holds every record and says
|
||||||
|
// where each one is, so a log is an *addition* rather than a requirement. A packed image is
|
||||||
|
// not — without a log there is nothing this path adds over the image's own order, which is why
|
||||||
|
// it answers "no log" and lets the caller walk the records it can see.
|
||||||
|
//
|
||||||
|
// Requiring a log here regardless of layout is what made a bare v3/v4 image read as a *packed*
|
||||||
|
// one: the caller fell through to a walk that starts at the v2 header length and reads index
|
||||||
|
// entries as record frames. It went unnoticed while every userspace-written image was v2, which
|
||||||
|
// is exactly the kind of bug that a migration finds and a unit test does not.
|
||||||
|
let addressed = header.version == VERSION_V3 || header.version == VERSION_V4;
|
||||||
|
if !addressed && (log.len() < WAL_HEADER_LEN || &log[0..4] != WAL_MAGIC) {
|
||||||
return Err("no-log");
|
return Err("no-log");
|
||||||
}
|
}
|
||||||
let (mut merged, applied) = build_merged(image, log, header)?;
|
let (mut merged, applied) = build_merged(image, log, header)?;
|
||||||
|
|||||||
Reference in New Issue
Block a user