add kpatch and kpatch-build scripts

Signed-off-by: Seth Jennings <sjenning@redhat.com>
This commit is contained in:
Seth Jennings 2014-02-05 09:58:01 -06:00
parent 139cfe5350
commit 28a5a1d275
2 changed files with 310 additions and 0 deletions

179
scripts/kpatch Executable file
View File

@ -0,0 +1,179 @@
#!/bin/bash
# This is the primary kpatch user script that manages loading, unloading
# and displaying information on the hotfixes that are installed on the
# system.
# Subcommands:
# - enable MODULE
# - disable MODULE
# - load [--all | MODULE]
# - unload [--all | MODULE]
# - list
# - info MODULE
# 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
usage () {
echo "usage:"
echo "kpatch enable MODULE"
echo "kpatch disable MODULE"
echo "kpatch load [--all | MODULE]"
echo "kpatch unload [--all | MODULE]"
echo "kpatch list"
echo "kpatch info MODULE"
exit 1
}
# return either VARDIR or USRDIR (or exits if not found)
find_hotfix () {
[ -e $VARDIR/available/$1 ] && DIR=$VARDIR && return
[ -e $USRDIR/available/$1 ] && DIR=$USRDIR && return
echo "Hotfix $2 is not installed"
echo "Use "kpatch list" for available hotfixes"
exit 2
}
# takes full path to hotfix module
load_hotfix () {
NAME=$(basename $1)
NAME=${NAME%.*}
insmod $1
if [ $? -ne 0 ]
then
echo "Hotfix $NAME failed to load"
exit 3
fi
echo "Hotfix $NAME loaded"
}
# takes only the module filename
unload_hotfix () {
NAME=$(basename $1)
rmmod ${NAME%.*}
if [ $? -ne 0 ]
then
echo "Hotfix $NAME failed to unload"
exit 3
fi
echo "Hotfix $NAME unloaded"
}
unset DIR
[ $# -gt 2 ] || [ $# -lt 1 ] && usage
MODFILE=$2.ko
case $1 in
"enable")
[ $# -ne 2 ] && usage
find_hotfix $MODFILE
if [ -e $DIR/enabled/$MODFILE ]
then
echo "Hotfix $2 is already enabled"
exit 0
fi
ln -s $DIR/available/$MODFILE $DIR/enabled/$MODFILE
if [ $? -ne 0 ]
then
echo "Failed to enable hotfix $2"
exit 3
else
echo "Hotfix $2 enabled"
fi
;;
"disable")
[ $# -ne 2 ] && usage
find_hotfix $MODFILE
if [ ! -e $DIR/enabled/$MODFILE ]
then
echo "Hotfix $2 is already disabled"
exit 0
fi
rm -f $DIR/enabled/$MODFILE
if [ $? -ne 0 ]
then
echo "Failed to disable hotfix $2"
exit 3
else
echo "Hotfix $2 disabled"
fi
;;
"load")
[ $# -ne 2 ] && usage
case $2 in
"--all")
for i in $(ls $VARDIR/enabled)
do
load_hotfix $VARDIR/enabled/$i
done
for i in $(ls $USRDIR/enabled)
do
load_hotfix $USRDIR/enabled/$i
done
;;
*)
find_hotfix $MODFILE
load_hotfix $DIR/available/$MODFILE
;;
esac
;;
"unload")
[ $# -ne 2 ] && usage
case $2 in
"--all")
for i in $(ls $VARDIR/available)
do
unload_hotfix ${i%.*}
done
for i in $(ls $USRDIR/available)
do
unload_hotfix ${i%.*}
done
;;
*)
find_hotfix $MODFILE
unload_hotfix $2
;;
esac
;;
"list")
[ $# -ne 1 ] && usage
echo "User hotfixes available:"
for i in $(ls $VARDIR/available)
do
echo ${i%.*}
done
echo ""
echo "User hotfixes enabled:"
for i in $(ls $VARDIR/enabled)
do
echo ${i%.*}
done
echo ""
echo "System hotfixes available:"
for i in $(ls $USRDIR/available)
do
echo ${i%.*}
done
echo ""
echo "System hotfixes enabled:"
for i in $(ls $USRDIR/enabled)
do
echo ${i%.*}
done
;;
"info")
[ $# -ne 2 ] && usage
find_hotfix $MODFILE
echo "Hotfix information for ${2%.*}:"
modinfo $DIR/available/$MODFILE
;;
*)
echo "subcommand $1 not recognized"
usage
;;
esac

