kpatch-build: use original vmlinux

There's at least one case in the kernel (ddebug_proc_show) where the
compiled instructions are affected by the source file path given to gcc.
Which means that compiling the kernel with O= will result in many of the
function addresses changing.  This causes a mismatch between the locally
compiled vmlinux and the original vmlinux, which is very dangerous,
since we need the addresses to be correct.

The easy fix is just to use the original vmlinux for all the function
addresses.

Other potential ways to fix it which we might want to consider in the
future:

- use a combination of the old System.map and the new vmlinux to find
  the addresses.  The function ordering should be the same.  For
  non-duplicate symbols, use System.map.  For duplicate symbols, use
  vmlinux to find what order the symbol comes in.  e.g. the 2nd
  occurrence of foo() in System.map.  It adds a little complexity to the
  lookup code, but seems safe and wouldn't require the kernel debuginfo
  package.  However, this may not help us for patching modules.

- do something similar at runtime, i.e. use kallsyms_lookup_name for
  non-dups and kallsyms_on_each_symbol for dups, and look for the nth
  occurrence of the symbol (value of n is decided at build time).  This
  has the complexity of the previous option but it's done at runtime
  rather than build time, so... why?  Doing it at build time is better.

- compile the kernel in place.  This basically means no more caching
  because recompiling with --function-sections causes everything to be
  recompiled again.  This is bad for kpatch developers' SSDs...
This commit is contained in:
Josh Poimboeuf 2014-05-15 22:46:57 -05:00
parent bf4be47e62
commit 5c98ec65a0
2 changed files with 13 additions and 3 deletions

View File

@ -31,6 +31,7 @@ Install the dependencies for the "kpatch-build" command:
sudo yum install rpmdevtools pesign yum-utils
sudo yum-builddep kernel
sudo debuginfo-install kernel
# optional, but highly recommended
sudo yum install ccache

View File

@ -88,6 +88,7 @@ usage() {
echo " -r, --sourcerpm Specify kernel source RPM" >&2
echo " -s, --sourcedir Specify kernel source directory" >&2
echo " -c, --config Specify kernel config file" >&2
echo " -v, --vmlinux Specify original vmlinux" >&2
echo " -d, --debug Keep scratch files in /tmp" >&2
}
@ -119,6 +120,11 @@ while [[ $# -gt 0 ]]; do
shift
[[ ! -f "$CONFIGFILE" ]] && die "config file $CONFIGFILE not found"
;;
-v|--vmlinux)
VMLINUX=$(readlink -f "$2")
shift
[[ ! -f "$VMLINUX" ]] && die "vmlinux file $VMLINUX not found"
;;
-d|--debug)
echo "DEBUG mode enabled"
DEBUG=1
@ -158,6 +164,9 @@ find_dirs || die "can't find supporting tools"
[[ -e "$SYMVERSFILE" ]] || die "can't find core module Module.symvers"
[[ -z $VMLINUX ]] && VMLINUX=/usr/lib/debug/lib/modules/${ARCHVERSION}/vmlinux
[[ -e "$VMLINUX" ]] || die "kernel-debuginfo not installed"
if [[ -n "$USERSRCDIR" ]]; then
SRCDIR="$CACHEDIR/src"
OBJDIR="$CACHEDIR/obj"
@ -209,6 +218,7 @@ else
elif [[ $ID = ubuntu ]]; then
echo "Debian/Ubuntu distribution detected"
cd $TEMPDIR
echo "Downloading and unpacking kernel source for $ARCHVERSION"
apt-get source linux || die "'apt-get source linux' failed. you may need to run 'apt-get install dpkg-dev'"
@ -234,7 +244,6 @@ echo "Building original kernel"
make mrproper >> "$LOGFILE" 2>&1 || die
make "-j$CPUS" vmlinux "O=$OBJDIR" >> "$LOGFILE" 2>&1 || die
cp -LR "$DATADIR/patch" "$TEMPDIR" || die
cp "$OBJDIR/vmlinux" "$TEMPDIR" || die
echo "Building patched kernel"
patch -N -p1 < "$APPLIEDPATCHFILE" >> "$LOGFILE" 2>&1 || die
@ -286,10 +295,10 @@ make prepare >> "$LOGFILE" 2>&1 || die
cd "$TEMPDIR/output"
ld -r -o ../patch/output.o $FILES >> "$LOGFILE" 2>&1 || die
cd "$TEMPDIR/patch"
"$TOOLSDIR"/add-patches-section output.o ../vmlinux >> "$LOGFILE" 2>&1 || die
"$TOOLSDIR"/add-patches-section output.o "$VMLINUX" >> "$LOGFILE" 2>&1 || die
KPATCH_BUILD="$SRCDIR" KPATCH_NAME="$PATCHNAME" KBUILD_EXTRA_SYMBOLS="$SYMVERSFILE" make "O=$OBJDIR" >> "$LOGFILE" 2>&1 || die
$STRIPCMD "kpatch-$PATCHNAME.ko" >> "$LOGFILE" 2>&1 || die
"$TOOLSDIR"/link-vmlinux-syms "kpatch-$PATCHNAME.ko" ../vmlinux >> "$LOGFILE" 2>&1 || die
"$TOOLSDIR"/link-vmlinux-syms "kpatch-$PATCHNAME.ko" "$VMLINUX" >> "$LOGFILE" 2>&1 || die
cp -f "$TEMPDIR/patch/kpatch-$PATCHNAME.ko" "$BASE" || die