
We have already reviewed the topic of updating kernel patches without rebooting in an
article published in 2014. It dealt with KernelCare, a tool developed by our partners from Cloud Linux. At the time of writing this article, KernelCare was almost the only tool that can be fully used for patching.
Two and a half years have passed - and the situation has changed, moreover, dramatically: starting from version 4.0, the possibility of applying patches “on the fly” has been officially added to the core.
The
kpatch and
kGraft tools , which were in a “raw” condition in 2014, were also significantly improved. Kpatch has even been added to the official repositories — for example, you can already install it on Ubuntu 16.04 using the standard package manager.
')
And Canonical recently introduced the
Canonical Livepatch Service , with which you can patch the Ubuntu core without rebooting.
In more detail about some modern tools for adding patches we will tell in this article.
The simplest example: livepatch
Let's start with a very simple experiment. To do this, we need any Linux distribution with a kernel version 4.0 or higher (in our case it is Ubuntu 16.04; hereinafter all examples of commands are provided just for this distribution). In new versions of the kernel, the function of adding patches “on the fly” (it is called livepatch) is enabled by default.
To check how it works, we need to first install the kernel headers:
$ sudo apt-get install linux-headers-$(uname -r)
Next, install the kernel debugging symbols:
Next, run:
$ sudo apt-get build-dep linux
When you run this command on Ubuntu 16.04, you may receive the following error message:
E: You must put some 'source' URIs in your sources.list
The reason for the error is that the deb-src repositories are not connected by default, and the corresponding lines in the /etc/apt/sources.list file are commented out. So that we could work with source code repositories, let's execute:
$ sudo sed -i -- 's/#deb-src/deb-src/g' /etc/apt/sources.list && sudo sed -i -- 's/# deb-src/deb-src/g' /etc/apt/sources.list $ sudo apt-get update
After that, the previous command will be executed without errors. Everything is ready for the experiment, you can start:
wget http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/plain/samples/livepatch/livepatch-sample.c
We downloaded the code for the kernel module, which changes the core code and modifies the output of the cat / proc / cmdline command. Now this very module needs to be assembled. To do this, create the following makefile:
obj-m +=livepatch-sample.o KDIR= /lib/modules/$(shell uname -r)/build all: $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules clean: rm -rf *.o *.ko *.mod.* .c* .t*
We assemble the module and insert it into the kernel:
$ make $ insmod livepatch-sample.ko
Let's see what happened. Perform:
$ cat /proc/cmdinfo
Instead of standard information about kernel parameters, we will see the following text:
this has been live patched
As you can see, the patch was successfully applied.
All information about downloaded patches is stored in the / sys / kernel / livepatch directory:
$ ls /sys/kernel/livepatch/ livepatch_sample
You can deactivate a patch using the command:
$ echo 0 > /sys/kernel_livepatch/livepatch_sample/enabled
Kpatch
Kpatch is a tool developed by Red Hat companies. It was first
introduced to a wide user audience in February 2016. During this time, it has been significantly improved: in Ubuntu 16.04, it is already included in the official repositories. Consider the features of working with kpatch on practical examples.
Let's start by installing the necessary dependencies:
$ sudo apt-get install libelf-dev dpkg-dev
To fully work with kpatch, it is also advisable to install
ccache :
$ sudo apt-get install ccache $ ccache --max-size=5G
That's all, dependencies are installed. You can install kpatch:
$ sudo apt-get install kpatch kpatch-build
In our experiment, we will patch the source of the kernel. Clone the repository with the source code of our current version of Ubuntu:
git clone git://kernel.ubuntu.com/ubuntu/ubuntu-xenial.git
When the cloning is complete, copy the source files to the ubuntu-xenial-kpatch directory (this is necessary to make changes to the source code and then create patches based on these changes):
$ mkdir ubuntu-xenial-kpatch $ cp -r ubuntu-xenial ubuntu-xenial-kpatch
Open the file ubuntu-xenial-kpatch / ubuntu-xenial / fs / proc / version.c and make the following changes to it:
#include <linux/fs.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/utsname.h> static int version_proc_show(struct seq_file *m, void *v) { seq_printf(m, linux_proc_banner, "This has been patched!", utsname()->sysname, utsname()->release, utsname()->version); return 0; }
Create a patch with the command:
$ diff -u ubuntu-xenial/fs/proc/version.c ubuntu-xenial.kpatch/ubuntu-xenial/proc.version.c > version.patch
The patch is a plain text file, which lists the changes:
--- ubuntu-xenial/fs/proc/version.c 2016-12-05 10:04:30.126141156 +0300 +++ ubuntu-xenial.kpatch/ubuntu-xenial/fs/proc/version.c 2016-12-05 10:10:35.678461801 +0300 @@ -8,6 +8,7 @@ static int version_proc_show(struct seq_file *m, void *v) { seq_printf(m, linux_proc_banner, + "This has been patched!", utsname()->sysname, utsname()->release, utsname()->version);
To add a patch to the kernel, run:
$ kpatch-build -t vmlinux --skip-gcc-check version.patch WARNING: Skipping gcc version matching check (not recommended) Debian/Ubuntu distribution detected Downloading the kernel source for 4.4.0-51-generic Unpacking kernel source Testing patch file checking file fs/proc/version.c Reading special section data Building original kernel Building patched kernel Detecting changed objects Rebuilding changed objects Extracting new and modified ELF sections version.o: changed function: version_proc_show Building patch module: kpatch-version.ko SUCCESS
As can be seen from the just given output, at the output we get the kernel module. To apply a patch, you just need to add this module in the standard way:
sudo insmod kpatch-version.ko
Let's see what happened as a result:
cat /proc/version This has been patched! version Linux (buildd@lcy01-08) (gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4) ) 4.4.0-51-generic
Everything is working!
Canonical Livepatch Service
A few months ago, Canonical launched the official Canonical LivePatch Service, which allows you to patch the kernel on the fly using simple commands. This service is primarily aimed at enterprise-level users, and therefore is paid.
But ordinary users can also quickly receive all the latest kernel updates. To do this, register with Ubuntu One and
get a token . Token allows you to install a canonical-livepatch program on 3 machines that loads and adds patches.
Let's see how the Canonical Livepatch Service works. Let's follow the link above, get a token, and then execute:
$ sudo snap install canonical-livepatch
When the installation is complete, we log out, then log in again and run:
$ sudo canonical-livepatch enable []
If everything was done correctly, we will receive the following message:
Successfully enabled device. Using machine-token: []
Next, run the command:
$ canonical-livepatch status kernel: 4.4.0-47.68-generic fully-patched: true version: "14.1"
The output shows that the canonical-livepatch works, and all the latest updates are installed in the kernel. More information can be obtained using the option −−verbose:
$ canonical-livepatch status --verbose client-version: "6" machine-id: [id] machine-token:[token] architecture: x86_64 cpu-model: Intel(R) Xeon(R) CPU E5-2670 v3 @ 2.30GHz last-check: 2016-12-05T11:56:02.88803394+03:00 boot-time: 2016-11-29T10:48:38+03:00 uptime: 145h18m21s status: - kernel: 4.4.0-47.68-generic running: true livepatch: checkState: checked patchState: applied version: "14.1" fixes: |- * CVE-2016-7425 * CVE-2016-8658
Also, information on installed patches can be obtained by looking into the / sys / kernel / livepatch directory already mentioned above:
$ ls /sys/kernel/livepatch kpatch_livepatch_Ubuntu_4_4_0_47_68_generic_14
Kpatch_livepatch_Ubuntu_4_4_0_47_68_generic_14 - this is the last downloaded patch. The last digits in the patch name (14) match the version number indicated in the output of the canonical-livepatch status command (see above).
You can also make sure that a new patch has been added using the lsmod command:
$ lsmod |grep livepatch kpatch_livepatch_Ubuntu_4_4_0_47_68_generic_14 36864 1
Conclusion
In this article, we made a small selection of tools for adding patches to the Linux kernel. Naturally, all aspects of a topic in one publication cannot be touched upon. If you have comments and additions - welcome to comments.
And if you want to explore the topic more deeply, pay attention to the following links:
If for some reason you can not leave comments here - welcome to
our corporate blog .