Creating a User Space Live Patch
- WHAT?
A guide on how to create a live patch on a system library.
- WHY?
You want to understand the entire process of patching a library using user space live patching.
- EFFORT
Approx. 5 minutes reading time.
- GOAL
You will be able to create your own live patch.
1 Creating user space live patches #
The following sections describe how to create live patches for libraries
using the libpulp
. The task comprises the following
actions:
creating the patch
testing the patch
packing the patch into an RPM
deploying the patch
For more information regarding libpulp
, refer to the
ULP
documentation.
2 Creating a live patch for a system library #
In the procedure below, you will create a live patch for the
malloc
function. The patched function will initialize
the memory allocated by the function with the string
glibc-livepatches
. To create the live patch, proceed as
follows:
Create a test program that checks if a live patch has been applied. The program should just allocate a region in memory and check if the string is there. An example follows:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <stdbool.h> #include <string.h> #define NUM_ATTEMPTS 30 #define LEN 32 static const char *const lp_string = "glibc-livepatch"; int main(int argc, char *argv[]) { for (int i = 0; i < NUM_ATTEMPTS; i++) { bool flag = false; char *m = malloc(LEN); m[LEN-1] = '\0'; fprintf(stderr, "%s\n", m); if (m) { if (!strcmp(m, lp_string)) { flag = true; } free(m); } m = calloc(1, 32); if (m) { free(m); } else if (flag) { return 0; } sleep(1); } return 1; }
Compile the program:
>
gcc -o test test.c
Create a file containing the new
malloc
function, for example,libc_livepatch1.c
.The code snippet shown below implements the new
malloc
function by using thecalloc
function to allocate memory and then overwrite its content with the glibc-livepatch string. The file is calledlibc_livepatch1.c
.#include <stdlib.h> #include <string.h> #define MIN(x, y) ((x) < (y) ? (x) : (y)) static const char *const lp_string = "glibc-livepatch"; void *malloc_lp(size_t s) { char *block = calloc(1, s); if (block && s > 0) { int lp_string_len = strlen(lp_string); int copy_len = MIN(lp_string_len + 1, s); memcpy(block, lp_string, copy_len); block[s-1] = '\0'; } return block; }
Compile the file for x86 as follows:
>
gcc -fPIC -fpatchable-function-entry=16,14 -shared -o libc_livepatch1.so libc_livepatch1.c
Create a live patch description file. The file must contain the following information:
A path to the live patch container, in this case the path to the
libc_livepatch1.so.6
file.A path to the target library—
/usr/lib64/libc.so
in this case.The function name that will be patched and its replacement. You can also describe multiple replacements.
The description file for the example live patch looks as follows:
libc_livepatch1.so @/usr/lib64/libc.so.6 __libc_malloc:malloc_lp
The patch is for the
__libc_malloc
function, not formalloc
, because themalloc
name is an indirect function, not a regular function, and in the end it calls the__libc_malloc
function. For details about ifunc, refer to the indirect function description.
Build the live patch container:
>
gcc -fPIC -fpatchable-function-entry=16,14 -shared -o libc_livepatch1.so libc_livepatch1.c
Embed the description file into the live patch container:
>
ulp packer libc_livepatch1.dsc
3 Testing the live patch #
After you prepare the live patch and its test program as described in Section 2, “Creating a live patch for a system library”, you can test if the live patch works:
Launch the test program:
>
LD_PRELOAD=/usr/lib64/libpulp.so.0 ./test
Install the live patch:
>
ulp trigger libc_livepatch.so
If the installation was successful, the ULP tool displays the message
SUCCESS
. You should also see the
glibc-livepatch
message from the test program.
4 Files required in a live patch package #
To prepare a live patch package, use the glibc-livepatches as a reference source. The package contains the following files:
glibc-livepatches.spec
; for details, refer to Section 4.1, “Theglibc-livepatches.spec
file”.glibc-livepatches-VERSION.tar.xz
; for details, refer to Section 4.2, “Theglibc-livepatches.tar.xz
file”.
4.1 The glibc-livepatches.spec
file #
The glibc-livepatches.spec
file contains
instructions on how to prepare, build, install and apply the live patch.
The file also calls the ulp_post_hook
script. The
script calls the ULP trigger with extracted boilerplate code to avoid
adding such a code to every package. To check the code, view the file
/usr/lib/userspace-livepatch/rpm-helper
. The call to
the ULP trigger is performed with the –revert-all
command that reverts all already installed patches. Make sure that your
patch is cumulative and contains fixes for the previous versions of the
patch.
4.2 The glibc-livepatches.tar.xz
file #
The glibc-livepatches.tar.xz
file contains the
actual source code of the live patch. The archive must also contain
information about all glibc
versions issued for the
particular SLES version.
5 Making an RPM from the live patch #
To prepare a live patch package, follow the steps below:
Extract the
glibc-livepatches
package.Add the live patch source files.
Run the following command to update the package so that it includes all
glibc
versions released for the particular SLES version.>
make download
Run the following command to check if the live patch is buildable.
>
make
If the process is successfully completed, one
.so
file is created for eachglibc
version. For example,libc_2.31-150300.26.5_livepatch1.so
.To ensure that your package does not contain any of your temporary build files, run the command:
>
make clean
To create a new
.tar.xz
, run the command:>
make dist
Build the package with OSC.
If the build is successful, you can upload the package to a repository.
6 Deploying the live patch package #
If you have the RPM
package ready and tested, you can
submit a merge request to the glibc-livepatches
SLES16.0 update repository.
>
osc -A https://api.suse.de mr YOUR_HOME glibc-livepatches SUSE:SLE-15-SP5:GA
7 Legal Notice #
Copyright© 2006–2024 SUSE LLC and contributors. All rights reserved.
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or (at your option) version 1.3; with the Invariant Section being this copyright notice and license. A copy of the license version 1.2 is included in the section entitled “GNU Free Documentation License”.
For SUSE trademarks, see https://www.suse.com/company/legal/. All other third-party trademarks are the property of their respective owners. Trademark symbols (®, ™ etc.) denote trademarks of SUSE and its affiliates. Asterisks (*) denote third-party trademarks.
All information found in this book has been compiled with utmost attention to detail. However, this does not guarantee complete accuracy. Neither SUSE LLC, its affiliates, the authors, nor the translators shall be held liable for possible errors or the consequences thereof.