mirror of https://github.com/dynup/kpatch
Merge pull request #9 from jpoimboe/kpatch-script-improvements
kpatch script improvements
This commit is contained in:
commit
6eafd1648f
4
README
4
README
|
@ -27,10 +27,10 @@ NOTE: While kpatch is designed to work with any recent Linux
|
|||
kernel on any distribution, the "kpatch build" command currently
|
||||
only works on Fedora.
|
||||
|
||||
First make a patch against the kernel tree, e.g. foo.patch.
|
||||
First, use diff to make a source patch against the kernel tree, e.g. foo.patch.
|
||||
Then:
|
||||
|
||||
sudo /usr/local/sbin/kpatch build foo.patch
|
||||
kpatch build foo.patch
|
||||
sudo insmod kpatch.ko kpatch-foo.ko
|
||||
|
||||
Voila, your kernel is patched.
|
||||
|
|
|
@ -1,21 +1,17 @@
|
|||
#!/bin/bash
|
||||
|
||||
# kpatch build script for Fedora
|
||||
# kpatch build script
|
||||
|
||||
# This script takes a patch based on the version of the kernel
|
||||
# currently running and creates a kernel module that will
|
||||
# replace modified functions in the kernel such that the
|
||||
# patched code takes effect.
|
||||
|
||||
# This script contains Fedora specific nuances and will probably
|
||||
# not work on other distributions; however, it does serve as a tutorial
|
||||
# on the various steps involved and should be adaptable to other
|
||||
# distributions.
|
||||
# This script currently only works on Fedora and will need to be adapted to
|
||||
# work on other distros.
|
||||
|
||||
# This script:
|
||||
# - Installs the required yum/rpm tools
|
||||
# - Downloads the kernel src rpm for the currently running kernel
|
||||
# - Installs the build dependencies for the src rpm
|
||||
# - Unpacks and prepares the src rpm for building
|
||||
# - Builds the base kernel (vmlinux)
|
||||
# - Builds the patched kernel and monitors changed objects
|
||||
|
@ -23,9 +19,8 @@
|
|||
# - Runs kpatch tools to create and link the patch kernel module
|
||||
|
||||
BASE="$PWD"
|
||||
LOGFILE="$PWD/kpatch-build.log"
|
||||
TOOLSDIR=/usr/local/libexec/kpatch
|
||||
DATADIR=/usr/local/share/kpatch
|
||||
LOGFILE="/tmp/kpatch-build-$(date +%s).log"
|
||||
TOOLSDIR="$(readlink -f $(dirname $0))"
|
||||
ARCHVERSION="$(uname -r)"
|
||||
DISTROVERSION="${ARCHVERSION%*.*}"
|
||||
CPUS="$(grep -c ^processor /proc/cpuinfo)"
|
||||
|
@ -37,17 +32,32 @@ KSRCDIR_CACHE="$KSRCDIR.tgz"
|
|||
TEMPDIR=
|
||||
|
||||
cleanup() {
|
||||
rm -Rf "$KSRCDIR" "kernel-$DISTROVERSION.src.rpm" "$LOGFILE" "$TEMPDIR" > /dev/null 2>/dev/null
|
||||
rm -Rf "$KSRCDIR" "$LOGFILE" "$TEMPDIR" > /dev/null 2>/dev/null
|
||||
}
|
||||
|
||||
die() {
|
||||
echo "ERROR: kpatch build failed" >&2
|
||||
echo "check kpatch-build.log for more details" >&2
|
||||
if [[ -z $1 ]]; then
|
||||
echo "ERROR: kpatch build failed. Check kpatch-build.log for more details." >&2
|
||||
else
|
||||
echo "ERROR: $1" >&2
|
||||
fi
|
||||
exit 1
|
||||
}
|
||||
|
||||
find_data_dir() {
|
||||
# git repo
|
||||
DATADIR="$(readlink -f $TOOLSDIR/../kmod)"
|
||||
[[ -e "$DATADIR" ]] && return
|
||||
|
||||
# installation path
|
||||
DATADIR="$(readlink -f $TOOLSDIR/../../share/kpatch)"
|
||||
[[ -e "$DATADIR" ]] && return
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
if [[ "$#" -ne 1 ]]; then
|
||||
echo "usage: $0 PATCH" >&2
|
||||
echo "usage: $0 patchfile" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
|
@ -64,7 +74,7 @@ fi
|
|||
|
||||
cleanup
|
||||
|
||||
TEMPDIR="$(mktemp -d)" || die
|
||||
TEMPDIR="$(mktemp -d)" || die "mktemp failed"
|
||||
|
||||
if [[ -f "$KSRCDIR_CACHE" ]]; then
|
||||
echo "Using cache at $KSRCDIR_CACHE"
|
||||
|
@ -72,19 +82,17 @@ if [[ -f "$KSRCDIR_CACHE" ]]; then
|
|||
tar xzf "$KSRCDIR_CACHE" -C "$KSRCDIR_DIR" >> "$LOGFILE" 2>&1 || die
|
||||
cd "$KSRCDIR" || die
|
||||
else
|
||||
echo "Verifying required development tools"
|
||||
yum install rpmdevtools yum-utils >> "$LOGFILE" 2>&1 || die
|
||||
rpm -q --quiet rpmdevtools || die "rpmdevtools not installed"
|
||||
rpm -q --quiet yum-utils || die "yum-utils not installed"
|
||||
|
||||
echo "Downloading kernel source for $ARCHVERSION"
|
||||
yumdownloader --source "kernel-$ARCHVERSION" >> "$LOGFILE" 2>&1 || die
|
||||
|
||||
echo "Verifying build dependencies for kernel package"
|
||||
yum-builddep "kernel-$DISTROVERSION.src.rpm" >> "$LOGFILE" 2>&1 || die
|
||||
yumdownloader --source --destdir "$TEMPDIR" "kernel-$ARCHVERSION" >> "$LOGFILE" 2>&1 || die
|
||||
|
||||
echo "Unpacking kernel source"
|
||||
rpmdev-setuptree >> "$LOGFILE" 2>&1 || die
|
||||
rpm -Uvh "kernel-$DISTROVERSION.src.rpm" >> "$LOGFILE" 2>&1 || die
|
||||
rpmbuild -bp "--target=$(uname -m)" "$HOME/rpmbuild/SPECS/kernel.spec" >> "$LOGFILE" 2>&1 || die
|
||||
rpm -ivh "$TEMPDIR/kernel-$DISTROVERSION.src.rpm" >> "$LOGFILE" 2>&1 || die
|
||||
rpmbuild -bp "--target=$(uname -m)" "$HOME/rpmbuild/SPECS/kernel.spec" >> "$LOGFILE" 2>&1 ||
|
||||
die "rpmbuild -bp failed. you may need to run 'yum-builddep kernel' first."
|
||||
rm -rf "$KSRCDIR"
|
||||
mkdir -p "$KSRCDIR_DIR"
|
||||
mv "$HOME"/rpmbuild/BUILD/kernel-*/linux-"$ARCHVERSION" "$KSRCDIR" >> "$LOGFILE" 2>&1 || die
|
||||
|
@ -98,6 +106,8 @@ else
|
|||
tar czf "$KSRCDIR_CACHE" -C "$KSRCDIR_DIR" "$ARCHVERSION" >> "$LOGFILE" 2>&1 || die
|
||||
fi
|
||||
|
||||
find_data_dir || (echo "can't find data dir" >&2 && die)
|
||||
|
||||
cp -R "$DATADIR/core" "$DATADIR/patch" "$TEMPDIR" || die
|
||||
cp vmlinux "$TEMPDIR" || die
|
||||
|
||||
|
@ -153,5 +163,5 @@ strip -d "kpatch-$PATCHNAME.ko" >> "$LOGFILE" 2>&1 || die
|
|||
|
||||
cp -f "$TEMPDIR/patch/kpatch-$PATCHNAME.ko" "$TEMPDIR/core/kpatch.ko" "$BASE" || die
|
||||
|
||||
echo "SUCCESS"
|
||||
cleanup
|
||||
echo "SUCCESS"
|
||||
|
|
178
kpatch/kpatch
178
kpatch/kpatch
|
@ -1,34 +1,25 @@
|
|||
#!/bin/bash
|
||||
|
||||
# This is the primary kpatch user script that manages loading, unloading
|
||||
# and displaying information on the patches that are installed on the
|
||||
# system.
|
||||
|
||||
# Subcommands:
|
||||
# - enable MODULE
|
||||
# - disable MODULE
|
||||
# - load [--all | MODULE]
|
||||
# - unload [--all | MODULE]
|
||||
# - list
|
||||
# - info MODULE
|
||||
# This is the primary kpatch user script that manages building, applying, and
|
||||
# displaying information about kernel patch modules installed on the system.
|
||||
|
||||
# TODO: add kernelrelease option to manage releases other than the
|
||||
# currently running one
|
||||
|
||||
KERNELRELEASE="$(uname -r)"
|
||||
VARDIR="/var/lib/kpatch/$KERNELRELEASE"
|
||||
USRDIR="/usr/lib/kpatch/$KERNELRELEASE"
|
||||
TOOLSDIR=/usr/local/libexec/kpatch
|
||||
SYSDIR="/usr/lib/kpatch/$KERNELRELEASE"
|
||||
USERDIR="/var/lib/kpatch/$KERNELRELEASE"
|
||||
ENABLEDDIR="$USERDIR/enabled"
|
||||
|
||||
usage () {
|
||||
echo "usage:" >&2
|
||||
echo "kpatch enable MODULE" >&2
|
||||
echo "kpatch disable MODULE" >&2
|
||||
echo "kpatch load [--all | MODULE]" >&2
|
||||
echo "kpatch unload [--all | MODULE]" >&2
|
||||
echo "kpatch enable PATCH" >&2
|
||||
echo "kpatch disable PATCH" >&2
|
||||
echo "kpatch apply [--all | PATCH]" >&2
|
||||
echo "kpatch remove PATCH" >&2
|
||||
echo "kpatch list" >&2
|
||||
echo "kpatch info MODULE" >&2
|
||||
echo "kpatch build PATCH" >&2
|
||||
echo "kpatch info PATCH" >&2
|
||||
echo "kpatch build PATCH.patch" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
@ -41,131 +32,138 @@ die() {
|
|||
exit 1
|
||||
}
|
||||
|
||||
# return either VARDIR or USRDIR
|
||||
find_patch () {
|
||||
[[ -f "$VARDIR/available/$1" ]] && DIR="$VARDIR" && return
|
||||
[[ -f "$USRDIR/available/$1" ]] && DIR="$USRDIR" && return
|
||||
__find_module () {
|
||||
MODULE="$USERDIR/$1"
|
||||
[[ -f "$MODULE" ]] && return
|
||||
|
||||
MODULE="$SYSDIR/$1"
|
||||
[[ -f "$MODULE" ]] && return
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# takes full path to patch module
|
||||
load_patch () {
|
||||
NAME=$(basename $1)
|
||||
NAME=${NAME%.*}
|
||||
# Given a patch name, find the corresponding module and return its full path in
|
||||
# $MODULE. For a given module kpatch-foo.ko, we allow foo or kpatch-foo or
|
||||
# kpatch-foo.ko as input.
|
||||
find_module () {
|
||||
arg=$1
|
||||
__find_module "kpatch-$arg.ko" || __find_module "$arg.ko" || __find_module "${arg}"
|
||||
}
|
||||
|
||||
load_module () {
|
||||
/usr/sbin/insmod "$1"
|
||||
}
|
||||
|
||||
# takes only the module filename
|
||||
unload_patch () {
|
||||
NAME="$(basename $1)"
|
||||
/usr/sbin/rmmod "${NAME%.*}"
|
||||
unload_module () {
|
||||
/usr/sbin/rmmod "$(basename $1)"
|
||||
}
|
||||
|
||||
unset DIR
|
||||
module_enabled() {
|
||||
[[ -e "$ENABLEDDIR/$(basename $1)" ]]
|
||||
}
|
||||
|
||||
echo_patch_name() {
|
||||
NAME="$(basename $1)"
|
||||
NAME="${NAME%.ko}"
|
||||
NAME="${NAME#kpatch-}"
|
||||
echo $NAME
|
||||
}
|
||||
|
||||
find_kpatch_build() {
|
||||
SCRIPTDIR="$(readlink -f $(dirname $0))"
|
||||
|
||||
# git repo
|
||||
KPATCHBUILD="$(readlink -f $SCRIPTDIR/../kpatch-build/kpatch-build)"
|
||||
[[ -e "$KPATCHBUILD" ]] && return
|
||||
|
||||
# installation path
|
||||
KPATCHBUILD="$(readlink -f $SCRIPTDIR/../libexec/kpatch/kpatch-build)"
|
||||
[[ -e "$KPATCHBUILD" ]] && return
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
unset MODULE
|
||||
[[ "$#" -gt 2 ]] || [[ "$#" -lt 1 ]] && usage
|
||||
case "$1" in
|
||||
"enable")
|
||||
[[ "$#" -ne 2 ]] && usage
|
||||
PATCH=$2
|
||||
MODFILE="$PATCH.ko"
|
||||
find_patch "$MODFILE" || die "$PATCH is not installed"
|
||||
[[ -e "$DIR/enabled/$MODFILE" ]] && die "patch $2 is already enabled"
|
||||
mkdir -p $DIR/enabled
|
||||
ln -s "$DIR/available/$MODFILE" "$DIR/enabled/$MODFILE" || die "failed to enable patch $PATCH"
|
||||
PATCH="$2"
|
||||
find_module "$PATCH" || die "$PATCH is not installed"
|
||||
module_enabled $MODULE && die "$PATCH is already enabled"
|
||||
mkdir -p $ENABLEDDIR
|
||||
ln -s "$MODULE" "$ENABLEDDIR" || die "failed to enable patch $PATCH"
|
||||
;;
|
||||
|
||||
"disable")
|
||||
[[ "$#" -ne 2 ]] && usage
|
||||
PATCH=$2
|
||||
MODFILE="$PATCH.ko"
|
||||
find_patch "$MODFILE" || die "$PATCH is not installed"
|
||||
[[ ! -e "$DIR/enabled/$MODFILE" ]] && die "$PATCH is already disabled"
|
||||
rm -f "$DIR/enabled/$MODFILE" || die "failed to disable patch $PATCH"
|
||||
PATCH="$2"
|
||||
find_module "$PATCH" || die "$PATCH is not installed"
|
||||
module_enabled $MODULE || die "$PATCH is already disabled"
|
||||
rm -f "$ENABLEDDIR/$(basename $MODULE)" || die "failed to disable patch $PATCH"
|
||||
;;
|
||||
|
||||
"load")
|
||||
"apply")
|
||||
[[ "$#" -ne 2 ]] && usage
|
||||
case "$2" in
|
||||
"--all")
|
||||
for i in "$VARDIR"/enabled/*.ko; do
|
||||
for i in "$ENABLEDDIR"/*.ko; do
|
||||
[[ -e "$i" ]] || continue
|
||||
load_patch "$VARDIR/enabled/$i" || die "failed to load patch $PATCH"
|
||||
done
|
||||
for i in "$USRDIR"/enabled/*.ko; do
|
||||
[[ -e "$i" ]] || continue
|
||||
load_patch "$USRDIR/enabled/$i" || die "failed to load patch $PATCH"
|
||||
load_module "$i" || die "failed to load module $i"
|
||||
done
|
||||
;;
|
||||
*)
|
||||
PATCH="$2"
|
||||
MODFILE="$PATCH.ko"
|
||||
find_patch "$MODFILE" || die "$PATCH is not installed"
|
||||
load_patch "$DIR/available/$MODFILE" || die "failed to load patch $PATCH"
|
||||
find_module "$PATCH" || die "$PATCH is not installed"
|
||||
load_module "$MODULE" || die "failed to load patch $PATCH"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
|
||||
"unload")
|
||||
"remove")
|
||||
[[ "$#" -ne 2 ]] && usage
|
||||
case "$2" in
|
||||
"--all")
|
||||
for i in "$VARDIR"/available/*.ko; do
|
||||
[[ -e "$i" ]] || continue
|
||||
unload_patch "${i%.*}" || die "failed to unload patch $PATCH"
|
||||
done
|
||||
for i in "$USRDIR"/available/*.ko; do
|
||||
[[ -e "$i" ]] || continue
|
||||
unload_patch "${i%.*}" || die "failed to unload patch $PATCH"
|
||||
done
|
||||
;;
|
||||
PATCH="$2"
|
||||
case "$PATCH" in
|
||||
*)
|
||||
PATCH="$2"
|
||||
MODFILE="$PATCH.ko"
|
||||
find_patch "$MODFILE" || die "$PATCH is not installed"
|
||||
unload_patch "$PATCH" || die "failed to unload patch $PATCH"
|
||||
find_module "$PATCH" || die "$PATCH is not installed"
|
||||
unload_module "$MODULE" || die "failed to unload patch $PATCH"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
|
||||
"list")
|
||||
[[ "$#" -ne 1 ]] && usage
|
||||
echo "User patches available:"
|
||||
for i in "$VARDIR"/available/*.ko; do
|
||||
echo "System patches:"
|
||||
for i in "$SYSDIR"/*.ko; do
|
||||
[[ -e "$i" ]] || continue
|
||||
echo "$(basename ${i%.*})"
|
||||
echo_patch_name $i
|
||||
done
|
||||
echo ""
|
||||
echo "User patches enabled:"
|
||||
for i in "$VARDIR"/enabled/*.ko; do
|
||||
echo "User patches:"
|
||||
for i in "$USERDIR"/*.ko; do
|
||||
[[ -e "$i" ]] || continue
|
||||
echo "$(basename ${i%.*})"
|
||||
echo_patch_name $i
|
||||
done
|
||||
echo ""
|
||||
echo "System patches available:"
|
||||
for i in "$USRDIR"/available/*.ko; do
|
||||
echo "Enabled patches:"
|
||||
for i in "$ENABLEDDIR"/*.ko; do
|
||||
[[ -e "$i" ]] || continue
|
||||
echo "$(basename ${i%.*})"
|
||||
done
|
||||
echo ""
|
||||
echo "System patches enabled:"
|
||||
for i in "$USRDIR"/enabled/*.ko; do
|
||||
[[ -e "$i" ]] || continue
|
||||
echo "$(basename ${i%.*})"
|
||||
echo_patch_name $i
|
||||
done
|
||||
;;
|
||||
|
||||
"info")
|
||||
[[ "$#" -ne 2 ]] && usage
|
||||
PATCH="$2"
|
||||
MODFILE="$PATCH.ko"
|
||||
find_patch "$MODFILE" || die "$PATCH is not installed"
|
||||
find_module "$PATCH" || die "$PATCH is not installed"
|
||||
echo "Patch information for $PATCH:"
|
||||
/usr/sbin/modinfo "$DIR/available/$MODFILE"
|
||||
/usr/sbin/modinfo "$MODULE" || die "failed to get info for patch $PATCH"
|
||||
;;
|
||||
|
||||
"build")
|
||||
[[ "$#" -ne 2 ]] && usage
|
||||
"$TOOLSDIR/kpatch-build" "$2" || die "kpatch build failed"
|
||||
find_kpatch_build || die "kpatch-build is not installed"
|
||||
shift
|
||||
"$KPATCHBUILD" "$@" || die "kpatch build failed"
|
||||
;;
|
||||
|
||||
*)
|
||||
|
|
Loading…
Reference in New Issue