From 519c8e6b4496c19d936177dfae5abdeecab5b226 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Wed, 12 Feb 2014 21:31:38 -0600 Subject: [PATCH 1/7] fix bash shebang --- scripts/kpatch-build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/kpatch-build b/scripts/kpatch-build index 5bbdf3ded..880196092 100755 --- a/scripts/kpatch-build +++ b/scripts/kpatch-build @@ -1,4 +1,4 @@ -#/bin/bash +#!/bin/bash # kpatch build script for Fedora From 8c9d8d0cb6096cbb69659dbd52c2d526455e2c3d Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Wed, 12 Feb 2014 21:34:22 -0600 Subject: [PATCH 2/7] add build caching --- scripts/kpatch-build | 56 +++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/scripts/kpatch-build b/scripts/kpatch-build index 880196092..43bbb76c1 100755 --- a/scripts/kpatch-build +++ b/scripts/kpatch-build @@ -30,6 +30,8 @@ DISTROVERSION=${ARCHVERSION%*.*} CPUS=$(grep -c ^processor /proc/cpuinfo) LOCALVERSION=$(uname -r) LOCALVERSION=-${LOCALVERSION##*-} +KSRCDIR=~/.kpatch/$ARCHVERSION +KSRCDIR_CACHE=$KSRCDIR.cache cleanup() { rm -Rf kernel-$DISTROVERSION.src.rpm rpmbuild $LOGFILE $TEMPDIR > /dev/null 2>/dev/null @@ -55,28 +57,40 @@ 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 +TEMPDIR=`mktemp -d` || 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 +if [ -d "$KSRCDIR_CACHE" ] +then + echo "Using kernel source compile cache at $KSRCDIR_CACHE" + rm -rf $KSRCDIR + cp -a $KSRCDIR_CACHE $KSRCDIR + cd $KSRCDIR +else + 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 + rpmbuild -bp --target=$(uname -m) ~/rpmbuild/SPECS/kernel.spec >> $LOGFILE 2>&1 || die + rm -rf $KSRCDIR + mkdir -p ~/.kpatch + mv ~/rpmbuild/BUILD/kernel-*/linux-$ARCHVERSION $KSRCDIR >> $LOGFILE 2>&1 || die + + echo "Building the base kernel" + cd $KSRCDIR + echo $LOCALVERSION > localversion + make -j$CPUS vmlinux >> $LOGFILE 2>&1 || die + + cp -a $KSRCDIR $KSRCDIR_CACHE +fi -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 @@ -124,7 +138,7 @@ 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 +KPATCH_BUILD=$KSRCDIR 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 From a8ab0c16a771120873235431bec1f21a46f7d208 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Wed, 12 Feb 2014 21:53:05 -0600 Subject: [PATCH 3/7] first pass at a decent user interface This makes it somewhat easy to use. From the root git dir, just: sudo scripts/kpatch-build ~/foo.patch and it'll take care of everything, eventually spitting out the base module (kpatch.ko) and the hotpatch module kpatch-foo.ko. This is still all very crude, but a better user interface is coming soon. --- README | 13 +++++++++ kpatch-files/Makefile | 14 +++++----- kpatch-files/kpatch-patch-hook.c | 2 +- scripts/kpatch-build | 46 ++++++++++++++++++++------------ tools/Makefile | 2 ++ tools/add-patches-section.c | 2 +- tools/create-diff-object.c | 2 +- tools/link-vmlinux-syms.c | 2 +- 8 files changed, 56 insertions(+), 27 deletions(-) diff --git a/README b/README index 6059be4f9..5ddad101c 100644 --- a/README +++ b/README @@ -12,6 +12,19 @@ scale-out, run on a single machine and are very downtime sensitive or require a heavyweight approval process and notification of workload users in the event of downtime. +QUICK START + +This only works on Fedora currently. + +First make a patch against the kernel tree, e.g. foo.patch. Then: + + sudo scripts/kpatch-build ~/foo.patch + insmod kpatch.ko kpatch-foo.ko + +Voila, your kernel is patched. + +A less crude interface is coming soon. + LICENSE kpatch is under the GPLv2 license. diff --git a/kpatch-files/Makefile b/kpatch-files/Makefile index ddeffb99f..d27819129 100644 --- a/kpatch-files/Makefile +++ b/kpatch-files/Makefile @@ -1,14 +1,16 @@ -KPATCH_BUILD = /lib/modules/$(shell uname -r)/build +KPATCH_NAME ?= patch +KPATCH_BUILD ?= /lib/modules/$(shell uname -r)/build KPATCH_MAKE = $(MAKE) -C $(KPATCH_BUILD) M=$(PWD) +ccflags-y += -I$(KPATCH_BASEDIR) -obj-m += kpatch-patch.o +obj-m += kpatch-$(KPATCH_NAME).o -kpatch-patch-objs += kpatch-patch-hook.o kpatch.lds output.o +kpatch-$(KPATCH_NAME)-objs += kpatch-patch-hook.o kpatch.lds output.o -all: kpatch-patch.ko +all: kpatch-$(KPATCH_NAME).ko -kpatch-patch.ko: - $(KPATCH_MAKE) kpatch-patch.ko +kpatch-$(KPATCH_NAME).ko: + $(KPATCH_MAKE) kpatch-$(KPATCH_NAME).ko kpatch-patch-hook.o: kpatch-patch-hook.c $(KPATCH_MAKE) kpatch-patch-hook.o diff --git a/kpatch-files/kpatch-patch-hook.c b/kpatch-files/kpatch-patch-hook.c index dca0fd0db..f0589341d 100644 --- a/kpatch-files/kpatch-patch-hook.c +++ b/kpatch-files/kpatch-patch-hook.c @@ -2,7 +2,7 @@ #include #include -#include "../kpatch-kmod/kpatch.h" +#include "kpatch.h" extern char __kpatch_patches, __kpatch_patches_end; diff --git a/scripts/kpatch-build b/scripts/kpatch-build index 43bbb76c1..8c51c2fab 100755 --- a/scripts/kpatch-build +++ b/scripts/kpatch-build @@ -24,7 +24,7 @@ BASE=$PWD LOGFILE=$PWD/kpatch-build.log -KPATCHPATH=/usr/local/share/kpatch +TOOLSDIR=$BASE/tools ARCHVERSION=$(uname -r) DISTROVERSION=${ARCHVERSION%*.*} CPUS=$(grep -c ^processor /proc/cpuinfo) @@ -34,17 +34,18 @@ KSRCDIR=~/.kpatch/$ARCHVERSION KSRCDIR_CACHE=$KSRCDIR.cache cleanup() { - rm -Rf kernel-$DISTROVERSION.src.rpm rpmbuild $LOGFILE $TEMPDIR > /dev/null 2>/dev/null + rm -Rf kernel-$DISTROVERSION.src.rpm $LOGFILE $TEMPDIR > /dev/null 2>/dev/null } die() { echo "kpatch encountered an error" + echo "check kpatch-build.log" exit 1 } if [ $# -ne 1 ] then - echo "kpatch patchfile" + echo "usage: $0 PATCH" exit 2 fi @@ -55,13 +56,22 @@ then exit 3 fi +PATCHBASE=`basename $PATCHFILE` +if [[ $PATCHBASE =~ \.patch ]] || [[ $PATCHBASE =~ \.diff ]] +then + PATCHBASE=${PATCHBASE%.*} +fi + cleanup +echo "Building tools" +make -C $TOOLSDIR >> $LOGFILE 2>&1 || die + TEMPDIR=`mktemp -d` || die if [ -d "$KSRCDIR_CACHE" ] then - echo "Using kernel source compile cache at $KSRCDIR_CACHE" + echo "Using cache at $KSRCDIR_CACHE" rm -rf $KSRCDIR cp -a $KSRCDIR_CACHE $KSRCDIR cd $KSRCDIR @@ -91,10 +101,10 @@ else cp -a $KSRCDIR $KSRCDIR_CACHE fi -cp -R $KPATCHPATH/* $TEMPDIR || die +cp -R $BASE/kpatch-files/* $BASE/kpatch-kmod $TEMPDIR || die cp vmlinux $TEMPDIR || die -echo "Building the patched kernel" +echo "Building patched kernel" patch -p1 < $PATCHFILE >> $LOGFILE 2>&1 make -j$CPUS vmlinux > $TEMPDIR/patched_build.log 2>&1 || die @@ -132,19 +142,21 @@ mkdir output for i in base/* do FILE=`basename $i` - ./tools/create-diff-object base/$FILE patched/$FILE output/$FILE >> $LOGFILE 2>&1 + $TOOLSDIR/create-diff-object base/$FILE patched/$FILE output/$FILE >> $LOGFILE 2>&1 || die 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 +echo "Building base module: kpatch.ko" +cd kpatch-kmod KPATCH_BUILD=$KSRCDIR 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 +cd .. -echo "Patch generation complete" -cp -f $TEMPDIR/kpatch-patch.ko $BASE -echo "Cleaning up" -cleanup -echo "Done" +echo "Building hotpatch module: kpatch-$PATCHBASE.ko" +ld -r -o output.o output/* >> $LOGFILE 2>&1 || die +$TOOLSDIR/add-patches-section output.o vmlinux >> $LOGFILE 2>&1 || die +KPATCH_BASEDIR=$TEMPDIR/kpatch-kmod KPATCH_BUILD=$KSRCDIR KPATCH_NAME=$PATCHBASE make >> $LOGFILE 2>&1 || die +strip -d kpatch-$PATCHBASE.ko >> $LOGFILE 2>&1 || die +$TOOLSDIR/link-vmlinux-syms kpatch-$PATCHBASE.ko vmlinux >> $LOGFILE 2>&1 || die +echo "SUCCESS" +cp -f $TEMPDIR/kpatch-$PATCHBASE.ko $TEMPDIR/kpatch-kmod/kpatch.ko $BASE +cleanup diff --git a/tools/Makefile b/tools/Makefile index 1d9685b3f..84b168049 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -1,3 +1,5 @@ +CFLAGS=-I../kpatch-kmod + all: create-diff-object add-patches-section link-vmlinux-syms create-diff-object: create-diff-object.c diff --git a/tools/add-patches-section.c b/tools/add-patches-section.c index c76d42996..cb425537a 100644 --- a/tools/add-patches-section.c +++ b/tools/add-patches-section.c @@ -26,7 +26,7 @@ #include #include -#include "../kpatch-kmod/kpatch.h" +#include "kpatch.h" #define ERROR(format, ...) \ error(1, 0, "%s: %d: " format, __FUNCTION__, __LINE__, ##__VA_ARGS__) diff --git a/tools/create-diff-object.c b/tools/create-diff-object.c index 9f9b98517..6f993be48 100644 --- a/tools/create-diff-object.c +++ b/tools/create-diff-object.c @@ -39,7 +39,7 @@ #include #include -#include "../kpatch-kmod/kpatch.h" +#include "kpatch.h" #define ERROR(format, ...) \ error(1, 0, "%s: %d: " format, __FUNCTION__, __LINE__, ##__VA_ARGS__) diff --git a/tools/link-vmlinux-syms.c b/tools/link-vmlinux-syms.c index 6295763dd..8e8f2a944 100644 --- a/tools/link-vmlinux-syms.c +++ b/tools/link-vmlinux-syms.c @@ -23,7 +23,7 @@ #include #include -#include "../kpatch-kmod/kpatch.h" +#include "kpatch.h" #define ERROR(format, ...) \ error(1, 0, "%s: %d: " format, __FUNCTION__, __LINE__, ##__VA_ARGS__) From 4f27b9ae31cd5ab289481ec46bc2b05ad923dece Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Thu, 13 Feb 2014 07:49:02 -0600 Subject: [PATCH 4/7] functional reorganization Organize the files functionally: - kmod/core: core kmod source - kmod/patch: patch kmod source - kpatch: kpatch script - kpatch-build: kpatch build script and supporting tools - contrib: distro-related files --- .gitignore | 10 ++---- Makefile | 8 ----- README | 16 +++++----- {scripts => contrib}/kpatch.service | 0 {kpatch-kmod => kmod/core}/Makefile | 4 +-- kpatch-kmod/base.c => kmod/core/core.c | 0 {kpatch-kmod => kmod/core}/kpatch.h | 0 {kpatch-kmod => kmod/core}/trampoline.S | 0 {kpatch-files => kmod/patch}/Makefile | 0 .../patch}/kpatch-patch-hook.c | 0 {kpatch-files => kmod/patch}/kpatch.lds | 0 {tools => kpatch-build}/Makefile | 2 +- {tools => kpatch-build}/add-patches-section.c | 0 {tools => kpatch-build}/create-diff-object.c | 0 {scripts => kpatch-build}/kpatch-build | 32 +++++++++---------- {tools => kpatch-build}/link-vmlinux-syms.c | 0 {scripts => kpatch}/kpatch | 0 17 files changed, 30 insertions(+), 42 deletions(-) delete mode 100644 Makefile rename {scripts => contrib}/kpatch.service (100%) rename {kpatch-kmod => kmod/core}/Makefile (80%) rename kpatch-kmod/base.c => kmod/core/core.c (100%) rename {kpatch-kmod => kmod/core}/kpatch.h (100%) rename {kpatch-kmod => kmod/core}/trampoline.S (100%) rename {kpatch-files => kmod/patch}/Makefile (100%) rename {kpatch-files => kmod/patch}/kpatch-patch-hook.c (100%) rename {kpatch-files => kmod/patch}/kpatch.lds (100%) rename {tools => kpatch-build}/Makefile (93%) rename {tools => kpatch-build}/add-patches-section.c (100%) rename {tools => kpatch-build}/create-diff-object.c (100%) rename {scripts => kpatch-build}/kpatch-build (83%) rename {tools => kpatch-build}/link-vmlinux-syms.c (100%) rename {scripts => kpatch}/kpatch (100%) diff --git a/.gitignore b/.gitignore index dd50ef5e9..1b5b1e63d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,9 @@ -kpatch-diff-gen/kpatch-diff-gen *.o *.o.cmd *.ko *.ko.cmd *.mod.c *.swp -kmod/.tmp_versions/ -kmod/Module.symvers -kmod/modules.order -tools/add-patches-section -tools/create-diff-object -tools/link-vmlinux-syms +kpatch-build/add-patches-section +kpatch-build/create-diff-object +kpatch-build/link-vmlinux-syms diff --git a/Makefile b/Makefile deleted file mode 100644 index f248f062b..000000000 --- a/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -SUBDIRS = kpatch-kmod tools - -.PHONY: clean -clean: - for dir in $(SUBDIRS); do \ - $(MAKE) -C $$dir $@; \ - done - diff --git a/README b/README index 5ddad101c..714738a7f 100644 --- a/README +++ b/README @@ -18,7 +18,7 @@ This only works on Fedora currently. First make a patch against the kernel tree, e.g. foo.patch. Then: - sudo scripts/kpatch-build ~/foo.patch + sudo kpatch-build/kpatch-build ~/foo.patch insmod kpatch.ko kpatch-foo.ko Voila, your kernel is patched. @@ -51,7 +51,7 @@ patches and environments is conducted. DEPENDENCIES -kpatch tools require libelf library and development headers to be installed. +kpatch-build tools require libelf library and development headers to be installed. See GOTCHAS below. GOTCHAS @@ -67,8 +67,8 @@ git://git.fedorahosted.org/git/elfutils.git HOWTO -An example script for automating the hotfix module generation is in -scripts/kpatch-build. The script is written for Fedora but should +An example script for automating the hotfix module generation is +kpatch-build/kpatch-build. The script is written for Fedora but should be adaptable to other distributions with limited changes. The primary steps in the hotfix module generation process are: @@ -80,16 +80,16 @@ The primary steps in the hotfix module generation process are: resulting in the changed patched objects - Unpatch the source tree - Recompile each changed object with -ffunction-sections -fdata-sections - resulting in the changed base objects -- Use tools/create-diff-object to analyze each base/patched object pair + resulting in the changed original objects +- Use create-diff-object to analyze each original/patched object pair for patchability and generate an output object containing modified sections - Link all the output objects in a into a cumulative object -- Use tools/add-patches-section to add the .patches section that the +- Use add-patches-section to add the .patches section that the core kpatch module uses to determine the list of functions that need to be redirected using ftrace - Generate the hotfix kernel module -- Use tools/link-vmlinux-syms to hardcode non-exported kernel symbols +- Use link-vmlinux-syms to hardcode non-exported kernel symbols into the symbol table of the hotfix kernel module DEMONSTRATION diff --git a/scripts/kpatch.service b/contrib/kpatch.service similarity index 100% rename from scripts/kpatch.service rename to contrib/kpatch.service diff --git a/kpatch-kmod/Makefile b/kmod/core/Makefile similarity index 80% rename from kpatch-kmod/Makefile rename to kmod/core/Makefile index 21d200a69..ac83fe421 100644 --- a/kpatch-kmod/Makefile +++ b/kmod/core/Makefile @@ -2,9 +2,9 @@ KPATCH_BUILD ?= /usr/lib/modules/$(shell uname -r)/build KPATCH_MAKE = $(MAKE) -C $(KPATCH_BUILD) M=$(PWD) obj-m := kpatch.o -kpatch-y := base.o trampoline.o +kpatch-y := core.o trampoline.o -kpatch.ko: base.c trampoline.S +kpatch.ko: core.c trampoline.S $(KPATCH_MAKE) kpatch.ko all: kpatch.ko diff --git a/kpatch-kmod/base.c b/kmod/core/core.c similarity index 100% rename from kpatch-kmod/base.c rename to kmod/core/core.c diff --git a/kpatch-kmod/kpatch.h b/kmod/core/kpatch.h similarity index 100% rename from kpatch-kmod/kpatch.h rename to kmod/core/kpatch.h diff --git a/kpatch-kmod/trampoline.S b/kmod/core/trampoline.S similarity index 100% rename from kpatch-kmod/trampoline.S rename to kmod/core/trampoline.S diff --git a/kpatch-files/Makefile b/kmod/patch/Makefile similarity index 100% rename from kpatch-files/Makefile rename to kmod/patch/Makefile diff --git a/kpatch-files/kpatch-patch-hook.c b/kmod/patch/kpatch-patch-hook.c similarity index 100% rename from kpatch-files/kpatch-patch-hook.c rename to kmod/patch/kpatch-patch-hook.c diff --git a/kpatch-files/kpatch.lds b/kmod/patch/kpatch.lds similarity index 100% rename from kpatch-files/kpatch.lds rename to kmod/patch/kpatch.lds diff --git a/tools/Makefile b/kpatch-build/Makefile similarity index 93% rename from tools/Makefile rename to kpatch-build/Makefile index 84b168049..de0f15ff9 100644 --- a/tools/Makefile +++ b/kpatch-build/Makefile @@ -1,4 +1,4 @@ -CFLAGS=-I../kpatch-kmod +CFLAGS=-I../kmod/core all: create-diff-object add-patches-section link-vmlinux-syms diff --git a/tools/add-patches-section.c b/kpatch-build/add-patches-section.c similarity index 100% rename from tools/add-patches-section.c rename to kpatch-build/add-patches-section.c diff --git a/tools/create-diff-object.c b/kpatch-build/create-diff-object.c similarity index 100% rename from tools/create-diff-object.c rename to kpatch-build/create-diff-object.c diff --git a/scripts/kpatch-build b/kpatch-build/kpatch-build similarity index 83% rename from scripts/kpatch-build rename to kpatch-build/kpatch-build index 8c51c2fab..9cd749c20 100755 --- a/scripts/kpatch-build +++ b/kpatch-build/kpatch-build @@ -24,7 +24,7 @@ BASE=$PWD LOGFILE=$PWD/kpatch-build.log -TOOLSDIR=$BASE/tools +TOOLSDIR=$BASE/kpatch-build ARCHVERSION=$(uname -r) DISTROVERSION=${ARCHVERSION%*.*} CPUS=$(grep -c ^processor /proc/cpuinfo) @@ -56,10 +56,10 @@ then exit 3 fi -PATCHBASE=`basename $PATCHFILE` -if [[ $PATCHBASE =~ \.patch ]] || [[ $PATCHBASE =~ \.diff ]] +PATCHNAME=`basename $PATCHFILE` +if [[ $PATCHNAME =~ \.patch ]] || [[ $PATCHNAME =~ \.diff ]] then - PATCHBASE=${PATCHBASE%.*} + PATCHNAME=${PATCHNAME%.*} fi cleanup @@ -101,7 +101,7 @@ else cp -a $KSRCDIR $KSRCDIR_CACHE fi -cp -R $BASE/kpatch-files/* $BASE/kpatch-kmod $TEMPDIR || die +cp -R $BASE/kmod/patch/* $BASE/kmod/core $TEMPDIR || die cp vmlinux $TEMPDIR || die echo "Building patched kernel" @@ -127,36 +127,36 @@ do done patch -R -p1 < $PATCHFILE >> $LOGFILE 2>&1 -mkdir $TEMPDIR/base +mkdir $TEMPDIR/orig 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/ + cp -f $i $TEMPDIR/orig/ done echo "Extracting new and modified ELF sections" cd $TEMPDIR mkdir output -for i in base/* +for i in orig/* do FILE=`basename $i` - $TOOLSDIR/create-diff-object base/$FILE patched/$FILE output/$FILE >> $LOGFILE 2>&1 || die + $TOOLSDIR/create-diff-object orig/$FILE patched/$FILE output/$FILE >> $LOGFILE 2>&1 || die done -echo "Building base module: kpatch.ko" -cd kpatch-kmod +echo "Building core module: kpatch.ko" +cd core KPATCH_BUILD=$KSRCDIR make >> $LOGFILE 2>&1 || die cd .. -echo "Building hotpatch module: kpatch-$PATCHBASE.ko" +echo "Building patch module: kpatch-$PATCHNAME.ko" ld -r -o output.o output/* >> $LOGFILE 2>&1 || die $TOOLSDIR/add-patches-section output.o vmlinux >> $LOGFILE 2>&1 || die -KPATCH_BASEDIR=$TEMPDIR/kpatch-kmod KPATCH_BUILD=$KSRCDIR KPATCH_NAME=$PATCHBASE make >> $LOGFILE 2>&1 || die -strip -d kpatch-$PATCHBASE.ko >> $LOGFILE 2>&1 || die -$TOOLSDIR/link-vmlinux-syms kpatch-$PATCHBASE.ko vmlinux >> $LOGFILE 2>&1 || die +KPATCH_BASEDIR=$TEMPDIR/core KPATCH_BUILD=$KSRCDIR KPATCH_NAME=$PATCHNAME make >> $LOGFILE 2>&1 || die +strip -d kpatch-$PATCHNAME.ko >> $LOGFILE 2>&1 || die +$TOOLSDIR/link-vmlinux-syms kpatch-$PATCHNAME.ko vmlinux >> $LOGFILE 2>&1 || die echo "SUCCESS" -cp -f $TEMPDIR/kpatch-$PATCHBASE.ko $TEMPDIR/kpatch-kmod/kpatch.ko $BASE +cp -f $TEMPDIR/kpatch-$PATCHNAME.ko $TEMPDIR/core/kpatch.ko $BASE cleanup diff --git a/tools/link-vmlinux-syms.c b/kpatch-build/link-vmlinux-syms.c similarity index 100% rename from tools/link-vmlinux-syms.c rename to kpatch-build/link-vmlinux-syms.c diff --git a/scripts/kpatch b/kpatch/kpatch similarity index 100% rename from scripts/kpatch rename to kpatch/kpatch From 6d6a5dfd1e98985482c0b9f90dccd30a3db2934c Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Thu, 13 Feb 2014 08:24:54 -0600 Subject: [PATCH 5/7] compressed cache Saves about 2G disk space per kernel version --- kpatch-build/kpatch-build | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build index 9cd749c20..deac7112f 100755 --- a/kpatch-build/kpatch-build +++ b/kpatch-build/kpatch-build @@ -31,10 +31,11 @@ CPUS=$(grep -c ^processor /proc/cpuinfo) LOCALVERSION=$(uname -r) LOCALVERSION=-${LOCALVERSION##*-} KSRCDIR=~/.kpatch/$ARCHVERSION -KSRCDIR_CACHE=$KSRCDIR.cache +KSRCDIR_DIR=$(dirname $KSRCDIR) +KSRCDIR_CACHE=$KSRCDIR.tgz cleanup() { - rm -Rf kernel-$DISTROVERSION.src.rpm $LOGFILE $TEMPDIR > /dev/null 2>/dev/null + rm -Rf $KSRCDIR kernel-$DISTROVERSION.src.rpm $LOGFILE $TEMPDIR > /dev/null 2>/dev/null } die() { @@ -69,12 +70,12 @@ make -C $TOOLSDIR >> $LOGFILE 2>&1 || die TEMPDIR=`mktemp -d` || die -if [ -d "$KSRCDIR_CACHE" ] +if [ -f "$KSRCDIR_CACHE" ] then echo "Using cache at $KSRCDIR_CACHE" rm -rf $KSRCDIR - cp -a $KSRCDIR_CACHE $KSRCDIR - cd $KSRCDIR + tar xzf $KSRCDIR_CACHE -C $KSRCDIR_DIR || die + cd $KSRCDIR || die else echo "Verifying required development tools" yum install rpmdevtools yum-utils || die @@ -90,15 +91,16 @@ else rpm -Uvh kernel-$DISTROVERSION.src.rpm >> $LOGFILE 2>&1 || die rpmbuild -bp --target=$(uname -m) ~/rpmbuild/SPECS/kernel.spec >> $LOGFILE 2>&1 || die rm -rf $KSRCDIR - mkdir -p ~/.kpatch + mkdir -p $KSRCDIR_DIR mv ~/rpmbuild/BUILD/kernel-*/linux-$ARCHVERSION $KSRCDIR >> $LOGFILE 2>&1 || die - echo "Building the base kernel" + echo "Building original kernel" cd $KSRCDIR echo $LOCALVERSION > localversion make -j$CPUS vmlinux >> $LOGFILE 2>&1 || die - cp -a $KSRCDIR $KSRCDIR_CACHE + echo "Creating cache" + tar czf $KSRCDIR_CACHE -C $KSRCDIR_DIR $ARCHVERSION fi cp -R $BASE/kmod/patch/* $BASE/kmod/core $TEMPDIR || die From cc846f6705b2c477362e074c33d181ec3550a726 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Thu, 13 Feb 2014 10:18:46 -0600 Subject: [PATCH 6/7] clarify that kpatch should work on non-Fedora --- README | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README b/README index 714738a7f..fb53b4580 100644 --- a/README +++ b/README @@ -14,17 +14,18 @@ notification of workload users in the event of downtime. QUICK START -This only works on Fedora currently. +NOTE: While kpatch is designed to work with any recent Linux +kernel on any distribution, these quick start instructions +currently only work on Fedora. -First make a patch against the kernel tree, e.g. foo.patch. Then: +First make a patch against the kernel tree, e.g. foo.patch. +Then: sudo kpatch-build/kpatch-build ~/foo.patch insmod kpatch.ko kpatch-foo.ko Voila, your kernel is patched. -A less crude interface is coming soon. - LICENSE kpatch is under the GPLv2 license. From 72b1ee7916f52eecf984b2c76644d3b7bb1e525f Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Thu, 13 Feb 2014 10:51:00 -0600 Subject: [PATCH 7/7] use consistent naming for core and patch modules --- README | 8 ++++---- kmod/core/core.c | 10 ++++------ kmod/core/kpatch.h | 2 +- kpatch/kpatch | 46 +++++++++++++++++++++++----------------------- 4 files changed, 32 insertions(+), 34 deletions(-) diff --git a/README b/README index fb53b4580..0c337d504 100644 --- a/README +++ b/README @@ -68,11 +68,11 @@ git://git.fedorahosted.org/git/elfutils.git HOWTO -An example script for automating the hotfix module generation is +An example script for automating the patch module generation is kpatch-build/kpatch-build. The script is written for Fedora but should be adaptable to other distributions with limited changes. -The primary steps in the hotfix module generation process are: +The primary steps in the patch module generation process are: - Building the unstripped vmlinux for the kernel - Patching the source tree - Rebuilding vmlinux and monitoring which objects are building rebuilt. @@ -89,9 +89,9 @@ The primary steps in the hotfix module generation process are: - Use add-patches-section to add the .patches section that the core kpatch module uses to determine the list of functions that need to be redirected using ftrace -- Generate the hotfix kernel module +- Generate the patch kernel module - Use link-vmlinux-syms to hardcode non-exported kernel symbols - into the symbol table of the hotfix kernel module + into the symbol table of the patch kernel module DEMONSTRATION diff --git a/kmod/core/core.c b/kmod/core/core.c index 57f9ee5ea..5c91b11fb 100644 --- a/kmod/core/core.c +++ b/kmod/core/core.c @@ -1,17 +1,15 @@ /* - * kpatch-kmod/base.c - * * Copyright (C) 2014 Seth Jennings * Copyright (C) 2013 Josh Poimboeuf * * Contains the code for the core kpatch module. This module reads - * information from the hotfix modules, find new patched functions, + * information from the patch modules, find new patched functions, * and register those functions in the ftrace handlers the redirects * the old function call to the new function code. * - * Each hotfix can contain one or more patched functions. This information - * is contained in the .patches section of the hotfix module. For each - * function patched by the module we must: + * Each patch module can contain one or more patched functions. This + * information is contained in the .patches section of the patch module. For + * each function patched by the module we must: * - Call stop_machine * - Ensure that no execution thread is currently in the function to be * patched (or has the function in the call stack) diff --git a/kmod/core/kpatch.h b/kmod/core/kpatch.h index 68cb88ee2..15e0f3e2f 100644 --- a/kmod/core/kpatch.h +++ b/kmod/core/kpatch.h @@ -4,7 +4,7 @@ * Copyright (C) 2014 Seth Jennings * Copyright (C) 2013 Josh Poimboeuf * - * Contains the API for the core kpatch module used by the hotfix modules + * Contains the API for the core kpatch module used by the patch modules */ #ifndef _KPATCH_H_ diff --git a/kpatch/kpatch b/kpatch/kpatch index 874ffa16c..6fcb06a33 100755 --- a/kpatch/kpatch +++ b/kpatch/kpatch @@ -1,7 +1,7 @@ #!/bin/bash # This is the primary kpatch user script that manages loading, unloading -# and displaying information on the hotfixes that are installed on the +# and displaying information on the patches that are installed on the # system. # Subcommands: @@ -31,16 +31,16 @@ usage () { } # return either VARDIR or USRDIR (or exits if not found) -find_hotfix () { +find_patch () { [ -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" + echo "Use "kpatch list" for available patches" exit 2 } -# takes full path to hotfix module -load_hotfix () { +# takes full path to patch module +load_patch () { NAME=$(basename $1) NAME=${NAME%.*} insmod $1 @@ -53,7 +53,7 @@ load_hotfix () { } # takes only the module filename -unload_hotfix () { +unload_patch () { NAME=$(basename $1) rmmod ${NAME%.*} if [ $? -ne 0 ] @@ -70,7 +70,7 @@ MODFILE=$2.ko case $1 in "enable") [ $# -ne 2 ] && usage - find_hotfix $MODFILE + find_patch $MODFILE if [ -e $DIR/enabled/$MODFILE ] then echo "Hotfix $2 is already enabled" @@ -79,7 +79,7 @@ case $1 in ln -s $DIR/available/$MODFILE $DIR/enabled/$MODFILE if [ $? -ne 0 ] then - echo "Failed to enable hotfix $2" + echo "Failed to enable patch $2" exit 3 else echo "Hotfix $2 enabled" @@ -87,7 +87,7 @@ case $1 in ;; "disable") [ $# -ne 2 ] && usage - find_hotfix $MODFILE + find_patch $MODFILE if [ ! -e $DIR/enabled/$MODFILE ] then echo "Hotfix $2 is already disabled" @@ -96,7 +96,7 @@ case $1 in rm -f $DIR/enabled/$MODFILE if [ $? -ne 0 ] then - echo "Failed to disable hotfix $2" + echo "Failed to disable patch $2" exit 3 else echo "Hotfix $2 disabled" @@ -108,16 +108,16 @@ case $1 in "--all") for i in $(ls $VARDIR/enabled) do - load_hotfix $VARDIR/enabled/$i + load_patch $VARDIR/enabled/$i done for i in $(ls $USRDIR/enabled) do - load_hotfix $USRDIR/enabled/$i + load_patch $USRDIR/enabled/$i done ;; *) - find_hotfix $MODFILE - load_hotfix $DIR/available/$MODFILE + find_patch $MODFILE + load_patch $DIR/available/$MODFILE ;; esac ;; @@ -127,40 +127,40 @@ case $1 in "--all") for i in $(ls $VARDIR/available) do - unload_hotfix ${i%.*} + unload_patch ${i%.*} done for i in $(ls $USRDIR/available) do - unload_hotfix ${i%.*} + unload_patch ${i%.*} done ;; *) - find_hotfix $MODFILE - unload_hotfix $2 + find_patch $MODFILE + unload_patch $2 ;; esac ;; "list") [ $# -ne 1 ] && usage - echo "User hotfixes available:" + echo "User patches available:" for i in $(ls $VARDIR/available) do echo ${i%.*} done echo "" - echo "User hotfixes enabled:" + echo "User patches enabled:" for i in $(ls $VARDIR/enabled) do echo ${i%.*} done echo "" - echo "System hotfixes available:" + echo "System patches available:" for i in $(ls $USRDIR/available) do echo ${i%.*} done echo "" - echo "System hotfixes enabled:" + echo "System patches enabled:" for i in $(ls $USRDIR/enabled) do echo ${i%.*} @@ -168,7 +168,7 @@ case $1 in ;; "info") [ $# -ne 2 ] && usage - find_hotfix $MODFILE + find_patch $MODFILE echo "Hotfix information for ${2%.*}:" modinfo $DIR/available/$MODFILE ;;