131
scripts/kpatch-build Executable file
View File

@ -0,0 +1,131 @@
#/bin/bash
# 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:
# - 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
# - Builds the patched objects with gcc flags -f[function|data]-sections
# - Runs kpatch tools to create and link the patch kernel module
BASE=$PWD
LOGFILE=$PWD/kpatch-build.log
KPATCHPATH=/usr/local/share/kpatch
ARCHVERSION=$(uname -r)
DISTROVERSION=${ARCHVERSION%*.*}
CPUS=$(grep -c ^processor /proc/cpuinfo)
LOCALVERSION=$(uname -r)
LOCALVERSION=-${LOCALVERSION##*-}
cleanup() {
rm -Rf kernel-$DISTROVERSION.src.rpm rpmbuild $LOGFILE $TEMPDIR > /dev/null 2>/dev/null
}
die() {
echo "kpatch encountered an error"
exit 1
}
if [ $# -ne 1 ]
then
echo "kpatch patchfile"
exit 2
fi
PATCHFILE=$(readlink -f $1)
if [ ! -e $PATCHFILE ]
then
echo "patch file not found"
exit 3
fi
cleanup
echo "Verifying required development tools"
yum install rpmdevtools yum-utils || die
echo "Downloading kernel source for $ARCHVERSION"
yumdownloader --source kernel-$ARCHVERSION || die
echo "Verifying build dependencies for kernel package"
yum-builddep kernel-$DISTROVERSION.src.rpm || die
echo "Unpacking kernel source"
rpmdev-setuptree >> $LOGFILE 2>&1 || die
rpm -Uvh kernel-$DISTROVERSION.src.rpm >> $LOGFILE 2>&1 || die
cd ~/rpmbuild/SPECS || die
rpmbuild -bp --target=$(uname -m) kernel.spec >> $LOGFILE 2>&1 || die
cd ~/rpmbuild/BUILD/kernel-* || die
cd linux-$ARCHVERSION || die
BUILD=$PWD
echo $LOCALVERSION > localversion
echo "Building the base kernel"
make -j$CPUS vmlinux >> $LOGFILE 2>&1 || die
TEMPDIR=`mktemp -d` || die
cp -R $KPATCHPATH/* $TEMPDIR || die
cp vmlinux $TEMPDIR || die
echo "Building the patched kernel"
patch -p1 < $PATCHFILE >> $LOGFILE 2>&1
make -j$CPUS vmlinux > $TEMPDIR/patched_build.log 2>&1 || die
echo "Detecting changed objects"
grep CC $TEMPDIR/patched_build.log | grep -v init/version.o | awk '{print $2}' >> $TEMPDIR/changed_objs
if [ $? -ne 0 ]
then
echo "No changed objects"
exit 0
fi
echo "Rebuilding changed objects"
mkdir $TEMPDIR/patched
for i in $(cat $TEMPDIR/changed_objs)
do
rm -f $i
KCFLAGS="-ffunction-sections -fdata-sections" make $i >> $LOGFILE 2>&1 || die
strip -d $i
cp -f $i $TEMPDIR/patched/
done
patch -R -p1 < $PATCHFILE >> $LOGFILE 2>&1
mkdir $TEMPDIR/base
for i in $(cat $TEMPDIR/changed_objs)
do
rm -f $i
KCFLAGS="-ffunction-sections -fdata-sections" make $i >> $LOGFILE 2>&1 || die
strip -d $i
cp -f $i $TEMPDIR/base/
done
echo "Extracting new and modified ELF sections"
cd $TEMPDIR
mkdir output
for i in base/*
do
FILE=`basename $i`
./tools/create-diff-object base/$FILE patched/$FILE output/$FILE >> $LOGFILE 2>&1
done
echo "Building hotfix module"
ld -r -o output.o output/* >> $LOGFILE 2>&1 || die
./tools/add-patches-section output.o vmlinux >> $LOGFILE 2>&1 || die
KPATCH_BUILD=$BUILD make >> $LOGFILE 2>&1 || die
strip -d kpatch-patch.ko >> $LOGFILE 2>&1 || die
./tools/link-vmlinux-syms kpatch-patch.ko vmlinux >> $LOGFILE 2>&1 || die
echo "Patch generation complete"
cp -f $TEMPDIR/kpatch-patch.ko $BASE
echo "Cleaning up"
cleanup
echo "Done"