Skip to content

Commit

Permalink
kpatch: better support for livepatch modules
Browse files Browse the repository at this point in the history
Livepatch modules can be supported with minimal changes to the kpatch
script.  Adjust for appropriate sysfs paths, core-patching code (in
kernel for livepatch, kpatch.ko for kpatch), and checksum verification
(only verify the checksum if it exists).

Fixes dynup#479.
  • Loading branch information
joe-lawrence committed Dec 19, 2016
1 parent 86e21e9 commit d55b58c
Showing 1 changed file with 23 additions and 13 deletions.
36 changes: 23 additions & 13 deletions kpatch/kpatch
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ INSTALLDIR=/var/lib/kpatch
SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))"
VERSION="0.3.4"

# Assume livepatch core is built into the kernel, otherwise
# use kpatch model.
if [[ -e /sys/kernel/livepatch ]] ; then
SYSFS="/sys/kernel/livepatch"
else
SYSFS="/sys/kernel/kpatch/patches"
fi

usage_cmd() {
printf ' %-20s\n %s\n' "$1" "$2" >&2
}
Expand Down Expand Up @@ -116,29 +124,31 @@ find_core_module() {
return 1
}

core_module_loaded () {
grep -q "T kpatch_register" /proc/kallsyms
core_loaded () {
grep -q -e "T klp_register_patch" -e "T kpatch_register" /proc/kallsyms
}

get_module_name () {
echo $(readelf -p .gnu.linkonce.this_module $1 | grep '\[.*\]' | awk '{print $3}')
}

verify_module_checksum () {
modname=$(get_module_name $1)
[[ -z $modname ]] && return 1
modname=$(get_module_name $1)
[[ -z $modname ]] && return 1

checksum=$(readelf -p .kpatch.checksum $1 | grep '\[.*\]' | awk '{print $3}')
[[ -z $checksum ]] && return 1
checksum=$(readelf -p .kpatch.checksum $1 | grep '\[.*\]' | awk '{print $3}')

sysfs_checksum=$(cat /sys/kernel/kpatch/patches/${modname}/checksum)
[[ $checksum == $sysfs_checksum ]] || return 1
# Fail checksum match only if both exist and diverge
if [[ ! -z $checksum ]] && [[ -e "$SYSFS/${modname}/checksum" ]] ; then
sysfs_checksum=$(cat $SYSFS/${modname}/checksum)
[[ $checksum == $sysfs_checksum ]] || return 1
fi
}

load_module () {
local module="$1"

if ! core_module_loaded; then
if ! core_loaded; then
if modprobe -q kpatch; then
echo "loaded core module"
else
Expand All @@ -149,7 +159,7 @@ load_module () {
fi

local modname=$(get_module_name $module)
local moddir=/sys/kernel/kpatch/patches/$modname
local moddir="$SYSFS/$modname"
if [[ -d $moddir ]] ; then
if [[ $(cat "${moddir}/enabled") -eq 0 ]]; then
if verify_module_checksum $module; then # same checksum
Expand Down Expand Up @@ -191,7 +201,7 @@ load_module () {
unload_module () {
PATCH="${1//-/_}"
PATCH="${PATCH%.ko}"
ENABLED=/sys/kernel/kpatch/patches/"$PATCH"/enabled
ENABLED="$SYSFS/$PATCH/enabled"
[[ -e "$ENABLED" ]] || die "patch module $1 is not loaded"
if [[ $(cat "$ENABLED") -eq 1 ]]; then
echo "disabling patch module: $PATCH"
Expand Down Expand Up @@ -233,7 +243,7 @@ case "$1" in
[[ "$#" -ne 2 ]] && usage
case "$2" in
"--all")
for module in /sys/kernel/kpatch/patches/*; do
for module in $SYSFS/*; do
[[ -e $module ]] || continue
unload_module $(basename $module) || die "failed to unload module $module"
done
Expand Down Expand Up @@ -320,7 +330,7 @@ case "$1" in
"list")
[[ "$#" -ne 1 ]] && usage
echo "Loaded patch modules:"
for module in /sys/kernel/kpatch/patches/*; do
for module in $SYSFS/*; do
if [[ -e $module ]] && [[ $(cat $module/enabled) -eq 1 ]]; then
echo $(basename "$module")
fi
Expand Down

0 comments on commit d55b58c

Please sign in to comment.