From 5c98ec65a0bbeebaa8f356d8aa66c28623b7959f Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Thu, 15 May 2014 22:46:57 -0500 Subject: [PATCH] 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... --- README.md | 1 + kpatch-build/kpatch-build | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8534884..38b9a17 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build index bedd447..42b79b7 100755 --- a/kpatch-build/kpatch-build +++ b/kpatch-build/kpatch-build @@ -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