Skip to content

Commit

Permalink
livepatching: add package for livepatches management (#3687)
Browse files Browse the repository at this point in the history
  • Loading branch information
PawelWMS committed Sep 6, 2022
1 parent ef6062e commit 2bcbca4
Show file tree
Hide file tree
Showing 7 changed files with 236 additions and 1 deletion.
1 change: 1 addition & 0 deletions .github/workflows/validate-cg-manifest.sh
Expand Up @@ -39,6 +39,7 @@ ignore_no_source_tarball=" \
javapackages-tools-meta \
kde-filesystem \
kf5 \
livepatching \
lua-rpm-macros \
mariner-repos \
mariner-rpm-macros \
Expand Down
2 changes: 1 addition & 1 deletion SPECS/LICENSES-AND-NOTICES/LICENSES-MAP.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions SPECS/LICENSES-AND-NOTICES/data/licenses.json
Expand Up @@ -2015,6 +2015,7 @@
"libsafec",
"libuv",
"libxml++",
"livepatching",
"lld",
"lsb-release",
"lttng-consume",
Expand Down
11 changes: 11 additions & 0 deletions SPECS/livepatching/livepatching.service
@@ -0,0 +1,11 @@
[Unit]
Description=Subscribe to kernel livepatches across kernel updates
Before=kpatch.service

[Service]
Type=notify
NotifyAccess=main
ExecStart=/lib/livepatching/livepatching.systemd

[Install]
WantedBy=multi-user.target
6 changes: 6 additions & 0 deletions SPECS/livepatching/livepatching.signatures.json
@@ -0,0 +1,6 @@
{
"Signatures": {
"livepatching.service": "7c1a827df2dfdefb795fab2c1417bc6145604c151b32d9d5987e458427ac1b0b",
"livepatching.systemd": "b248eeb126ce212843d75b01a16bd63157bee8e1ca1ac4f86de6573561a5e069"
}
}
94 changes: 94 additions & 0 deletions SPECS/livepatching/livepatching.spec
@@ -0,0 +1,94 @@
%define livepatching_lib_path %{_libdir}/livepatching

Summary: Set of core livepatching packages for Mariner.
Name: livepatching
Version: 1.0.0
Release: 1%{?dist}
License: MIT
Vendor: Microsoft Corporation
Distribution: Mariner
Group: Applications/Text
URL: https://aka.ms/cbl-mariner
Source0: livepatching.service
Source1: livepatching.systemd

BuildArch: noarch

BuildRequires: systemd

%description
%{summary}

%package filesystem
Summary: Basic directory layout for livepatching packages.

%description filesystem
%{summary}

%package subscription
Summary: Retain livepatches across kernel upgrades.

Requires: %{name}-filesystem = %{version}-%{release}
Requires: coreutils
Requires: grep
Requires: inotify-tools
Requires: kpatch
Requires: systemd
Requires: tdnf

Requires(post): grep
Requires(post): inotify-tools
Requires(post): kpatch
Requires(post): systemd
Requires(post): tdnf

Requires(postun): systemd

Requires(preun): systemd

%description subscription
This package allows your system to retain livepatches across kernel upgrades.
Once a livepatch for the new kernel is installed, it does NOT automatically
pull newer versions of the livepatch for that kernel.

%prep

%install
install -vdm755 %{buildroot}%{_libdir}/systemd/system-preset
echo "enable livepatching.service" > %{buildroot}%{_libdir}/systemd/system-preset/50-livepatching.preset

install -vdm755 %{buildroot}%{_unitdir}
install -D -m 644 %{SOURCE0} %{buildroot}%{_unitdir}/livepatching.service

install -vdm755 %{buildroot}%{livepatching_lib_path}
install -D -m 744 %{SOURCE1} %{buildroot}%{livepatching_lib_path}/livepatching.systemd

%post subscription
%systemd_post livepatching.service
# Only start on initial installation. Upgrade restarts handled by %%postun.
if [ $1 -eq 1 ]
then
systemctl start livepatching.service >/dev/null 2>&1 || :
fi

%preun subscription
%systemd_preun livepatching.service

%postun subscription
%systemd_postun_with_restart livepatching.service
systemctl try-restart livepatching.service >/dev/null 2>&1 || :

%files filesystem
%defattr(-,root,root)
%dir %{livepatching_lib_path}

%files subscription
%defattr(-,root,root)
%{_libdir}/systemd/system-preset/50-livepatching.preset
%{_unitdir}/livepatching.service
%{livepatching_lib_path}/livepatching.systemd

%changelog
* Fri Sep 02 2022 Pawel Winogrodzki <pawelwi@microsoft.com> - 1.0.0-1
- Original version for CBL-Mariner.
- License verified.
122 changes: 122 additions & 0 deletions SPECS/livepatching/livepatching.systemd
@@ -0,0 +1,122 @@
#!/bin/bash
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

install_patch_after_kernel_change() {
local installable_patch="livepatch-$RUNNING_KERNEL_VERSION"
local patch_module_name
local patch_module_path

echo "Making sure patch is installed after a kernel reboot."

if [[ "$RUNNING_KERNEL_VERSION" != "$INSTALLED_KERNEL_VERSION" ]]
then
echo "Running kernel ($RUNNING_KERNEL_VERSION) different than installed kernel ($INSTALLED_KERNEL_VERSION). Nothing to do."
return 0
fi

if ! rpm --quiet -q --whatprovides "$installable_patch"
then
echo "No livepatch package installed for running kernel ($RUNNING_KERNEL_VERSION)."
return 0
fi

patch_module_path=$(rpm -ql --whatprovides "$installable_patch" | grep "ko$")
if [[ ! -f "$patch_module_path" ]]
then
echo "Initial (empty) livepatch installed for kernel ($RUNNING_KERNEL_VERSION) - no livepatch module to install."
return 0
fi

patch_module_name=$(basename "$patch_module_path" | cut -d. -f1)
if patch_installed "$patch_module_name"
then
echo "Patch already installed for the running kernel ($RUNNING_KERNEL_VERSION)."
return 0
fi

kpatch install "$patch_module_path"
}

install_livepatch_package() {
local kernel_version
local patch_package

kernel_version="$1"
patch_package="livepatch = $kernel_version"

echo "Checking if a livepatch is available for kernel version ($kernel_version)."
if ! tdnf -q list available "$patch_package" >/dev/null
then
echo "No livepatches available for kernel version ($kernel_version)."
return 0
fi

echo "Livepatch available for kernel version ($kernel_version). Checking if it's already installed."
if tdnf -q list installed "$patch_package" >/dev/null
then
echo "Livepatch for kernel version ($kernel_version) already installed."
else
echo "Installing livepatch for kernel version ($kernel_version)."

tdnf -q install -y "$patch_package" >/dev/null
fi
}

patch_installed() {
kpatch list | grep -qP "$1.*$RUNNING_KERNEL_VERSION"
}

read_installed_kernel_version() {
realpath /boot/mariner.cfg | grep -oP "(?<=linux-).*(?=\.cfg)"
}

read_running_kernel_version() {
uname -r
}

wait_for_kernel_change() {
local new_kernel_version

echo "Waiting for RPM database changes."

while inotifywait -e close_write /var/lib/rpm/rpmdb.sqlite &>/dev/null
do
echo "Change detected, checking if different kernel got installed."

new_kernel_version=$(read_installed_kernel_version)
if [[ "$INSTALLED_KERNEL_VERSION" != "$new_kernel_version" ]]
then
echo "Detected new kernel version ($new_kernel_version)."

INSTALLED_KERNEL_VERSION=$new_kernel_version
return 0
fi

echo "No changes to the kernel. Going back to waiting."
done
}

RUNNING_KERNEL_VERSION=$(read_running_kernel_version)
INSTALLED_KERNEL_VERSION=$(read_installed_kernel_version)

echo "Running kernel: $RUNNING_KERNEL_VERSION."
echo "Installed kernel: $INSTALLED_KERNEL_VERSION."

install_patch_after_kernel_change

# Letting systemd know the service finished its startup and kpatch can now run.
systemd-notify --ready

install_livepatch_package "$RUNNING_KERNEL_VERSION"

if [[ "$RUNNING_KERNEL_VERSION" != "$INSTALLED_KERNEL_VERSION" ]]
then
echo "Kernel will change after reboot ($RUNNING_KERNEL_VERSION -> $INSTALLED_KERNEL_VERSION). Installing patches for post-reboot kernel."
install_livepatch_package "$INSTALLED_KERNEL_VERSION"
fi

while wait_for_kernel_change
do
install_livepatch_package "$INSTALLED_KERNEL_VERSION"
done

0 comments on commit 2bcbca4

Please sign in to comment.