mirror of https://github.com/dynup/kpatch
add kpatch and kpatch-build scripts
Signed-off-by: Seth Jennings <sjenning@redhat.com>
This commit is contained in:
parent
139cfe5350
commit
28a5a1d275
|
@ -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
|
|
@ -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"
|
||||
|
Loading…
Reference in New Issue