Skip to content

Commit

Permalink
nydus-image: generate dm-verity data for block device
Browse files Browse the repository at this point in the history
Add `--verity` option to `nydus-image export --block` to generate
dm-verity data for block devices.

```
[root@iZ0jl3vazmhc81dur3xnm3Z image-service]# tar -cvf src.tar src
[root@iZ0jl3vazmhc81dur3xnm3Z image-service]# sha256sum src.tar
0e2dbe8b6e0f55f42c75034ed9dfc582ad0a94098cfc248c968522e7ef02e00a  src.tar
[root@iZ0jl3vazmhc81dur3xnm3Z image-service]# cp src.tar images/0e2dbe8b6e0f55f42c75034ed9dfc582ad0a94098cfc248c968522e7ef02e00a
[root@iZ0jl3vazmhc81dur3xnm3Z image-service]# target/debug/nydus-image create -t tar-tarfs -D images/ images/0e2dbe8b6e0f55f42c75034ed9dfc582ad0a94098cfc248c968522e7ef02e00a
[2023-03-27 16:32:00.068730 +08:00] INFO successfully built RAFS filesystem:
meta blob path: images/90f0e6e7e0ff822d4acddf30c36ac77fe06f549fe58f89a818fa824b19f70d47
data blob size: 0x3c000
data blobs: ["0e2dbe8b6e0f55f42c75034ed9dfc582ad0a94098cfc248c968522e7ef02e00a"]
[root@iZ0jl3vazmhc81dur3xnm3Z image-service]# target/debug/nydus-image export --block --verity -D images/ -B images/90f0e6e7e0ff822d4acddf30c36ac77fe06f549fe58f89a818fa824b19f70d47
[2023-03-27 23:49:14.450762 +08:00] INFO RAFS features: COMPRESSION_NONE | HASH_SHA256 | EXPLICIT_UID_GID | TARTFS_MODE
dm-verity options: --no-superblock --format=1 -s "" --hash=sha256 --data-block-size=4096 --hash-block-size=4096 --data-blocks 572 --hash-offset 2342912 ab7b417fc284c3b58a72044a996ec55e2c68a8b9dcf10bc469f4e640e5d98e6a
losetup -r /dev/loop1 images/90f0e6e7e0ff822d4acddf30c36ac77fe06f549fe58f89a818fa824b19f70d47.disk
[root@iZ0jl3vazmhc81dur3xnm3Z image-service]# veritysetup open -v --no-superblock --format=1 -s "" --hash=sha256 --data-block-size=4096 --hash-block-size=4096 --data-blocks 572 --hash-offset 2342912 /dev/loop1 verity /dev/loop1 ab7b417fc284c3b58a72044a996ec55e2c68a8b9dcf10bc469f4e640e5d98e6a
[root@iZ0jl3vazmhc81dur3xnm3Z image-service]# veritysetup status verity
/dev/mapper/verity is active.
  type:        VERITY
  status:      verified
  hash type:   1
  data block:  4096
  hash block:  4096
  hash name:   sha256
  salt:        -
  data device: /dev/loop1
  data loop:   /root/image-service/images/90f0e6e7e0ff822d4acddf30c36ac77fe06f549fe58f89a818fa824b19f70d47.disk
  size:        4576 sectors
  mode:        readonly
  hash device: /dev/loop1
  hash loop:   /root/image-service/images/90f0e6e7e0ff822d4acddf30c36ac77fe06f549fe58f89a818fa824b19f70d47.disk
  hash offset: 4576 sectors
  root hash:   ab7b417fc284c3b58a72044a996ec55e2c68a8b9dcf10bc469f4e640e5d98e6a
```

Signed-off-by: Jiang Liu <[email protected]>
  • Loading branch information
jiangliu committed Mar 28, 2023
1 parent 80b5143 commit ec78d62
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 8 deletions.
74 changes: 67 additions & 7 deletions service/src/block_device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use std::cmp::{max, min};
use std::fs::OpenOptions;
use std::io::Result;
use std::path::PathBuf;
use std::sync::Arc;
use std::sync::{Arc, Mutex};
use std::thread;
use std::thread::JoinHandle;

Expand All @@ -25,6 +25,9 @@ use nydus_rafs::metadata::layout::v6::{
EROFS_BLOCK_BITS_12, EROFS_BLOCK_BITS_9, EROFS_BLOCK_SIZE_4096, EROFS_BLOCK_SIZE_512,
};
use nydus_storage::utils::alloc_buf;
use nydus_utils::digest::{self, RafsDigest};
use nydus_utils::round_up;
use nydus_utils::verity::VerityGenerator;
use tokio_uring::buf::IoBufMut;

use crate::blob_cache::{generate_blob_key, BlobCacheMgr, BlobConfig, DataBlob, MetaBlob};
Expand Down Expand Up @@ -287,6 +290,7 @@ impl BlockDevice {
output: Option<String>,
localfs_dir: Option<String>,
threads: u32,
verity: bool,
) -> Result<()> {
let cache_mgr = Arc::new(BlobCacheMgr::new());
cache_mgr.add_blob_entry(&blob_entry).map_err(|e| {
Expand All @@ -303,6 +307,7 @@ impl BlockDevice {
))
})?;
let block_device = Arc::new(block_device);
let blocks = block_device.blocks();

