kpatch/kpatch-create

137 lines
3.1 KiB
Plaintext
Raw Normal View History

2013-01-18 00:09:26 +00:00
#!/bin/bash
# vim: tabstop=4 shiftwidth=4 expandtab
set -o nounset
set -o errexit
set -o pipefail
2013-01-18 16:42:56 +00:00
# TODO: log output to a file instead of /dev/null
2013-01-18 00:09:26 +00:00
CUR_DIR="$PWD"
SCRIPT="`basename $BASH_SOURCE`"
SCRIPT_DIR="`dirname $BASH_SOURCE`"
2013-01-18 18:31:14 +00:00
SCRIPT_DIR="`readlink -f \"$SCRIPT_DIR\"`"
2013-01-18 00:09:26 +00:00
KMOD_DIR="$SCRIPT_DIR/kmod"
KPATCH_REG="$KMOD_DIR/kpatch-register.o"
KPATCH_LDS="$KMOD_DIR/kpatch.lds"
2013-01-18 16:45:58 +00:00
KPATCH_GEN="$SCRIPT_DIR/kpatch-diff-gen/kpatch-diff-gen"
2013-01-18 00:09:26 +00:00
KPATCHGCC="$SCRIPT_DIR/kpatch-gcc"
JOBS=`grep -c processor /proc/cpuinfo`
2013-01-18 00:09:26 +00:00
MAKE_CMD="make -j$JOBS vmlinux"
export CROSS_COMPILE="$KPATCHGCC "
# TODO make in function
PROGRESS_FILE="kpatch-in-progress"
PATCHED=
PATCH=
KERNEL_DIR=
2013-01-18 16:42:56 +00:00
OUTPUT_DIR=
usage ()
{
echo "usage: $SCRIPT -p [PATCH] -k [KERNEL DIR] -o [OUTPUT DIR]" >&2
exit 1
}
2013-01-18 00:09:26 +00:00
scriptecho ()
{
echo "$SCRIPT: $*"
}
cleanup_objs ()
{
find "$KERNEL_DIR" -name "*.kpatch_orig" -o -name "*.kpatch_gen" | while read file; do
2013-01-18 00:09:26 +00:00
rm -f $file
done
}
cleanup ()
{
scriptecho "cleaning up..."
rm -f "$PROGRESS_FILE"
cleanup_objs
if [ $PATCHED ]; then
cd "$KERNEL_DIR"
patch -p1 -R < "$PATCH"
2013-01-18 00:09:26 +00:00
export CROSS_COMPILE="$KPATCHGCC "
$MAKE_CMD > /dev/null
fi
2013-01-18 16:42:56 +00:00
rm -rf "$TMPDIR"
2013-01-18 00:09:26 +00:00
}
die ()
{
echo "$SCRIPT: error: $*" >&2
exit 1
}
2013-01-18 16:42:56 +00:00
while getopts "p:k:o:" arg; do
2013-01-18 00:09:26 +00:00
case "$arg" in
p) PATCH="$OPTARG" ;;
k) KERNEL_DIR="$OPTARG" ;;
2013-01-18 16:42:56 +00:00
o) OUTPUT_DIR="$OPTARG" ;;
2013-01-18 00:09:26 +00:00
*) usage ;;
esac
done
2013-01-18 16:42:56 +00:00
[ ! "$PATCH" ] || [ ! "$KERNEL_DIR" ] || [ ! "$OUTPUT_DIR" ] && usage
2013-01-18 00:09:26 +00:00
[ ! -f "$PATCH" ] && die "$PATCH doesn't exist"
[ ! -d "$KERNEL_DIR" ] && die "$KERNEL_DIR doesn't exist"
2013-01-18 16:42:56 +00:00
mkdir -p "$OUTPUT_DIR"
2013-01-18 00:09:26 +00:00
PATCH="`readlink -f \"$PATCH\"`"
KERNEL_DIR="`readlink -f \"$KERNEL_DIR\"`"
2013-01-18 16:42:56 +00:00
OUTPUT_DIR="`readlink -f \"$OUTPUT_DIR\"`"
2013-01-18 00:09:26 +00:00
TMPDIR="`mktemp -d`"
trap cleanup exit
scriptecho "compiling original kernel"
rm -f "$PROGRESS_FILE"
cleanup_objs
cd "$KERNEL_DIR"
$MAKE_CMD > /dev/null
cp vmlinux vmlinux.kpatch_orig
2013-01-18 00:09:26 +00:00
scriptecho "patching kernel"
patch -p1 < "$PATCH"
2013-01-18 00:09:26 +00:00
PATCHED=1
scriptecho "compiling patched kernel"
touch "$PROGRESS_FILE"
$MAKE_CMD > /dev/null
rm -f "$PROGRESS_FILE"
2013-01-18 18:31:14 +00:00
scriptecho "diffing binaries"
find . -type f -name '*.o.kpatch_orig' | while read file; do
2013-01-18 00:09:26 +00:00
origfile="${file#./}"
newfile="${origfile%.kpatch_orig}"
[ ! -f "$newfile" ] && die "can't find $newfile"
2013-01-18 00:09:26 +00:00
num="`readelf -s \"$file\" |awk '{print $4}' |grep -c FILE`"
[ "$num" = 0 ] && die "unsupported change in (assembly?) file $file"
[ "$num" -gt 1 ] && die "$newfile has too many FILE symbols"
scriptecho "object changed: $newfile"
"$KPATCH_GEN" "$origfile" "$newfile" -v vmlinux.kpatch_orig -o "$newfile.kpatch_gen"
2013-01-18 00:09:26 +00:00
done
2013-01-18 18:31:14 +00:00
scriptecho "generating kpatch modules"
2013-01-18 00:09:26 +00:00
unset CROSS_COMPILE
cp -a "$KMOD_DIR" "$TMPDIR/kmod"
2013-01-18 16:42:56 +00:00
make -C "$KERNEL_DIR" M="$TMPDIR/kmod" kpatch-patch-hook.o > /dev/null
2013-01-18 00:09:26 +00:00
cd $TMPDIR/kmod
find "$KERNEL_DIR" -name "*.kpatch_gen" -exec ld -m elf_x86_64 -r -o kpatch-patch-foo.o kpatch-patch-hook.o kpatch.lds {} +
2013-01-18 16:42:56 +00:00
make -C "$KERNEL_DIR" M="$TMPDIR/kmod" kpatch.ko > /dev/null
make -C "$KERNEL_DIR" M="$TMPDIR/kmod" kpatch-patch.ko > /dev/null
cp kpatch.ko kpatch-patch.ko "$OUTPUT_DIR"
2013-01-18 00:09:26 +00:00
2013-01-18 18:31:14 +00:00
scriptecho success!