Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 3 additions & 7 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -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
8 changes: 0 additions & 8 deletions Makefile

This file was deleted.

34 changes: 24 additions & 10 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,20 @@ 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

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:

sudo kpatch-build/kpatch-build ~/foo.patch
insmod kpatch.ko kpatch-foo.ko

Voila, your kernel is patched.

LICENSE

kpatch is under the GPLv2 license.
Expand All @@ -38,7 +52,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
Expand All @@ -54,11 +68,11 @@ 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 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.
Expand All @@ -67,17 +81,17 @@ 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
into the symbol table of 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 patch kernel module

DEMONSTRATION

Expand Down
File renamed without changes.
4 changes: 2 additions & 2 deletions kpatch-kmod/Makefile → kmod/core/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 4 additions & 6 deletions kpatch-kmod/base.c → kmod/core/core.c
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
/*
* kpatch-kmod/base.c
*
* Copyright (C) 2014 Seth Jennings <sjenning@redhat.com>
* Copyright (C) 2013 Josh Poimboeuf <jpoimboe@redhat.com>
*
* 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)
Expand Down
2 changes: 1 addition & 1 deletion kpatch-kmod/kpatch.h → kmod/core/kpatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* Copyright (C) 2014 Seth Jennings <sjenning@redhat.com>
* Copyright (C) 2013 Josh Poimboeuf <jpoimboe@redhat.com>
*
* 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_
Expand Down
File renamed without changes.
20 changes: 20 additions & 0 deletions kmod/patch/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
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-$(KPATCH_NAME).o

kpatch-$(KPATCH_NAME)-objs += kpatch-patch-hook.o kpatch.lds output.o

all: kpatch-$(KPATCH_NAME).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

clean:
$(RM) -Rf .*.o.cmd .*.ko.cmd .tmp_versions *.o *.ko *.mod.c \
Module.symvers
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

#include <linux/module.h>
#include <linux/printk.h>
#include "../kpatch-kmod/kpatch.h"
#include "kpatch.h"

extern char __kpatch_patches, __kpatch_patches_end;

Expand Down
File renamed without changes.
2 changes: 2 additions & 0 deletions tools/Makefile → kpatch-build/Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
CFLAGS=-I../kmod/core

all: create-diff-object add-patches-section link-vmlinux-syms

create-diff-object: create-diff-object.c
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
#include <gelf.h>
#include <unistd.h>

#include "../kpatch-kmod/kpatch.h"
#include "kpatch.h"

#define ERROR(format, ...) \
error(1, 0, "%s: %d: " format, __FUNCTION__, __LINE__, ##__VA_ARGS__)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
#include <error.h>
#include <gelf.h>

#include "../kpatch-kmod/kpatch.h"
#include "kpatch.h"

#define ERROR(format, ...) \
error(1, 0, "%s: %d: " format, __FUNCTION__, __LINE__, ##__VA_ARGS__)
Expand Down
108 changes: 68 additions & 40 deletions scripts/kpatch-build → kpatch-build/kpatch-build
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#/bin/bash
#!/bin/bash

# kpatch build script for Fedora

Expand All @@ -24,25 +24,29 @@

BASE=$PWD
LOGFILE=$PWD/kpatch-build.log
KPATCHPATH=/usr/local/share/kpatch
TOOLSDIR=$BASE/kpatch-build
ARCHVERSION=$(uname -r)
DISTROVERSION=${ARCHVERSION%*.*}
CPUS=$(grep -c ^processor /proc/cpuinfo)
LOCALVERSION=$(uname -r)
LOCALVERSION=-${LOCALVERSION##*-}
KSRCDIR=~/.kpatch/$ARCHVERSION
KSRCDIR_DIR=$(dirname $KSRCDIR)
KSRCDIR_CACHE=$KSRCDIR.tgz

cleanup() {
rm -Rf kernel-$DISTROVERSION.src.rpm rpmbuild $LOGFILE $TEMPDIR > /dev/null 2>/dev/null
rm -Rf $KSRCDIR 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

Expand All @@ -53,34 +57,56 @@ then
exit 3
fi

cleanup
PATCHNAME=`basename $PATCHFILE`
if [[ $PATCHNAME =~ \.patch ]] || [[ $PATCHNAME =~ \.diff ]]
then
PATCHNAME=${PATCHNAME%.*}
fi

echo "Verifying required development tools"
yum install rpmdevtools yum-utils || die
cleanup

echo "Downloading kernel source for $ARCHVERSION"
yumdownloader --source kernel-$ARCHVERSION || die
echo "Building tools"
make -C $TOOLSDIR >> $LOGFILE 2>&1 || 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 [ -f "$KSRCDIR_CACHE" ]
then
echo "Using cache at $KSRCDIR_CACHE"
rm -rf $KSRCDIR
tar xzf $KSRCDIR_CACHE -C $KSRCDIR_DIR || die
cd $KSRCDIR || die
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 $KSRCDIR_DIR
mv ~/rpmbuild/BUILD/kernel-*/linux-$ARCHVERSION $KSRCDIR >> $LOGFILE 2>&1 || die

echo "Building original kernel"
cd $KSRCDIR
echo $LOCALVERSION > localversion
make -j$CPUS vmlinux >> $LOGFILE 2>&1 || die

echo "Creating cache"
tar czf $KSRCDIR_CACHE -C $KSRCDIR_DIR $ARCHVERSION
fi

echo "Building the base kernel"
make -j$CPUS vmlinux >> $LOGFILE 2>&1 || die
TEMPDIR=`mktemp -d` || die
cp -R $KPATCHPATH/* $TEMPDIR || die
cp -R $BASE/kmod/patch/* $BASE/kmod/core $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

Expand All @@ -103,34 +129,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`
./tools/create-diff-object base/$FILE patched/$FILE output/$FILE >> $LOGFILE 2>&1
$TOOLSDIR/create-diff-object orig/$FILE patched/$FILE output/$FILE >> $LOGFILE 2>&1 || die
done

echo "Building hotfix module"
echo "Building core module: kpatch.ko"
cd core
KPATCH_BUILD=$KSRCDIR make >> $LOGFILE 2>&1 || die
cd ..

echo "Building patch module: kpatch-$PATCHNAME.ko"
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"
$TOOLSDIR/add-patches-section output.o 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-$PATCHNAME.ko $TEMPDIR/core/kpatch.ko $BASE
cleanup
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
#include <gelf.h>
#include <unistd.h>

#include "../kpatch-kmod/kpatch.h"
#include "kpatch.h"

#define ERROR(format, ...) \
error(1, 0, "%s: %d: " format, __FUNCTION__, __LINE__, ##__VA_ARGS__)
Expand Down
18 changes: 0 additions & 18 deletions kpatch-files/Makefile

This file was deleted.

Loading