Skip to content

Commit

Permalink
feat: verify kmod signatures for dual-sign (#218)
Browse files Browse the repository at this point in the history
  • Loading branch information
m2Giles authored Jul 20, 2024
1 parent 20fce9f commit 7c3a5d8
Show file tree
Hide file tree
Showing 11 changed files with 281 additions and 5 deletions.
30 changes: 29 additions & 1 deletion .github/workflows/reusable-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,10 @@ jobs:
for TAG in "${COMMIT_TAGS[@]}"; do
echo "${TAG}"
done
default_tag=${COMMIT_TAGS[0]}
alias_tags=("${COMMIT_TAGS[@]}")
else
default_tag=${BUILD_TAGS[0]}
alias_tags=("${BUILD_TAGS[@]}")
fi
Expand All @@ -154,6 +155,7 @@ jobs:
done
echo "alias_tags=${alias_tags[*]}" >> $GITHUB_OUTPUT
echo "default_tag=$default_tag" >> $GITHUB_ENV
# Build metadata
- name: Image Metadata
Expand Down Expand Up @@ -206,6 +208,32 @@ jobs:
labels: ${{ steps.meta.outputs.labels }}
oci: false

- name: Build Test Image
uses: redhat-actions/buildah-build@v2
with:
containerfiles: |
./Containerfile.test
image: akmods-test
tags: latest
build-args: |
BUILDER_IMAGE=${{ env.BUILDER_IMAGE }}
KERNEL_ORG=${{ github.repository_owner }}
KERNEL_FLAVOR=${{ matrix.kernel_flavor }}
FEDORA_MAJOR_VERSION=${{ matrix.fedora_version }}
INPUT_AKMODS=${{ env.IMAGE_NAME }}
INPUT_TAG=${{ env.default_tag }}
DUAL_SIGN=true
oci: false

- name: Test Akmods Signature
id: test_akmods
shell: bash
run: |
if ! podman run akmods-test:latest; then
echo "Signatures Failed"
exit 1
fi
# Workaround bug where capital letters in your GitHub username make it impossible to push to GHCR.
# https://github.com/macbre/push-to-ghcr/issues/12
- name: Lowercase Registry
Expand Down
2 changes: 1 addition & 1 deletion Containerfile.common
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ ARG KERNEL_FLAVOR="${KERNEL_FLAVOR:-main}"
ARG RPMFUSION_MIRROR=""
ARG DUAL_SIGN="true"

COPY build*.sh dual-sign.sh /tmp/
COPY build*.sh dual-sign*.sh /tmp/
COPY certs /tmp/certs

# cached kernel rpms
Expand Down
2 changes: 1 addition & 1 deletion Containerfile.extra
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ ARG KERNEL_FLAVOR="${KERNEL_FLAVOR:-main}"
ARG RPMFUSION_MIRROR=""
ARG DUAL_SIGN="true"

COPY build*.sh dual-sign.sh /tmp/
COPY build*.sh dual-sign*.sh /tmp/
COPY certs /tmp/certs

# cached kernel rpms
Expand Down
2 changes: 1 addition & 1 deletion Containerfile.nvidia
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ ARG KERNEL_FLAVOR="${KERNEL_FLAVOR:-main}"
ARG RPMFUSION_MIRROR=""
ARG DUAL_SIGN="true"

COPY build*.sh dual-sign.sh /tmp/
COPY build*.sh dual-sign*.sh /tmp/
COPY certs /tmp/certs

# cached kernel rpms
Expand Down
40 changes: 40 additions & 0 deletions Containerfile.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
###
### Containerfile.test - used to test akmods
###

ARG FEDORA_MAJOR_VERSION="${FEDORA_MAJOR_VERSION:-40}"
ARG KERNEL_FLAVOR="${KERNEL_FLAVOR:-main}"
ARG KERNEL_IMAGE="${KERNEL_IMAGE:-${KERNEL_FLAVOR}-kernel}"
ARG KERNEL_ORG="${KERNEL_ORG:-ublue-os}"
ARG KERNEL_BASE="ghcr.io/${KERNEL_ORG}/${KERNEL_IMAGE}:${FEDORA_MAJOR_VERSION}"
ARG BUILDER_IMAGE="${BUILDER_IMAGE:-quay.io/fedora/fedora}"
ARG BUILDER_BASE="${BUILDER_IMAGE}:${FEDORA_MAJOR_VERSION}"
ARG INPUT_AKMODS="${INPUT_AKMODS:-akmods}"
ARG INPUT_TAG="${INPUT_TAG:-${KERNEL_FLAVOR}-${FEDORA_MAJOR_VERSION}}"
ARG INPUT_BASE="${INPUT_AKMODS}:${INPUT_TAG}"
FROM ${KERNEL_BASE} AS kernel_cache
FROM ${INPUT_BASE} AS akmods_cache
FROM ${BUILDER_BASE} AS tester

ARG FEDORA_MAJOR_VERSION="${FEDORA_MAJOR_VERSION:-40}"
ARG KERNEL_FLAVOR="${KERNEL_FLAVOR:-main}"
ARG RPMFUSION_MIRROR=""
ARG DUAL_SIGN="true"

COPY test-prep.sh dual-sign-check.sh /tmp/
COPY check-signatures.sh /
COPY certs /tmp/certs

# cached kernel rpms
COPY --from=kernel_cache /tmp/rpms /tmp/kernel_cache
COPY --from=akmods_cache /rpms /tmp/akmods-rpms

RUN --mount=type=cache,dst=/var/cache/dnf \
if grep -qv "surface" <<< "${KERNEL_FLAVOR}"; then \
export KERNEL_NAME="kernel" \
; else \
export KERNEL_NAME="kernel-surface" \
; fi && \
/tmp/test-prep.sh

CMD ["/check-signatures.sh"]
2 changes: 1 addition & 1 deletion Containerfile.zfs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ ARG DUAL_SIGN="true"
ARG RPMFUSION_MIRROR=""
ARG ZFS_MINOR_VERSION="${ZFS_MINOR_VERSION:-2.2}"

COPY build*.sh dual-sign-zfs.sh /tmp/
COPY build*.sh dual-sign*.sh /tmp/
COPY certs /tmp/certs

# cached kernel rpms
Expand Down
23 changes: 23 additions & 0 deletions check-signatures.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/usr/bin/bash

source /tmp/info.sh

KERNEL="$(rpm -q "${KERNEL_NAME}" --queryformat '%{VERSION}-%{RELEASE}.%{ARCH}')"
PUBLIC_CHAIN="/tmp/certs/public_key_chain.pem"

for module in /usr/lib/modules/"${KERNEL}"/extra/*/*.ko*;
do
module_basename=${module:0:-3}
module_suffix=${module: -3}
if [[ "$module_suffix" == ".xz" ]]; then
xz --decompress "$module"
/tmp/dual-sign-check.sh "${KERNEL}" "${module_basename}" "${PUBLIC_CHAIN}"
xz -f "${module_basename}"
elif [[ "$module_suffix" == ".gz" ]]; then
gzip -d "$module"
/tmp/dual-sign-check.sh "${KERNEL}" "${module_basename}" "${PUBLIC_CHAIN}"
gzip -9f "${module_basename}"
else
/tmp/dual-sign-check.sh "${KERNEL}" "${module}" "${PUBLIC_CHAIN}"
fi
done
24 changes: 24 additions & 0 deletions dual-sign-check.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/bash

KERNEL="$1"
module="$2"
PUBLIC_CERT="$3"

kmod_sig="/tmp/kmod.sig"
kmod_p7s="/tmp/kmod.p7s"
kmod_data="/tmp/kmod.data"
/usr/src/kernels/"${KERNEL}"/scripts/extract-module-sig.pl -s "${module}" > ${kmod_sig}
openssl pkcs7 -inform der -in ${kmod_sig} -out ${kmod_p7s}
/usr/src/kernels/"${KERNEL}"/scripts/extract-module-sig.pl -0 "${module}" > ${kmod_data}
if openssl cms -verify -binary -inform PEM \
-in ${kmod_p7s} \
-content ${kmod_data} \
-certfile "${PUBLIC_CERT}" \
-out "/dev/null" \
-nointern -noverify
then
echo "Signature Verified for ${module}"
else
echo "Signature Failed for ${module}"
exit 1
fi
3 changes: 3 additions & 0 deletions dual-sign-zfs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,18 @@ if [[ "${DUAL_SIGN}" == "true" ]]; then
xz --decompress "$module"
openssl cms -sign -signer "${SIGNING_KEY_1}" -signer "${SIGNING_KEY_2}" -binary -in "$module_basename" -outform DER -out "${module_basename}.cms" -nocerts -noattr -nosmimecap
/usr/src/kernels/"${KERNEL}"/scripts/sign-file -s "${module_basename}.cms" sha256 "${PUBLIC_CHAIN}" "${module_basename}"
/tmp/dual-sign-check.sh "${KERNEL}" "${module_basename}" "${PUBLIC_CHAIN}"
xz -f "${module_basename}"
elif [[ "$module_suffix" == ".gz" ]]; then
gzip -d "$module"
openssl cms -sign -signer "${SIGNING_KEY_1}" -signer "${SIGNING_KEY_2}" -binary -in "$module_basename" -outform DER -out "${module_basename}.cms" -nocerts -noattr -nosmimecap
/usr/src/kernels/"${KERNEL}"/scripts/sign-file -s "${module_basename}.cms" sha256 "${PUBLIC_CHAIN}" "${module_basename}"
/tmp/dual-sign-check.sh "${KERNEL}" "${module_basename}" "${PUBLIC_CHAIN}"
gzip -9f "${module_basename}"
else
openssl cms -sign -signer "${SIGNING_KEY_1}" -signer "${SIGNING_KEY_2}" -binary -in "$module" -outform DER -out "${module}.cms" -nocerts -noattr -nosmimecap
/usr/src/kernels/"${KERNEL}"/scripts/sign-file -s "${module}.cms" sha256 "${PUBLIC_CHAIN}" "${module}"
/tmp/dual-sign-check.sh "${KERNEL}" "${module}" "${PUBLIC_CHAIN}"
fi
done
rpmrebuild --batch /var/cache/rpms/kmods/zfs/kmod-zfs-*.rpm
Expand Down
3 changes: 3 additions & 0 deletions dual-sign.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,18 @@ if [[ "${DUAL_SIGN}" == "true" ]]; then
xz --decompress "$module"
openssl cms -sign -signer "${SIGNING_KEY_1}" -signer "${SIGNING_KEY_2}" -binary -in "$module_basename" -outform DER -out "${module_basename}.cms" -nocerts -noattr -nosmimecap
/usr/src/kernels/"${KERNEL}"/scripts/sign-file -s "${module_basename}.cms" sha256 "${PUBLIC_CHAIN}" "${module_basename}"
/tmp/dual-sign-check.sh "${KERNEL}" "${module_basename}" "${PUBLIC_CHAIN}"
xz -f "${module_basename}"
elif [[ "$module_suffix" == ".gz" ]]; then
gzip -d "$module"
openssl cms -sign -signer "${SIGNING_KEY_1}" -signer "${SIGNING_KEY_2}" -binary -in "$module_basename" -outform DER -out "${module_basename}.cms" -nocerts -noattr -nosmimecap
/usr/src/kernels/"${KERNEL}"/scripts/sign-file -s "${module_basename}.cms" sha256 "${PUBLIC_CHAIN}" "${module_basename}"
/tmp/dual-sign-check.sh "${KERNEL}" "${module_basename}" "${PUBLIC_CHAIN}"
gzip -9f "${module_basename}"
else
openssl cms -sign -signer "${SIGNING_KEY_1}" -signer "${SIGNING_KEY_2}" -binary -in "$module" -outform DER -out "${module}.cms" -nocerts -noattr -nosmimecap
/usr/src/kernels/"${KERNEL}"/scripts/sign-file -s "${module}.cms" sha256 "${PUBLIC_CHAIN}" "${module}"
/tmp/dual-sign-check.sh "${KERNEL}" "${module}" "${PUBLIC_CHAIN}"
fi
done
find /var/cache/akmods -type f -name \kmod-*.rpm
Expand Down
155 changes: 155 additions & 0 deletions test-prep.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
#!/usr/bin/bash

set -oeux pipefail

### PREPARE REPOS
# ARCH="$(rpm -E '%_arch')"
RELEASE="$(rpm -E '%fedora')"

sed -i 's@enabled=1@enabled=0@g' /etc/yum.repos.d/fedora-cisco-openh264.repo

# enable RPMs with alternatives to create them in this image build
mkdir -p /var/lib/alternatives

if [[ -f $(find /tmp/akmods-rpms/ublue-os/ublue-os-*.rpm 2> /dev/null) ]]; then
dnf install -y /tmp/akmods-rpms/ublue-os/ublue-os-*.rpm
fi


# install kernel_cache provided kernel
echo "Installing ${KERNEL_FLAVOR} kernel-cache RPMs..."
# fedora image has no kernel so this needs nothing fancy, just install
dnf install -y /tmp/kernel_cache/*.rpm

if [[ "${KERNEL_FLAVOR}" == "surface" ]]; then
KERNEL_VERSION=$(rpm -q kernel-surface|cut -d '-' -f2-)
else
KERNEL_VERSION=$(rpm -q kernel|cut -d '-' -f2-)
fi

# enable more repos
RPMFUSION_MIRROR_RPMS="https://mirrors.rpmfusion.org"
if [ -n "${RPMFUSION_MIRROR}" ]; then
RPMFUSION_MIRROR_RPMS=${RPMFUSION_MIRROR}
fi

if [[ "${RELEASE}" -ge 41 ]]; then
COPR_RELEASE="rawhide"
else
COPR_RELEASE="${RELEASE}"
fi

curl -Lo /etc/yum.repos.d/_copr_ublue-os_staging.repo \
"https://copr.fedorainfracloud.org/coprs/ublue-os/staging/repo/fedora-${COPR_RELEASE}/ublue-os-staging-fedora-${COPR_RELEASE}.repo"

curl -Lo /etc/yum.repos.d/_copr_kylegospo_oversteer.repo \
"https://copr.fedorainfracloud.org/coprs/kylegospo/oversteer/repo/fedora-${COPR_RELEASE}/kylegospo-oversteer-fedora-${COPR_RELEASE}.repo"

curl -Lo /etc/yum.repos.d/_copr_ublue-os-akmods.repo \
"https://copr.fedorainfracloud.org/coprs/ublue-os/akmods/repo/fedora-${COPR_RELEASE}/ublue-os-akmods-fedora-${COPR_RELEASE}.repo"

curl -Lo /etc/yum.repos.d/negativo17-fedora-multimedia.repo \
"https://negativo17.org/repos/fedora-multimedia.repo"

if [[ -f $(find /tmp/akmods-rpms/kmods/kmod-vhba-*.rpm) ]]; then
curl -LsSf -o /etc/yum.repos.d/_copr_rok-cdemu.repo \
"https://copr.fedorainfracloud.org/coprs/rok/cdemu/repo/fedora-${COPR_RELEASE}/rok-cdemu-fedora-${COPR_RELEASE}.repo"
fi

if [[ -f $(find /tmp/akmods-rpms/kmods/kmod-facetimehd-*.rpm) ]]; then
curl -LsSf -o /etc/yum.repos.d/_copr_mulderje-facetimehd-kmod.repo \
"https://copr.fedorainfracloud.org/coprs/mulderje/facetimehd-kmod/repo/fedora-${COPR_RELEASE}/mulderje-facetimehd-kmod-fedora-${COPR_RELEASE}.repo"
fi

if [[ -f $(find /tmp/akmods-rpms/kmods/kmod-kvmfr-*.rpm) ]]; then
curl -LsSf -o /etc/yum.repos.d/_copr_hikariknight-looking-glass-kvmfr.repo \
"https://copr.fedorainfracloud.org/coprs/hikariknight/looking-glass-kvmfr/repo/fedora-${COPR_RELEASE}/hikariknight-looking-glass-kvmfr-fedora-${COPR_RELEASE}.repo"
fi

if [[ -f $(find /tmp/akmods-rpms/kmods/kmod-nvidia-*.rpm) ]]; then
curl -Lo /etc/yum.repos.d/negativo17-fedora-nvidia.repo \
"https://negativo17.org/repos/fedora-nvidia.repo"
curl -Lo /etc/yum.repos.d/nvidia-container-toolkit.repo \
"https://nvidia.github.io/libnvidia-container/stable/rpm/nvidia-container-toolkit.repo"
curl -Lo /etc/yum.repos.d/nvidia-container.pp \
"https://raw.githubusercontent.com/NVIDIA/dgx-selinux/master/bin/RHEL9/nvidia-container.pp"
curl -Lo /etc/yum.repos.d/eyecantcu-supergfxctl.repo \
"https://copr.fedorainfracloud.org/coprs/eyecantcu/supergfxctl/repo/fedora-${COPR_RELEASE}/eyecantcu-supergfxctl-fedora-${COPR_RELEASE}.repo"
curl -Lo /tmp/nvidia-install.sh \
"https://raw.githubusercontent.com/ublue-os/hwe/main/nvidia-install.sh"
chmod +x /tmp/nvidia-install.sh
sed -i "s@gpgcheck=0@gpgcheck=1@" /etc/yum.repos.d/nvidia-container-toolkit.repo
fi

dnf install -y \
"${RPMFUSION_MIRROR_RPMS}"/free/fedora/rpmfusion-free-release-"${RELEASE}".noarch.rpm \
"${RPMFUSION_MIRROR_RPMS}"/nonfree/fedora/rpmfusion-nonfree-release-"${RELEASE}".noarch.rpm \
fedora-repos-archive \
openssl


# after F41 launches, bump to 42
if [[ "${FEDORA_MAJOR_VERSION}" -ge 41 ]]; then
# pre-release rpmfusion is in a different location
sed -i "s%free/fedora/releases%free/fedora/development%" /etc/yum.repos.d/rpmfusion-*.repo
# pre-release rpmfusion needs to enable testing
sed -i '0,/enabled=0/{s/enabled=0/enabled=1/}' /etc/yum.repos.d/rpmfusion-*-updates-testing.repo
fi

if [ -n "${RPMFUSION_MIRROR}" ]; then
# force use of single rpmfusion mirror
echo "Using single rpmfusion mirror: ${RPMFUSION_MIRROR}"
sed -i.bak "s%^metalink=%#metalink=%" /etc/yum.repos.d/rpmfusion-*.repo
sed -i "s%^#baseurl=http://download1.rpmfusion.org%baseurl=${RPMFUSION_MIRROR}%" /etc/yum.repos.d/rpmfusion-*.repo
fi

if [[ ! -s "/tmp/certs/private_key.priv" ]]; then
echo "WARNING: Using test signing key. Run './generate-akmods-key' for production builds."
cp /tmp/certs/public_key.der{.test,}
fi

openssl x509 -in /tmp/certs/public_key.der -out /tmp/certs/public_key.crt
cat /tmp/certs/public_key.crt > /tmp/certs/public_key_chain.pem
rm -f /tmp/certs/private_key.priv

if [[ "${DUAL_SIGN}" == "true" ]]; then
if [[ ! -s "/tmp/certs/private_key_2.priv" ]]; then
echo "WARNING: Using test signing key. Run './generate-akmods-key' for production builds."
cp /tmp/certs/public_key_2.der{.test,}
fi
openssl x509 -in /tmp/certs/public_key_2.der -out /tmp/certs/public_key_2.crt
rm -f /tmp/certs/public_key_chain.pem
cat /tmp/certs/public_key.crt <(echo) /tmp/certs/public_key_2.crt >> /tmp/certs/public_key_chain.pem
fi

rm -f /tmp/certs/private_key_2.priv

if [[ -f $(find /tmp/akmods-rpms/kmods/kmod-nvidia-*.rpm 2> /dev/null) ]]; then
sed -i '0,/enabled=0/{s/enabled=0/enabled=1/}' /etc/yum.repos.d/eyecantcu-supergfxctl.repo
sed -i '0,/enabled=0/{s/enabled=0/enabled=1/}' /etc/yum.repos.d/negativo17-fedora-nvidia.repo
sed -i '0,/enabled=0/{s/enabled=0/enabled=1/}' /etc/yum.repos.d/nvidia-container-toolkit.repo
source /tmp/akmods-rpms/kmods/nvidia-vars
dnf install -y \
libnvidia-fbc \
libnvidia-ml.i686 \
libva-nvidia-driver \
mesa-vulkan-drivers.i686 \
nvidia-driver \
nvidia-driver-cuda \
nvidia-driver-cuda-libs.i686 \
nvidia-driver-libs.i686 \
nvidia-modprobe \
nvidia-persistenced \
nvidia-settings \
nvidia-container-toolkit \
/tmp/akmods-rpms/kmods/kmod-nvidia-"${KERNEL_VERSION}"-"${NVIDIA_AKMOD_VERSION}".fc"${RELEASE}".rpm
elif [[ -f $(find /tmp/akmods-rpms/kmods/zfs/kmod-*.rpm 2> /dev/null) ]]; then
dnf install -y \
pv \
/tmp/akmods-rpms/kmods/zfs/*.rpm
else
dnf install -y \
/tmp/akmods-rpms/kmods/*.rpm
fi

printf "KERNEL_NAME=%s" "$KERNEL_NAME" >> /tmp/info.sh

0 comments on commit 7c3a5d8

Please sign in to comment.