📜 ⬆️ ⬇️

How to patch a kernel without rebooting: livepatch, kpatch and Canonical Livepatch Service

pr-3322

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:

 #  $ codename=$(lsb_release -sc) $ sudo tee /etc/apt/sources.list.d/ddebs.list << EOF deb http://ddebs.ubuntu.com/ ${codename} main restricted universe multiverse deb http://ddebs.ubuntu.com/ ${codename}-security main restricted universe multiverse deb http://ddebs.ubuntu.com/ ${codename}-updates main restricted universe multiverse deb http://ddebs.ubuntu.com/ ${codename}-proposed main restricted universe multiverse EOF #  wget -Nq http://ddebs.ubuntu.com/dbgsym-release-key.asc -O- | sudo apt-key add - #   $ sudo apt-get update #   $ sudo apt-get install linux-image-$(uname -r)-dbgsym 

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 .

Source: https://habr.com/ru/post/317034/


All Articles