let path = match output {
Some(v) => PathBuf::from(v),
Expand Down Expand Up @@ -353,7 +358,27 @@ impl BlockDevice {
})?;
let output_file = Arc::new(tokio_uring::fs::File::from_std(output_file));

let blocks = block_device.blocks();
let mut verity_offset = 0;
let generator = if verity {
let file = OpenOptions::new()
.read(true)
.write(true)
.open(&path)
.map_err(|e| {
eother!(format!(
"block_device: failed to create output file {}, {}",
path.display(),
e
))
})?;
verity_offset = round_up(block_device.blocks_to_size(blocks), 4096);
let mut generator = VerityGenerator::new(file, verity_offset, blocks)?;
generator.initialize()?;
Some(Arc::new(Mutex::new(generator)))
} else {
None
};

let batch_size = BLOCK_DEVICE_EXPORT_BATCH_SIZE as u32 / block_device.block_size() as u32;
assert_eq!(batch_size.count_ones(), 1);
let threads = max(threads, 1);
Expand All @@ -363,8 +388,9 @@ impl BlockDevice {
}

if threads == 1 {
let generator = generator.clone();
tokio_uring::start(async move {
Self::do_export(block_device.clone(), output_file, 0, block_device.blocks()).await
Self::do_export(block_device, output_file, 0, blocks, generator).await
})?;
} else {
let mut thread_handlers: Vec<JoinHandle<Result<()>>> =
Expand All @@ -377,6 +403,7 @@ impl BlockDevice {
let mgr = cache_mgr.clone();
let id = blob_id.clone();
let path = path.to_path_buf();
let generator = generator.clone();

let handler = thread::spawn(move || {
let output_file = OpenOptions::new()
Expand All @@ -399,9 +426,9 @@ impl BlockDevice {
})?;
let device = Arc::new(block_device);

tokio_uring::start(
async move { Self::do_export(device, file, pos, count).await },
)?;
tokio_uring::start(async move {
Self::do_export(device, file, pos, count, generator).await
})?;
Ok(())
});
pos += count;
Expand All @@ -424,6 +451,21 @@ impl BlockDevice {
})?;
}
}

if let Some(generator) = generator.as_ref() {
let mut guard = generator.lock().unwrap();
let root_digest = guard.generate_all_digests()?;
let root_digest: String = root_digest
.data
.iter()
.map(|v| format!("{:02x}", v))
.collect();
println!(
"dm-verity options: --no-superblock --format=1 -s \"\" --hash=sha256 --data-block-size=512 --hash-block-size=4096 --data-blocks {} --hash-offset {} {}",
blocks, verity_offset, root_digest
);
}

Ok(())
}

Expand All @@ -432,16 +474,18 @@ impl BlockDevice {
output_file: Arc<tokio_uring::fs::File>,
start: u32,
mut blocks: u32,
generator: Option<Arc<Mutex<VerityGenerator>>>,
) -> Result<()> {
let batch_size = BLOCK_DEVICE_EXPORT_BATCH_SIZE as u32 / block_device.block_size() as u32;
let block_size = block_device.block_size() as usize;
let mut pos = start;
let mut buf = alloc_buf(BLOCK_DEVICE_EXPORT_BATCH_SIZE);

while blocks > 0 {
let count = min(batch_size, blocks);
let (res, buf1) = block_device.async_read(pos, count, buf).await;
let sz = res?;
if sz != count as usize * block_device.block_size() as usize {
if sz != count as usize * block_size {
return Err(eio!(
"block_device: failed to read data, got less data than requested"
));
Expand All @@ -462,6 +506,22 @@ impl BlockDevice {
}
buf = buf2;

// Generate Merkle tree leaf nodes.
if let Some(generator) = generator.as_ref() {
let mut page_idx = (block_device.blocks_to_size(pos) / block_size as u64) as u32;
let mut offset = 0;
while offset < buf.len() {
let digest = RafsDigest::from_buf(
&buf[offset..offset + block_size],
digest::Algorithm::Sha256,
);
let mut guard = generator.lock().unwrap();
guard.set_digest(1, page_idx, &digest.data)?;
offset += block_size;
page_idx += 1;
}
}

pos += count;
blocks -= count;
}
Expand Down
11 changes: 10 additions & 1 deletion src/bin/nydus-image/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,14 @@ fn prepare_cmd_args(bti_string: &'static str) -> App {
.help("File path for saving the exported content")
.required_unless_present("localfs-dir")
)
.arg(
Arg::new("verity")
.long("verity")
.help("Generate dm-verity data for block device")
.action(ArgAction::SetTrue)
.required(false)
.requires("block")
)
);

let app = app.subcommand(
Expand Down Expand Up @@ -1558,8 +1566,9 @@ impl Command {
.map(|n| n.parse().unwrap_or(1))
.unwrap_or(1);
let output = subargs.value_of("output").map(|v| v.to_string());
let verity = subargs.is_present("verity");

BlockDevice::export(entry, output, localfs_dir, threads)
BlockDevice::export(entry, output, localfs_dir, threads, verity)
.context("failed to export RAFS filesystem as raw block device image")
}
}
Expand Down

0 comments on commit ec78d62

Please sign in to comment.