summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Gortmaker <paul.gortmaker@windriver.com>2023-06-21 10:13:32 -0700
committerArmin Kuster <akuster808@gmail.com>2023-06-25 15:05:28 -0400
commit4922b3053af9e0f66a3e0a65bd25b9f51df3a4f9 (patch)
tree99d349f20894e1799749d3da0333fe5d7f8be791
parent39c69c8b5dd56730c469c90e934f8b0606331d3b (diff)
downloadmeta-security-4922b3053af9e0f66a3e0a65bd25b9f51df3a4f9.tar.gz
dm-verity: add support for hash storage on separate partition
There are essentially two ways for dealing with where to put the hash data for dm-verity block integrity checks. You can store both in a single partition, by using ~95% of the storage space for the filesystem and the remaining 5% tail for the hash, or you can use a completely separate partition (or even device) for storing the hash data elsewhere. Method A relies on using a hash offset argument during creation, which is generally OK from a scripted use case but is error prone when run from the command line and the offset calculated manually. Method B has the advantage of using the basic partition/device compartmentalization of the kernel to ensure the fs data doesn't overwrite the hash or vice versa. It takes any possible errors due to math miscalculations completely off the table. At the moment, our current support is hard coded to only support the offset method A. Here we add support for separate hash as per B. As multiple partitions are now in play, we use the UUID creation standard adopted by the systemd/verity community which implicitly links the root and hash partitions by splitting the top roothash in two for the UUIDs of the components. This change optionally creates the separate hash file but no examples use it yet. Further commits will implement an example. Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> Signed-off-by: Armin Kuster <akuster808@gmail.com>
-rw-r--r--classes/dm-verity-img.bbclass60
1 files changed, 58 insertions, 2 deletions
diff --git a/classes/dm-verity-img.bbclass b/classes/dm-verity-img.bbclass
index e190c87..8351ab2 100644
--- a/classes/dm-verity-img.bbclass
+++ b/classes/dm-verity-img.bbclass
@@ -10,11 +10,15 @@
10# assure data integrity, the root hash must be stored in a trusted location 10# assure data integrity, the root hash must be stored in a trusted location
11# or cryptographically signed and verified. 11# or cryptographically signed and verified.
12# 12#
13# Optionally, we can store the hash data on a separate device or partition
14# for improved compartmentalization and ease of use/deployment.
15#
13# Usage: 16# Usage:
14# DM_VERITY_IMAGE = "core-image-full-cmdline" # or other image 17# DM_VERITY_IMAGE = "core-image-full-cmdline" # or other image
15# DM_VERITY_IMAGE_TYPE = "ext4" # or ext2, ext3 & btrfs 18# DM_VERITY_IMAGE_TYPE = "ext4" # or ext2, ext3 & btrfs
19# DM_VERITY_SEPARATE_HASH = "1" # optional; store hash on separate dev
16# IMAGE_CLASSES += "dm-verity-img" 20# IMAGE_CLASSES += "dm-verity-img"
17# 21
18# The resulting image can then be used to implement the device mapper block 22# The resulting image can then be used to implement the device mapper block
19# integrity checking on the target device. 23# integrity checking on the target device.
20 24
@@ -28,6 +32,9 @@ DM_VERITY_IMAGE_DATA_BLOCK_SIZE ?= "1024"
28# Define the hash block size to use in veritysetup. 32# Define the hash block size to use in veritysetup.
29DM_VERITY_IMAGE_HASH_BLOCK_SIZE ?= "4096" 33DM_VERITY_IMAGE_HASH_BLOCK_SIZE ?= "4096"
30 34
35# Should we store the hash data on a separate device/partition?
36DM_VERITY_SEPARATE_HASH ?= "0"
37
31# Process the output from veritysetup and generate the corresponding .env 38# Process the output from veritysetup and generate the corresponding .env
32# file. The output from veritysetup is not very machine-friendly so we need to 39# file. The output from veritysetup is not very machine-friendly so we need to
33# convert it to some better format. Let's drop the first line (doesn't contain 40# convert it to some better format. Let's drop the first line (doesn't contain
@@ -50,6 +57,35 @@ process_verity() {
50 57
51 # Add partition size 58 # Add partition size
52 echo "DATA_SIZE=$SIZE" >> $ENV 59 echo "DATA_SIZE=$SIZE" >> $ENV
60
61 # Add whether we are storing the hash data separately
62 echo "SEPARATE_HASH=${DM_VERITY_SEPARATE_HASH}" >> $ENV
63
64 # Configured for single partition use of veritysetup? OK, we are done.
65 if [ ${DM_VERITY_SEPARATE_HASH} -eq 0 ]; then
66 return
67 fi
68
69 # Craft up the UUIDs that are part of the verity standard for root & hash
70 # while we are here and in shell. Re-read our output to get ROOT_HASH
71 # and then cut it in 1/2 ; HI for data UUID and LO for hash-data UUID.
72 # https://uapi-group.org/specifications/specs/discoverable_partitions_specification/
73
74 ROOT_HASH=$(cat $ENV | grep ^ROOT_HASH | sed 's/ROOT_HASH=//' | tr a-f A-F)
75 ROOT_HI=$(echo "obase=16;ibase=16;$ROOT_HASH/2^80" | /usr/bin/bc)
76 ROOT_LO=$(echo "obase=16;ibase=16;$ROOT_HASH%2^80" | /usr/bin/bc)
77
78 # Hyphenate as per UUID spec and as expected by wic+sgdisk parameters.
79 # Prefix with leading zeros, in case hash chunks weren't using highest bits
80 # "bc" needs upper case, /dev/disk/by-partuuid/ is lower case. <sigh>
81 ROOT_UUID=$(echo 00000000$ROOT_HI | sed 's/.*\(.\{32\}\)$/\1/' | \
82 sed 's/./-&/9;s/./-&/14;s/./-&/19;s/./-&/24' | tr A-F a-f )
83 RHASH_UUID=$(echo 00000000$ROOT_LO | sed 's/.*\(.\{32\}\)$/\1/' | \
84 sed 's/./-&/9;s/./-&/14;s/./-&/19;s/./-&/24' | tr A-F a-f )
85
86 # Emit the values needed for a veritysetup run in the initramfs
87 echo "ROOT_UUID=$ROOT_UUID" >> $ENV
88 echo "RHASH_UUID=$RHASH_UUID" >> $ENV
53} 89}
54 90
55verity_setup() { 91verity_setup() {
@@ -57,6 +93,8 @@ verity_setup() {
57 local INPUT=${IMAGE_NAME}${IMAGE_NAME_SUFFIX}.$TYPE 93 local INPUT=${IMAGE_NAME}${IMAGE_NAME_SUFFIX}.$TYPE
58 local SIZE=$(stat --printf="%s" $INPUT) 94 local SIZE=$(stat --printf="%s" $INPUT)
59 local OUTPUT=$INPUT.verity 95 local OUTPUT=$INPUT.verity
96 local OUTPUT_HASH=$INPUT.verity
97 local HASH_OFFSET=""
60 local SETUP_ARGS="" 98 local SETUP_ARGS=""
61 local SAVED_ARGS="${STAGING_VERITY_DIR}/${IMAGE_BASENAME}.$TYPE.verity.args" 99 local SAVED_ARGS="${STAGING_VERITY_DIR}/${IMAGE_BASENAME}.$TYPE.verity.args"
62 100
@@ -69,12 +107,19 @@ verity_setup() {
69 fi 107 fi
70 SIZE=$(expr \( $SIZE + $align - 1 \) / $align \* $align) 108 SIZE=$(expr \( $SIZE + $align - 1 \) / $align \* $align)
71 109
110 # Assume some users may want separate hash vs. appended hash
111 if [ ${DM_VERITY_SEPARATE_HASH} -eq 1 ]; then
112 OUTPUT_HASH=$INPUT.vhash
113 else
114 HASH_OFFSET="--hash-offset="$SIZE
115 fi
116
72 cp -a $INPUT $OUTPUT 117 cp -a $INPUT $OUTPUT
73 118
74 SETUP_ARGS=" \ 119 SETUP_ARGS=" \
75 --data-block-size=${DM_VERITY_IMAGE_DATA_BLOCK_SIZE} \ 120 --data-block-size=${DM_VERITY_IMAGE_DATA_BLOCK_SIZE} \
76 --hash-block-size=${DM_VERITY_IMAGE_HASH_BLOCK_SIZE} \ 121 --hash-block-size=${DM_VERITY_IMAGE_HASH_BLOCK_SIZE} \
77 --hash-offset=$SIZE format $OUTPUT $OUTPUT \ 122 $HASH_OFFSET format $OUTPUT $OUTPUT_HASH \
78 " 123 "
79 124
80 echo "veritysetup $SETUP_ARGS" > $SAVED_ARGS 125 echo "veritysetup $SETUP_ARGS" > $SAVED_ARGS
@@ -84,6 +129,13 @@ verity_setup() {
84 veritysetup $SETUP_ARGS | tail -n +2 | process_verity 129 veritysetup $SETUP_ARGS | tail -n +2 | process_verity
85} 130}
86 131
132# make "dateless" symlink for the hash so the wks can find it.
133verity_hash() {
134 cd ${IMGDEPLOYDIR}
135 ln -sf ${IMAGE_NAME}${IMAGE_NAME_SUFFIX}.${DM_VERITY_IMAGE_TYPE}.vhash \
136 ${IMAGE_BASENAME}-${MACHINE}.${DM_VERITY_IMAGE_TYPE}.vhash
137}
138
87VERITY_TYPES = " \ 139VERITY_TYPES = " \
88 ext2.verity ext3.verity ext4.verity \ 140 ext2.verity ext3.verity ext4.verity \
89 btrfs.verity \ 141 btrfs.verity \
@@ -94,10 +146,12 @@ IMAGE_TYPES += "${VERITY_TYPES}"
94CONVERSIONTYPES += "verity" 146CONVERSIONTYPES += "verity"
95CONVERSION_CMD:verity = "verity_setup ${type}" 147CONVERSION_CMD:verity = "verity_setup ${type}"
96CONVERSION_DEPENDS_verity = "cryptsetup-native" 148CONVERSION_DEPENDS_verity = "cryptsetup-native"
149IMAGE_CMD:vhash = "verity_hash"
97 150
98python __anonymous() { 151python __anonymous() {
99 verity_image = d.getVar('DM_VERITY_IMAGE') 152 verity_image = d.getVar('DM_VERITY_IMAGE')
100 verity_type = d.getVar('DM_VERITY_IMAGE_TYPE') 153 verity_type = d.getVar('DM_VERITY_IMAGE_TYPE')
154 verity_hash = d.getVar('DM_VERITY_SEPARATE_HASH')
101 image_fstypes = d.getVar('IMAGE_FSTYPES') 155 image_fstypes = d.getVar('IMAGE_FSTYPES')
102 pn = d.getVar('PN') 156 pn = d.getVar('PN')
103 157
@@ -112,6 +166,8 @@ python __anonymous() {
112 bb.fatal('DM_VERITY_IMAGE_TYPE must contain exactly one type') 166 bb.fatal('DM_VERITY_IMAGE_TYPE must contain exactly one type')
113 167
114 d.appendVar('IMAGE_FSTYPES', ' %s.verity' % verity_type) 168 d.appendVar('IMAGE_FSTYPES', ' %s.verity' % verity_type)
169 if verity_hash == "1":
170 d.appendVar('IMAGE_FSTYPES', ' vhash')
115 171
116 # If we're using wic: we'll have to use partition images and not the rootfs 172 # If we're using wic: we'll have to use partition images and not the rootfs
117 # source plugin so add the appropriate dependency. 173 # source plugin so add the appropriate dependency.