From 67aa3b15d794d76c816475e3e53725c878aa2c6d Mon Sep 17 00:00:00 2001 From: whisky-ma Date: Mon, 11 Nov 2024 20:17:27 +0800 Subject: [PATCH] support dm-verity and secureboot --- scripts/05dmverity/dmv-mount.sh | 97 ++++++++ scripts/05dmverity/module-setup.sh | 18 ++ scripts/create/imageCreate.sh | 73 ++++-- scripts/create/rootfsCreate.sh | 20 +- scripts/dm-verity/chroot_new_grub.sh | 26 ++ scripts/dm-verity/dm_verity.sh | 360 +++++++++++++++++++++++++++ scripts/dm-verity/grub.cfg | 133 ++++++++++ scripts/grub.cfg | 2 +- scripts/kbimg.sh | 64 ++++- scripts/rpmlist | 4 +- scripts/set_in_chroot.sh | 8 +- 11 files changed, 775 insertions(+), 30 deletions(-) create mode 100644 scripts/05dmverity/dmv-mount.sh create mode 100644 scripts/05dmverity/module-setup.sh create mode 100644 scripts/dm-verity/chroot_new_grub.sh create mode 100644 scripts/dm-verity/dm_verity.sh create mode 100644 scripts/dm-verity/grub.cfg diff --git a/scripts/05dmverity/dmv-mount.sh b/scripts/05dmverity/dmv-mount.sh new file mode 100644 index 00000000..af2c9157 --- /dev/null +++ b/scripts/05dmverity/dmv-mount.sh @@ -0,0 +1,97 @@ +#!/bin/bash +set -x +export PATH=/bin:/sbin:/usr/bin:/usr/sbin + +echo "create dm-verity device for rootfs..." + +roothash= + +function parse_kernel_args() { + CMDLINE=$(cat /proc/cmdline) + for param in $CMDLINE; do + case "${param}" in + root=*) + root_device="${param}" + echo "${root_device}" + ;; + dmvroothash=*) + roothash=$(echo "${param}" | cut -d'=' -f2 | tr -d '\n') + echo "${roothash}" + ;; + esac + done +} + +function try_another() { + bootres=$(efibootmgr) + bootcurrent=$(echo "$bootres" | grep "BootCurrent" | cut -d ':' -f2 | tr -d ' ') + currentposition=$(echo "$bootres" | grep "Boot$bootcurrent" | cut -d '(' -f2 | cut -b 1) + + if [ "$currentposition" = "1" ]; then + another=4 + elif [ "$currentposition" = "4" ]; then + another=1 + else + echo "reboot" + fi + + exist=$(echo "$bootres" | grep "$another,GPT") + if [ "$exist" = "" ]; then + arch=$(arch) + if [ "$arch" = "x86_64" ]; then + efibootmgr -c -d "/dev/${DEVprefix}" -p "$another" -l "\EFI\openEuler\shimx64.efi" + elif [ "$arch" = "aarch64" ]; then + efibootmgr -c -d "/dev/${DEVprefix}" -p "$another" -l "\EFI\openEuler\shimaa64.efi" + else + echo "$arch not support" + reboot + fi + fi + anotherbootNum=$(efibootmgr | grep "$another,GPT" | cut -b 5-8) + + efibootmgr -o "$anotherbootNum,$bootcurrent" + reboot +} + +parse_kernel_args + +root1=$(echo "${root_device}" | cut -d'=' -f2) +root2=$(echo "${root_device}" | cut -d'=' -f3) +final="" +DEVprefix="vda" +hwinfo --disk + +if [ "${root2}" = "" ]; then + final=${root1: -1} + DEVprefix=$(echo "$root1" | cut -d'/' -f3 | sed 's/[^a-z]//g') +elif [ "${root1}" = "LABEL" ] && [ "${root2}" != "" ]; then + root3=$(readlink "/dev/disk/by-label/$root2") + final=${root3: -1} + ## shellcheck disable=SC2001 + DEVprefix=$(echo "$root3" | sed 's/[^a-z]//g') +elif [ "${root1}" = "UUID" ] && [ "${root2}" != "" ]; then + root3=$(readlink "/dev/disk/by-uuid/$root2") + final=${root3: -1} + DEVprefix=$(echo "$root3" | sed 's/[^a-z]//g') +elif [ "${root1}" = "PARTUUID" ] && [ "${root2}" != "" ]; then + root3=$(readlink "/dev/disk/by-partuuid/$root2") + final=${root3: -1} + DEVprefix=$(echo "$root3" | sed 's/[^a-z]//g') +else + echo "${root_device}: root-device identifier error, parse failed" +fi + +hashpart=$(echo "${final}+1" | bc) +veritysetup create kubeos-root "/dev/${DEVprefix}${final}" "/dev/${DEVprefix}${hashpart}" "${roothash}" +dmvstatus=$(veritysetup status kubeos-root | grep "status:" | cut -d : -f2 | tr -d " ") +if [ "$dmvstatus" = "verified" ]; then + echo "dm-verity verify success! switch to kubeos-root...." + mount /dev/mapper/kubeos-root /sysroot +else + try_another +fi + +if [ $? -ne 0 ]; then + echo "mount rootfs failed" + reboot +fi diff --git a/scripts/05dmverity/module-setup.sh b/scripts/05dmverity/module-setup.sh new file mode 100644 index 00000000..639b19ab --- /dev/null +++ b/scripts/05dmverity/module-setup.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +check() { + return 0 +} + +install() { + inst_multiple -o grub2-mkimage fdisk cpio veritysetup cut awk efibootmgr modprobe arch bc hwinfo partprobe + inst_hook pre-mount 05 "$moddir/dmv-mount.sh" +} + +installkernel() { + hostonly='' \ + instmods \ + =drivers/scsi \ + =drivers/virtio \ + =drivers/block +} diff --git a/scripts/create/imageCreate.sh b/scripts/create/imageCreate.sh index 4d02f9d1..c5bbb7e0 100644 --- a/scripts/create/imageCreate.sh +++ b/scripts/create/imageCreate.sh @@ -15,6 +15,10 @@ IMG_SIZE=20 PWD="$(pwd)" function create_img() { local BOOT_MODE=$1 + local DMV_MODE=0 + if [ $# -ge 2 ]; then + DMV_MODE=$2 + fi rm -f system.img update.img qemu-img create system.img ${IMG_SIZE}G if [ "$BOOT_MODE" = "legacy" ]; then @@ -27,15 +31,23 @@ function create_img() { parted system.img -s mkpart primary fat32 1MiB 60MiB fi parted system.img -s mkpart primary ext4 60MiB 2160MiB - parted system.img -s mkpart primary ext4 2160MiB 4260MiB - parted system.img -s mkpart primary ext4 4260MiB 100% + if [ "$BOOT_MODE" = "efi" ] && [ "${DMV_MODE}" == "2" ]; then + parted system.img -s mkpart primary ext4 2160MiB 2260MiB + parted system.img -s mkpart primary fat32 2260MiB 2320MiB + parted system.img -s mkpart primary ext4 2320MiB 4420MiB + parted system.img -s mkpart primary ext4 4420MiB 4520MiB + parted system.img -s mkpart primary ext4 4520MiB 100% + else + parted system.img -s mkpart primary ext4 2160MiB 4260MiB + parted system.img -s mkpart primary ext4 4260MiB 100% + fi local device=$(losetup -f) losetup "${device}" system.img mkdir -p "${TMP_MOUNT_PATH}" init_part system.img2 ROOT-A "${TMP_MOUNT_PATH}" - + mkdir -p ${BOOT_PATH} chmod 755 ${BOOT_PATH} if [ "$BOOT_MODE" = "legacy" ]; then @@ -48,7 +60,7 @@ function create_img() { sed -i "s/insmod part_gpt/insmod part_msdos/g; \ s/set root='hd0,gpt2'/set root='hd0,msdos2'/g; \ s/set root='hd0,gpt3'/set root='hd0,msdos3'/g" \ -"${TMP_MOUNT_PATH}"/boot/grub2/grub.cfg + "${TMP_MOUNT_PATH}"/boot/grub2/grub.cfg fi sync cp bootloader.sh "${TMP_MOUNT_PATH}" @@ -60,17 +72,32 @@ s/set root='hd0,gpt3'/set root='hd0,msdos3'/g" \ dd if=/dev/disk/by-label/ROOT-A of=update.img bs=8M sync unmount_dir "${TMP_MOUNT_PATH}" - init_part system.img3 ROOT-B "${TMP_MOUNT_PATH}" + + if [ "$BOOT_MODE" = "efi" ] && [ "${DMV_MODE}" == "2" ]; then + init_part system.img5 ROOT-B "${TMP_MOUNT_PATH}" + else + init_part system.img3 ROOT-B "${TMP_MOUNT_PATH}" + fi umount "${TMP_MOUNT_PATH}" - init_part system.img4 PERSIST "${TMP_MOUNT_PATH}" + if [ "$BOOT_MODE" = "efi" ] && [ "${DMV_MODE}" == "2" ]; then + init_part system.img7 PERSIST "${TMP_MOUNT_PATH}" + else + init_part system.img4 PERSIST "${TMP_MOUNT_PATH}" + fi mkdir ${TMP_MOUNT_PATH}/{var,etc,etcwork} mkdir -p ${TMP_MOUNT_PATH}/etc/KubeOS/certs umount "${TMP_MOUNT_PATH}" losetup -D parted system.img -- set 1 boot on - qemu-img convert system.img -O qcow2 system.qcow2 + + if [ "${DMV_MODE}" == "2" ]; then + rm -f update.img + dmvmain $3 $4 $5 + else + qemu-img convert system.img -O qcow2 system.qcow2 + fi } function create_pxe_img() { @@ -85,7 +112,7 @@ function create_pxe_img() { create_os_tar_from_docker "$@" ;; esac - tar -xvf os.tar ./initramfs.img + tar -xvf os.tar ./initramfs.img mv os.tar kubeos.tar } @@ -99,16 +126,24 @@ function create_vm_img() { local opt=$1 shift local BOOT_MODE=$5 - case $opt in - "repo") - create_os_tar_from_repo "$@" - create_img "${BOOT_MODE}" - ;; - "docker") - create_os_tar_from_docker "$@" - create_img "${BOOT_MODE}" - ;; - esac + local DMV_MODE=0 + if [ $# -ge 6 ]; then + DMV_MODE=$6 + fi + case $opt in + "repo") + create_os_tar_from_repo "$@" + if [ "${DMV_MODE}" == "2" ]; then + create_img "${BOOT_MODE}" "${DMV_MODE}" $7 $8 $9 + else + create_img "${BOOT_MODE}" "${DMV_MODE}" + fi + ;; + "docker") + create_os_tar_from_docker "$@" + create_img "${BOOT_MODE}" + ;; + esac } @@ -119,4 +154,4 @@ function create_admin_img() { cp ../bin/hostshell ${ADMIN_CONTAINER_DIR} docker build -t ${DOCKER_IMG} -f ${DOCKERFILE} ${ADMIN_CONTAINER_DIR} rm -rf ${ADMIN_CONTAINER_DIR}/hostshell -} \ No newline at end of file +} diff --git a/scripts/create/rootfsCreate.sh b/scripts/create/rootfsCreate.sh index 377cbf85..b09f58f0 100644 --- a/scripts/create/rootfsCreate.sh +++ b/scripts/create/rootfsCreate.sh @@ -23,6 +23,7 @@ function prepare_yum() { function install_packages() { local REPO=$1 local BOOT_MODE=$2 + local DMV_MODE=$3 prepare_yum ${REPO} echo "install package.." @@ -41,8 +42,14 @@ function install_packages() { else rpms+=" grub2-efi grub2-tools grub2-efi-x64-modules grub2-pc-modules" fi - yum -y --installroot="${RPM_ROOT}" install --nogpgcheck --setopt install_weak_deps=False ${rpms} + if [ ${DMV_MODE} == "2" ]; then + rpms+=" veritysetup shim mokutil grub2-efi-x64" + fi + yum -y --installroot="${RPM_ROOT}" install --nogpgcheck --setopt install_weak_deps=False ${rpms} elif [ "${ARCH}" == "aarch64" ]; then + if [ ${DMV_MODE} == "2" ]; then + rpms+=" veritysetup shim mokutil grub2-efi-aa64" + fi yum -y --installroot="${RPM_ROOT}" install --nogpgcheck --setopt install_weak_deps=False ${rpms} grub2-efi grub2-tools grub2-efi-aa64-modules fi yum -y --installroot="${RPM_ROOT}" clean all @@ -53,6 +60,7 @@ function install_misc() { local AGENT_PATH=$2 local PASSWD=$3 local BOOT_MODE=$4 + local DMV_MODE=$5 local DNS_CONF="${PWD}/resolv.conf" cp ../files/*mount ../files/os-agent.service "${RPM_ROOT}/usr/lib/systemd/system/" cp ../files/os-release "${RPM_ROOT}/usr/lib/" @@ -77,7 +85,10 @@ s/set root='hd0,gpt3'/set root='hd0,msdos3'/g" \ cp grub.cfg "${RPM_ROOT}"/boot/efi/EFI/openEuler fi cp -r ./00bootup ${RPM_ROOT}/usr/lib/dracut/modules.d/ - cp set_in_chroot.sh "${RPM_ROOT}" + if [ ${DMV_MODE} == "2" ]; then + cp -r ./05dmverity ${RPM_ROOT}/usr/lib/dracut/modules.d/ + fi + cp set_in_chroot.sh "${RPM_ROOT}" ROOT_PWD="${PASSWD}" BOOT_MODE="${BOOT_MODE}" chroot "${RPM_ROOT}" bash /set_in_chroot.sh rm "${RPM_ROOT}/set_in_chroot.sh" if [ -e "${DNS_CONF}" ]; then @@ -91,8 +102,9 @@ function create_os_tar_from_repo() { local AGENT_PATH=$3 local PASSWD=$4 local BOOT_MODE=$5 - install_packages ${REPO} ${BOOT_MODE} - install_misc ${VERSION} ${AGENT_PATH} ${PASSWD} ${BOOT_MODE} + local DMV_MODE=$6 + install_packages ${REPO} ${BOOT_MODE} ${DMV_MODE} + install_misc ${VERSION} ${AGENT_PATH} ${PASSWD} ${BOOT_MODE} ${DMV_MODE} unmount_dir "${RPM_ROOT}" tar -C "$RPM_ROOT" -cf ./os.tar . } diff --git a/scripts/dm-verity/chroot_new_grub.sh b/scripts/dm-verity/chroot_new_grub.sh new file mode 100644 index 00000000..b9608c9a --- /dev/null +++ b/scripts/dm-verity/chroot_new_grub.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +set -x + +WORKDIR="/tmp4grub" + +function create_new_grubxx_efi() { + + ARCH=$(arch) + if [ "$ARCH" == "x86_64" ]; then + MODULES="all_video boot btrfs cat configfile cryptodisk echo efifwsetup efinet ext2 f2fs fat font gcry_rijndael gcry_rsa gcry_serpent gcry_sha256 gcry_sha512 gcry_twofish gcry_whirlpool gfxmenu gfxterm gzio halt hfsplus http iso9660 jpeg loadenv loopback linux lvm lsefi lsefimmap luks luks2 mdraid09 mdraid1x minicmd net normal part_apple part_msdos part_gpt password_pbkdf2 pgp png reboot regexp search search_fs_uuid search_fs_file search_label serial sleep syslinuxcfg test tftp video xfs zstd tpm backtrace chain usb usbserial_common usbserial_pl2303 usbserial_ftdi usbserial_usbdebug keylayouts at_keyboard" + grub2-mkimage -d /usr/lib/grub/x86_64-efi -O x86_64-efi -p /EFI/openEuler --pubkey "${WORKDIR}/gpg.key" --output "${WORKDIR}/grubx64.efi" -c "${WORKDIR}"/grub.init.cfg --sbat "${WORKDIR}/sbat.csv" $MODULES 2>&1 | tee "${WORKDIR}/mkimage.log" + fi + + if [ "$ARCH" == "aarch64" ]; then + MODULES="all_video boot btrfs cat configfile cryptodisk echo efifwsetup efinet ext2 f2fs fat font gcry_rijndael gcry_rsa gcry_serpent gcry_sha256 gcry_sha512 gcry_twofish gcry_whirlpool gfxmenu gfxterm gzio halt hfsplus http iso9660 jpeg loadenv loopback linux lvm lsefi lsefimmap luks luks2 mdraid09 mdraid1x minicmd net normal part_apple part_msdos part_gpt password_pbkdf2 pgp png reboot regexp search search_fs_uuid search_fs_file search_label serial sleep syslinuxcfg test tftp video xfs zstd tpm" + grub2-mkimage -d /usr/lib/grub/arm64-efi -O arm64-efi -p /EFI/openEuler --pubkey "${WORKDIR}/gpg.key" --output "${WORKDIR}/grubaa64.efi" -c "${WORKDIR}/grub.init.cfg" --sbat "${WORKDIR}/sbat.csv" $MODULES 2>&1 | tee "${WORKDIR}/mkimage.log" + fi + + if [ $? -ne 0 ]; then + echo "create grubxx.efi failed" + return 7 + fi +} + +create_new_grubxx_efi diff --git a/scripts/dm-verity/dm_verity.sh b/scripts/dm-verity/dm_verity.sh new file mode 100644 index 00000000..e9b8ef85 --- /dev/null +++ b/scripts/dm-verity/dm_verity.sh @@ -0,0 +1,360 @@ +#!/bin/bash +## Copyright (c) Huawei Technologies Co., Ltd. 2022. All rights reserved. +# KubeOS is licensed under the Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# http://license.coscl.org.cn/MulanPSL2 +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR +# PURPOSE. +## See the Mulan PSL v2 for more details. + +set -e + +CURDIR=$(cd "$(dirname $0)";pwd) +PWDDD=$(cd "$CURDIR/"; pwd) +KEYDIR="$PWDDD/dm-verity/keys" +CERTDB="$KEYDIR/certdb" +BIOSkeyname="rsa4BIOS" +WORKDIR="$PWDDD/dm-verity/tmp" +GPGkeyid="gpgKey4kubeos" +GPG_KEY="" + + +function keys_exist() { + keyExist=True + if [ ! -d "${KEYDIR}" ]; then + keyExist=False + mkdir -p "${KEYDIR}" + else + for file in "${BIOSkeyname}.der" "gpg.key" "gpg.log" + do + if [ ! "$(find "${KEYDIR}" -name "${file}")" ]; then + keyExist=False + break + fi + done + if [ ! -d "${CERTDB}" ]; then + keyExist=False + fi + fi + echo ${keyExist} +} + + +function gpg_key_gen() { + + GPG_PASSWORD=$1 + + id=$(gpg --list-keys | grep "${GPGkeyid}" | awk '{ print $3 }') + if [ "$id" == ${GPGkeyid} ];then + fgpt=$(gpg --with-colons --fingerprint gpgKey4kubeos | grep -m 1 "^fpr" | sed -n 's/^fpr:::::::::\([[:alnum:]]\+\):/\1/p') + gpg --batch --yes --delete-secret-keys "$fgpt" + gpg --batch --yes --delete-keys "$fgpt" + fi + + cat > "${KEYDIR}/gpg.batch.file" << EOF +Key-Type: RSA +Key-Length: 4096 +Subkey-Type: RSA +Subkey-Length: 4096 +Name-Real: ${GPGkeyid} +Expire-Date: 0 +Passphrase: ${GPG_PASSWORD} +EOF + + gpg --batch --gen-key "${KEYDIR}/gpg.batch.file" + gpg --list-keys --keyid-format LONG ${GPGkeyid} | grep pub > "${KEYDIR}/gpg.log" + GPG_KEY=$(gpg --list-keys --keyid-format LONG ${GPGkeyid} | grep pub | awk -F 'rsa4096/' '{print $2}' | cut -b 1-16) + if [ "$GPG_KEY" = "" ]; then + echo "GPG-key-gen ID failed" + return 7 + fi + gpg --export "$GPG_KEY" > "${KEYDIR}/gpg.key" + rm -f "${KEYDIR}/gpg.batch.file" + if [ $? -ne 0 ]; then + echo "GPG-key-gen failed" + return 7 + fi +} + + +function BIOS_key_gen() { + + PIN_PASSWORD=$1 + keyname=$BIOSkeyname + + if [ -d "${CERTDB}" ]; then + rm -rf "${CERTDB}" + fi + mkdir -p "${CERTDB}" + cat > "${KEYDIR}/pinfile" << EOF +$PIN_PASSWORD +EOF + + openssl genrsa -out "${KEYDIR}/${keyname}.key" 4096 + openssl req -new -key "${KEYDIR}/${keyname}.key" -out "${KEYDIR}/${keyname}.csr" -subj '/C=AA/ST=BB/O=CC/OU=DD/CN=BIOS-cert-for-kubeos-secure-boot' + openssl x509 -req -days 365 -in "${KEYDIR}/${keyname}.csr" -signkey "${KEYDIR}/${keyname}.key" -out "${KEYDIR}/${keyname}.crt" + openssl x509 -in "${KEYDIR}/${keyname}.crt" -out "${KEYDIR}/${keyname}.der" -outform der + + certutil -N -d "${CERTDB}" -f "${KEYDIR}/pinfile" + certutil -A -n ${keyname} -d "${CERTDB}" -t CT,CT,CT -i "${KEYDIR}/${keyname}.crt" -f "${KEYDIR}/pinfile" + openssl pkcs12 -export -out "${KEYDIR}/${keyname}.p12" -inkey "${KEYDIR}/${keyname}.key" -in "${KEYDIR}/${keyname}.crt" -password pass:"${PIN_PASSWORD}" + pk12util -d "${CERTDB}" -i "${KEYDIR}/${keyname}.p12" -w "${KEYDIR}/pinfile" -k "${KEYDIR}/pinfile" + + rm -f "${KEYDIR}/pinfile" + rm -f "${KEYDIR}/${keyname}.p12" + rm -f "${KEYDIR}/${keyname}.crt" + rm -f "${KEYDIR}/${keyname}.csr" + rm -f "${KEYDIR}/${keyname}.key" + + if [ $? -ne 0 ]; then + echo "BIOS-key-gen failed" + return 7 + fi +} + + +function create_new_grubxx_efi() { + + GRUB_PASSWORD=$2 + GPG_PASSWORD=$1 + GRUB_version=2.06 + + GRUB_PASSWORD_HASH=$(echo -e "$GRUB_PASSWORD\n$GRUB_PASSWORD" | grub2-mkpasswd-pbkdf2 | grep -o "grub.*") + + loopN=$(losetup -f) + losetup -P "$loopN" "${PWDDD}/system.img" + bootUUID=$(blkid | grep "${loopN}p1" | awk -F ' UUID=' '{print $2}' | cut -b 2-10) + losetup -d "${loopN}" + + cat > "${WORKDIR}/grub.init.cfg" << EOF +#set debug=linux,linuxefi,crypt +#export debug +set check_signatures=enforce +export check_signatures +set superusers=root +export superusers +set prefix='/EFI/openEuler' +export prefix +password_pbkdf2 root $GRUB_PASSWORD_HASH +set root='hd0,gpt1' +search --no-floppy --fs-uuid --set=root $bootUUID +echo "now in grub-init......1....." +configfile /EFI/openEuler/grub.cfg +echo /EFI/openEuler/grub.cfg did not boot the system, rebooting the system in 10 seconds.. +sleep 10 +reboot +EOF + + cat > "${WORKDIR}/sbat.csv" << EOF +sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md +grub,4,Free Software Foundation,grub,$GRUB_version,https//www.gnu.org/software/grub/ +grub.openeuler,1,The openEuler Project,grub2,$GRUB_version-0,https://gitee.com/src-openeuler/grub2 +EOF + + gpg --pinentry-mode=loopback --passphrase "${GPG_PASSWORD}" --default-key "$GPG_KEY" --detach-sign "${WORKDIR}/grub.init.cfg" + + if [ $? -ne 0 ]; then + echo "prepare new grub files failed" + return 7 + fi +} + +function sign_efi_imgs() { + + PIN_PASSWORD=$1 + GRUB_PASSWORD2=$3 + GPG_PASSWORD=$2 + cat > "${WORKDIR}/pinfile" << EOF +$PIN_PASSWORD +EOF + + tmpRoot="${WORKDIR}/tmproot" + tmpBoot="${WORKDIR}/tmpboot" + mkdir -p "${tmpRoot}" + mkdir -p "${tmpBoot}" + + loopX=$(losetup -f) + losetup -P "${loopX}" "$PWDDD/system.img" + mount "${loopX}p1" "$tmpBoot" + mount "${loopX}p2" "$tmpRoot" + + ARCH=$(arch) + suffix= + if [ "$ARCH" == "x86_64" ]; then + suffix="x64.efi" + elif [ "$ARCH" == "aarch64" ]; then + suffix="aa64.efi" + else + echo "ARCH $ARCH not support currently" + return 7 + fi + + mkdir -p "$tmpRoot/tmp4grub" + cp "${WORKDIR}/grub.init.cfg" "$tmpRoot/tmp4grub/grub.init.cfg" + cp "${WORKDIR}/grub.init.cfg.sig" "$tmpRoot/tmp4grub/grub.init.cfg.sig" + cp "${WORKDIR}/sbat.csv" "$tmpRoot/tmp4grub/sbat.csv" + cp "${KEYDIR}/gpg.key" "$tmpRoot/tmp4grub/gpg.key" + cp "${PWDDD}/dm-verity/chroot_new_grub.sh" "$tmpRoot/chroot_new_grub.sh" + chroot "$tmpRoot" bash /chroot_new_grub.sh + cp "$tmpRoot/tmp4grub/grub$suffix" "${WORKDIR}" + rm -rf "$tmpRoot/tmp4grub" + rm -f "$tmpRoot/chroot_new_grub.sh" + + bootuuid=$(blkid | grep "${loopX}p1" | awk -F ' UUID=' '{print $2}' | cut -b 2-10) + sed -i "s/What=\/dev\/disk\/by-label\/BOOT/What=\/dev\/disk\/by-uuid\/$bootuuid/g" "$tmpRoot/usr/lib/systemd/system/boot-efi.mount" + + if [ $? -ne 0 ]; then + echo "create grubxx.efi failed" + return 7 + fi + + IMGs="shim fb mm" + for img in $IMGs + do + /bin/cp "$tmpBoot/EFI/openEuler/$img$suffix" "${WORKDIR}" + done + + IMGs="$IMGs grub" + for img in $IMGs + do + pesign -n "${CERTDB}" -c ${BIOSkeyname} --pinfile "${WORKDIR}/pinfile" -s -i "$WORKDIR/$img$suffix" -o "${WORKDIR}/$img$suffix.signed" + /bin/cp "${WORKDIR}/$img$suffix.signed" "$tmpBoot/EFI/openEuler/$img$suffix" + done + + if [ $? -ne 0 ]; then + echo "pesign efi failed" + return 7 + fi + + /bin/cp "$PWDDD/grub.cfg" "${WORKDIR}" + if [ "$ARCH" == "x86_64" ]; then + /bin/cp "$tmpRoot/boot/vmlinuz" "${WORKDIR}" + /bin/cp "$tmpRoot/boot/initramfs-verity.img" "${WORKDIR}" + elif [ "$ARCH" == "aarch64" ]; then + /bin/cp "$tmpRoot/boot/vmlinuz" "${WORKDIR}/vmlinuz.gz" + /bin/cp "$tmpRoot/boot/initramfs-verity.img" "${WORKDIR}/initramfs-verity.img" + gzip -d "${WORKDIR}/vmlinuz.gz" + else + echo "ARCH $ARCH not support currently" + fi + + if [ $? -ne 0 ]; then + echo "copy/gzip -d failed" + return 7 + fi + + pesign -n "${CERTDB}" -c ${BIOSkeyname} --pinfile "${WORKDIR}/pinfile" -s -i "$WORKDIR/vmlinuz" -o "${WORKDIR}/vmlinuz.signed" + gpg --pinentry-mode=loopback --passphrase "${GPG_PASSWORD}" --default-key "$GPG_KEY" --detach-sign "${WORKDIR}/vmlinuz.signed" + gpg --pinentry-mode=loopback --passphrase "${GPG_PASSWORD}" --default-key "$GPG_KEY" --detach-sign "${WORKDIR}/initramfs-verity.img" + + if [ $? -ne 0 ]; then + echo "gpg sign failed" + return 7 + fi + + if [ "$ARCH" == "x86_64" ]; then + /bin/cp "${WORKDIR}/vmlinuz.signed" "$tmpRoot/boot/vmlinuz" + /bin/cp "${WORKDIR}/vmlinuz.signed.sig" "$tmpRoot/boot/vmlinuz.sig" + /bin/cp "${WORKDIR}/initramfs-verity.img" "$tmpRoot/boot/initramfs-verity.img" + /bin/cp "${WORKDIR}/initramfs-verity.img.sig" "$tmpRoot/boot/initramfs-verity.img.sig" + elif [ "$ARCH" == "aarch64" ]; then + gzip "${WORKDIR}/vmlinuz.signed" + /bin/cp "${WORKDIR}/vmlinuz.signed.gz" "$tmpRoot/boot/vmlinuz" + /bin/cp "${WORKDIR}/vmlinuz.signed.sig" "$tmpRoot/boot/vmlinuz.sig" + /bin/cp "${WORKDIR}/initramfs-verity.img" "$tmpRoot/boot/initramfs-verity.img" + /bin/cp "${WORKDIR}/initramfs-verity.img.sig" "$tmpRoot/boot/initramfs-verity.img.sig" + else + echo "ARCH $ARCH not support currently" + fi + + if [ $? -ne 0 ]; then + echo "copy/gzip back(vmlinuz/initramfs) failed" + return 7 + fi + + ssh-keygen -t rsa -f "$tmpRoot/etc/ssh/ssh_host_rsa_key" -N '' + ssh-keygen -t ecdsa -f "$tmpRoot/etc/ssh/ssh_host_ecdsa_key" -N '' + ssh-keygen -t ed25519 -f "$tmpRoot/etc/ssh/ssh_host_ed25519_key" -N '' + sync + umount "$tmpRoot" + + veritysetup format "${loopX}p2" "${loopX}p3" --root-hash-file="${WORKDIR}/roothash" + veritysetup verify "${loopX}p2" "${loopX}p3" --root-hash-file="${WORKDIR}/roothash" --debug + + dmvroothash=$(cat "${WORKDIR}/roothash") + + vzlines=$(grep -n boot/vmlinuz "${WORKDIR}/grub.cfg" | cut -d : -f1) + for ln in $vzlines + do + ori=$(sed -n "${ln}p" "${WORKDIR}/grub.cfg") + sed -i "${ln}c \ ${ori} dmvroothash=${dmvroothash}" "${WORKDIR}/grub.cfg" + done + + GRUB_PASSWORD_HASH2=$(echo -e "$GRUB_PASSWORD2\n$GRUB_PASSWORD2" | grub2-mkpasswd-pbkdf2 | grep -o "grub.*") + grub2pwhline=$(awk '/password_pbkdf2/{print NR}' "${WORKDIR}/grub.cfg") + oripwh=$(sed -n "${grub2pwhline}p" "${WORKDIR}/grub.cfg") + sed -i "${grub2pwhline}c ${oripwh} ${GRUB_PASSWORD_HASH2}" "${WORKDIR}/grub.cfg" + + gpg --pinentry-mode=loopback --passphrase "${GPG_PASSWORD}" --default-key "$GPG_KEY" --detach-sign "${WORKDIR}/grub.cfg" + + if [ $? -ne 0 ]; then + echo "modify grub.cfg failed" + return 7 + fi + + /bin/cp "${WORKDIR}/grub.cfg" "$tmpBoot/EFI/openEuler/grub.cfg" + /bin/cp "${WORKDIR}/grub.cfg.sig" "$tmpBoot/EFI/openEuler/grub.cfg.sig" + /bin/cp "$tmpBoot/EFI/openEuler/fb$suffix" "$tmpBoot/EFI/BOOT/fb$suffix" + /bin/cp "$tmpBoot/EFI/openEuler/mm$suffix" "$tmpBoot/EFI/BOOT/mm$suffix" + if [ "$ARCH" == "x86_64" ]; then + /bin/cp "$tmpBoot/EFI/openEuler/shim$suffix" "$tmpBoot/EFI/BOOT/BOOTX64.EFI" + elif [ "$ARCH" == "aarch64" ]; then + /bin/cp "$tmpBoot/EFI/openEuler/shim$suffix" "$tmpBoot/EFI/BOOT/BOOTAA64.EFI" + else + echo "ARCH $ARCH not support currently" + return 7 + fi + /bin/cp "${KEYDIR}/${BIOSkeyname}.der" "$tmpBoot/EFI/${BIOSkeyname}.der" + if [ $? -ne 0 ]; then + echo "copy back efi failed" + return 7 + fi + + sync + umount "$tmpBoot" + dd if="${loopX}p2" of=update-root.img bs=8M + dd if="${loopX}p1" of=update-boot.img bs=8M + dd if="${loopX}p3" of=update-hash.img bs=8M + losetup -D + rm -rf "${WORKDIR}" +} + + +function dmvmain() { + set -e + umask 0177 + + if [ -d "${WORKDIR}" ]; then + rm -rf "${WORKDIR}" + fi + mkdir -m 750 -p "${WORKDIR}" + + BIOSpwd=$1 + GPGpwd=$2 + GRUBpwd=$3 + if [ "$(keys_exist)" == "False" ]; then + rm -rf "${KEYDIR}" + mkdir -p "${KEYDIR}" + gpg_key_gen "$GPGpwd" + BIOS_key_gen "$BIOSpwd" + fi + + GPG_KEY=$(gpg --list-keys --keyid-format LONG ${GPGkeyid} | grep pub | awk -F 'rsa4096/' '{print $2}' | cut -b 1-16) + rm -f "${KEYDIR}/gpg.key" + gpg --export "$GPG_KEY" > "${KEYDIR}/gpg.key" + create_new_grubxx_efi "$GPGpwd" "$GRUBpwd" + sign_efi_imgs "$BIOSpwd" "$GPGpwd" "$GRUBpwd" + qemu-img convert "$PWDDD/system.img" -O qcow2 "$PWDDD/system.qcow2" +} diff --git a/scripts/dm-verity/grub.cfg b/scripts/dm-verity/grub.cfg new file mode 100644 index 00000000..27c50536 --- /dev/null +++ b/scripts/dm-verity/grub.cfg @@ -0,0 +1,133 @@ +## Copyright (c) Huawei Technologies Co., Ltd. 2022. All rights reserved. +# KubeOS is licensed under the Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# http://license.coscl.org.cn/MulanPSL2 +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR +# PURPOSE. +## See the Mulan PSL v2 for more details. +set pager=1 + +set superusers="root" +export superusers +password_pbkdf2 root + +WHITELIST="boot_success saved_entry boot_indeterminate prev_saved_entry next_entry feature_menuentry_id boot_once feature_all_video_module menu_show_once feature_timeout_style menu_auto_hide menu_hide_ok fastboot config_directory" + +if [ -f ${prefix}/grubenv ]; then + load_env -f ${prefix}/grubenv --skip-sig $WHITELIST +fi +if [ "${next_entry}" ] ; then + set default="${next_entry}" + set next_entry= + save_env next_entry + set boot_once=true +else + set default="${saved_entry}" +fi + +if [ x"${feature_menuentry_id}" = xy ]; then + menuentry_id_option="--id" +else + menuentry_id_option="" +fi + +export menuentry_id_option + +if [ "${prev_saved_entry}" ]; then + set saved_entry="${prev_saved_entry}" + save_env saved_entry + set prev_saved_entry= + save_env prev_saved_entry + set boot_once=true +fi + +terminal_output console +if [ x$feature_timeout_style = xy ] ; then + set timeout_style=menu + set timeout=5 +else + set timeout=5 +fi + +menuentry 'A' --class KubeOS --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'KubeOS-A' { + set gfxpayload=keep + set root='hd0,gpt2' + linux /boot/vmlinuz root=/dev/vda2 ro rootfstype=ext4 nomodeset quiet oops=panic softlockup_panic=1 nmi_watchdog=1 rd.shell=0 selinux=0 crashkernel=256M panic=3 console=ttyS0 apparmor=0 + initrd /boot/initramfs-verity.img +} + +menuentry 'B' --class KubeOS --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'KubeOS-B' { + set gfxpayload=keep + set root='hd0,gpt5' + linux /boot/vmlinuz root=/dev/vda5 ro rootfstype=ext4 nomodeset quiet oops=panic softlockup_panic=1 nmi_watchdog=1 rd.shell=0 selinux=0 crashkernel=256M panic=3 console=ttyS0 apparmor=0 + initrd /boot/initramfs-verity.img +} + +### END /etc/grub.d/10_linux ### + +### BEGIN /etc/grub.d/10_reset_boot_success ### +# Hiding the menu is ok if last boot was ok or if this is a first boot attempt to boot the entry +if [ "${boot_success}" = "1" -o "${boot_indeterminate}" = "1" ]; then + set menu_hide_ok=1 +else + set menu_hide_ok=0 +fi +# Reset boot_indeterminate after a successful boot +if [ "${boot_success}" = "1" ] ; then + set boot_indeterminate=0 +# Avoid boot_indeterminate causing the menu to be hidden more then once +elif [ "${boot_indeterminate}" = "1" ]; then + set boot_indeterminate=2 +fi +# Reset boot_success for current boot +set boot_success=0 +save_env boot_success boot_indeterminate +### END /etc/grub.d/10_reset_boot_success ### + +### BEGIN /etc/grub.d/12_menu_auto_hide ### +if [ x$feature_timeout_style = xy ] ; then + if [ "${menu_show_once}" ]; then + unset menu_show_once + save_env menu_show_once + set timeout_style=menu + set timeout=60 + elif [ "${menu_auto_hide}" -a "${menu_hide_ok}" = "1" ]; then + set orig_timeout_style=${timeout_style} + set orig_timeout=${timeout} + if [ "${fastboot}" = "1" ]; then + # timeout_style=menu + timeout=0 avoids the countdown code keypress check + set timeout_style=menu + set timeout=0 + else + set timeout_style=hidden + set timeout=1 + fi + fi +fi +### END /etc/grub.d/12_menu_auto_hide ### + +### BEGIN /etc/grub.d/20_linux_xen ### +### END /etc/grub.d/20_linux_xen ### + +### BEGIN /etc/grub.d/20_ppc_terminfo ### +### END /etc/grub.d/20_ppc_terminfo ### + +### BEGIN /etc/grub.d/30_uefi-firmware ### +### END /etc/grub.d/30_uefi-firmware ### + +### BEGIN /etc/grub.d/40_custom ### +# This file provides an easy way to add custom menu entries. Simply type the +# menu entries you want to add after this comment. Be careful not to change +# the 'exec tail' line above. +### END /etc/grub.d/40_custom ### + +### BEGIN /etc/grub.d/41_custom ### +if [ -f ${config_directory}/custom.cfg ]; then + source ${config_directory}/custom.cfg +elif [ -z "${config_directory}" -a -f ${prefix}/custom.cfg ]; then + source ${prefix}/custom.cfg; +fi +### END /etc/grub.d/41_custom ### + diff --git a/scripts/grub.cfg b/scripts/grub.cfg index 984b1616..456ec2d1 100644 --- a/scripts/grub.cfg +++ b/scripts/grub.cfg @@ -69,7 +69,7 @@ if [ x$feature_timeout_style = xy ] ; then else set timeout=5 fi -set superusers="root" +#set superusers="root" ### END /etc/grub.d/00_header ### ### BEGIN /etc/grub.d/01_users ### diff --git a/scripts/kbimg.sh b/scripts/kbimg.sh index de7bb922..aaf225ce 100644 --- a/scripts/kbimg.sh +++ b/scripts/kbimg.sh @@ -21,6 +21,10 @@ DOCKERFILE="" LOCK=./test.lock ADMIN_CONTAINER_DIR=./admin-container BOOT_MODE=efi +DMV_MODE=0 +RSApw="" +GPGpw="" +GRUBpw="" source common/globalVariables.sh &>/dev/null source common/log.sh &>/dev/null @@ -28,6 +32,7 @@ source common/utils.sh &>/dev/null source create/rootfsCreate.sh &>/dev/null source create/imageCreate.sh &>/dev/null source 00bootup/Global.cfg &>/dev/null +source dm-verity/dm_verity.sh &>/dev/null function show_options() { cat << EOF @@ -92,6 +97,13 @@ options: -e os encrypted password -d docker image like repository/name:tag -l boot to legacy BIOS mode, if not specify, then UEFI mode + -V dm-verity support [UPPER case -V], + V=0(default) with no dm-verity + V=2 dm-verity and secure-boot (require UEFI mode) + if V=2, the following also required: + -k password for private keys to sign secure-boot EFI images + -K password for private keys to sign grub-config files + -G password for entering GRUB shell -h,--help show help information EOF } @@ -125,16 +137,22 @@ function test_lock() { function clean_space() { delete_dir "${RPM_ROOT}" delete_dir "${TMP_MOUNT_PATH}" + delete_dir "${PWD}/dm-verity/tmp" delete_file os.tar rm -rf "${LOCK}" delete_file ${ADMIN_CONTAINER_DIR}/hostshell } function clean_img() { - delete_file system.img + losetup -D + delete_file system.img delete_file update.img delete_file initramfs.img delete_file kubeos.tar + delete_file update-root.img + delete_file update-boot.img + delete_file update-hash.img + delete_file update-roothash } function verify_upgrade_image_input() { @@ -196,7 +214,7 @@ function verify_repo_input() { fi done set -eE - while getopts "p:v:e:b:l" opt + while getopts "p:v:e:b:V:k:K:G:l" opt do case $opt in p) @@ -215,6 +233,22 @@ function verify_repo_input() { # encrypted password contains special characters.,not verify. PASSWD="$OPTARG" ;; + V) + # check when used + DMV_MODE="$OPTARG" + ;; + k) + # check when used + RSApw="$OPTARG" + ;; + K) + # check when used + GPGpw="$OPTARG" + ;; + G) + # check when used + GRUBpw="$OPTARG" + ;; l) BOOT_MODE=legacy ;; @@ -225,6 +259,24 @@ function verify_repo_input() { ;; esac done + if [ ${DMV_MODE} == "2" ]; then + DMV_MODE="${DMV_MODE}" + else + DMV_MODE=0 + fi + if [ ${DMV_MODE} == "2" ]; then + set +eE + for i in "k" "K" "G" + do + echo "$@" | grep -q "\-$i " + if [ "$?" -ne 0 ];then + log_error_print " ** If V=2 **, option -$i is mandatory, please check input" + show_vm_pxe_image_usage + exit 3 + fi + done + fi + } function verify_docker_input() { @@ -301,11 +353,15 @@ function verify_create_input() { fi fi check_disk_space "vm" - if [[ $# -eq 8 || $# -eq 9 ]]; then + if [ $# -ge 8 ]; then verify_repo_input "$@" check_repo_path "${REPO}" check_binary_exist "${AGENT_PATH}" - create_vm_img "repo" "${REPO}" "${VERSION}" "${AGENT_PATH}" "${PASSWD}" "${BOOT_MODE}" + if [ ${DMV_MODE} == "2" ]; then + create_vm_img "repo" "${REPO}" "${VERSION}" "${AGENT_PATH}" "${PASSWD}" "${BOOT_MODE}" "${DMV_MODE}" "${RSApw}" "${GPGpw}" "${GRUBpw}" + else + create_vm_img "repo" "${REPO}" "${VERSION}" "${AGENT_PATH}" "${PASSWD}" "${BOOT_MODE}" "${DMV_MODE}" + fi elif [ $# -eq 2 ]; then verify_docker_input "$@" check_docker_exist "${DOCKER_IMG}" diff --git a/scripts/rpmlist b/scripts/rpmlist index fb6f2381..460b4547 100644 --- a/scripts/rpmlist +++ b/scripts/rpmlist @@ -19,4 +19,6 @@ dracut coreutils gawk parted -dosfstools \ No newline at end of file +dosfstools +efibootmgr +kbd diff --git a/scripts/set_in_chroot.sh b/scripts/set_in_chroot.sh index 80b5a91b..6842785b 100644 --- a/scripts/set_in_chroot.sh +++ b/scripts/set_in_chroot.sh @@ -17,4 +17,10 @@ cat /etc/shadow_bak >> /etc/shadow rm -rf /etc/shadow_bak dracut -f -v --add bootup /initramfs.img --kver `ls /lib/modules` -rm -rf /usr/lib/dracut/modules.d/00bootup \ No newline at end of file +rm -rf /usr/lib/dracut/modules.d/00bootup + +if [ -d "/usr/lib/dracut/modules.d/05dmverity" ]; then + dracut -f -v --add dmverity /boot/initramfs-verity.img --kver `ls /lib/modules` + rm -rf /usr/lib/dracut/modules.d/05dmverity +fi +grub2-editenv /boot/efi/EFI/openEuler/grubenv create -- Gitee