Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: verify kmod signatures for dual-sign #218

Merged
merged 10 commits into from
Jul 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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