Backporting security patches from Debian Extended LTS to Raspberry PI OS packages

Backport security patches to Raspberry PI OS using a git-based workflow.

This document provides a base to backport security patches provided by Freexian Debian ELTS into Raspberry PI OS packages. We describe a git-based workflow, particularly using git-buildpackage, focusing also on source debian packages in "3.0 (quilt)" format, so the (security) patches to be backported should be found in the debian/patches/ directory, and applied according to debian/patches/series.

Prerequisites

The final outcome of following the workflow described in this document are debian source packages. You should have a working setup to build the binary packages from these source packages in a clean environment, taking the source debian package as input. This means building the packages using sbuild (+schroots), pbuilder, cowbuilder or similar. You should also have the building system able to produce binary packages for the target architecture (such as armhf).

Also, this document assumes you know how to download source packages from the Raspberry PI OS and from Freexian Debian Extended LTS repositories. Either by using apt-get source, or using dget. The Freexian Debian Extended LTS source package repositories are the same as those documented in How to use Extended LTS.

If you are not familiar with git-buildpackage, quilt and their workflows, we invite you to read the documentation listed at the end of the document.

Workflow

Generally the Raspberry PI OS packages include modifications on top of a specific Debian package. Those changes should mainly be present in the debian sources (the debian/ directory). For example, in the debian/rules file, or modifying the patches found in debian/patches/. The Debian Extended LTS security updates would also add new patches to the debian/patches/ directory, so the final goal of this workflow is to “merge” both the Raspberry PI OS and the Freexian Debian Extended LTS changes together.

  1. Prepare a git repository from the source packages

As mentioned above, this document describes a git-based workflow. We document creating a git repository from scratch, but you may adapt the workflow to existing git repositories. Please refer to the git-buildpackage documentation, mentioned in the References at the end of the document. To create the git repository from scratch, you need to download the source packages first. We take as an example the glibc package from Debian 10 “buster”, and the Raspberry PI OS adaptations.

As of July 2024, the latest glibc package released for Raspberry PI OS (legacy), based on buster, was glibc 2.28-10+rpt2+rpi1+deb10u2, as it is found at the Raspberry PI OS glibc archive. It was based on glibc 2.28-10+deb10u2, from Debian 10 LTS. This specific glibc release is no longer available in any Debian regular repository. For the sake of the exercise, you can download it from https://snapshot.debian.org:

workdir$ dget -d https://snapshot.debian.org/archive/debian-security/20221017T122748Z/pool/updates/main/g/glibc/glibc_2.28-10+deb10u2.dsc

However, in practice, all the Debian Extended LTS source packages that you need should be available in the Freexian repositories.

The following command creates a git repository inside the glibc directory:

workdir$ cd glibc
workdir/glibc$ gbp import-dsc --pristine-tar --debian-branch=debian/buster --upstream-branch=upstream/2.28.x glibc_2.28-10+deb10u2.dsc

With the above command we tell gbp import-dsc to use pristine-tar(1), to place the upstream code in the upstream/2.28.x branch, and the debian sources in the debian/buster branch. This follows the recommended layout for Git packaging repositories (DEP-14). You can run git branch to take a look at the resulting branches in the repository:

workdir/glibc$ git branch
* debian/buster
  pristine-tar
  upstream/2.28.x

gbp import-dsc also creates upstream and debian tags for that release.

Now, for the Raspberry PI OS source package. First we have to download it:

workdir$ dget -d https://archive.raspberrypi.org/debian/pool/main/g/glibc/glibc_2.28-10+rpt2+rpi1+deb10u2.dsc

Then import the Raspberry PI OS glibc source package, putting the debian sources in the rpbios/buster branch.

workdir/glibc$ gbp import-dsc --pristine-tar --debian-branch=rbpios/buster --upstream-branch=upstream/2.28.x --create-missing-branches ../glibc_2.28-10+rpt2+rpi1+deb10u2.dsc

You should have now these branches in the repository:

workdir/glibc$ git branch
* debian/buster
  pristine-tar
  rbpios/buster
  upstream/2.28.x

As well as the following tags:

workdir/glibc$ git tag
debian/2.28-10+deb10u2
debian/2.28-10+rpt2+rpi1+deb10u2
upstream/2.28

We can take a look at the differences between both packages with git diff. To limit the size of the document, we highlight here the differences in the patches applied and those in debian/rules:

workdir/glibc$ git diff debian/2.28-10+deb10u2 debian/2.28-10+rpt2+rpi1+deb10u2
[...]
diff --git a/debian/patches/series b/debian/patches/series
index 211d5981..7bb55643 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -28,12 +28,14 @@ alpha/submitted-fts64.diff
 alpha/submitted-makecontext.diff
 
 arm/local-sigaction.diff
-arm/unsubmitted-ldconfig-cache-abi.diff
-arm/unsubmitted-ldso-abi-check.diff
+#arm/unsubmitted-ldconfig-cache-abi.diff
+#arm/unsubmitted-ldso-abi-check.diff
 arm/local-soname-hack.diff
 arm/local-vfp-sysdeps.diff
 arm/unsubmitted-ldso-multilib.diff
 arm/local-arm-futex.diff
+arm/sht_relr_new.diff
+arm/glibc-tls-libwidevinecdm.so-since-4.10.2252.0-has-TLS-with.patch
 
 hppa/local-inlining.diff
 
[...]
diff --git a/debian/rules b/debian/rules
index de564b5f..cda61b8f 100755
--- a/debian/rules
+++ b/debian/rules
@@ -98,7 +98,7 @@ BASE_CXX = g++
 BASE_MIG = mig
 DEB_GCC_VERSION ?= -8
 
-RUN_TESTSUITE = yes
+RUN_TESTSUITE = no
 TIMEOUTFACTOR = 25
 
 # Set cross and native compiler names, including version.

Since the Raspberry PI OS glibc package is very close to the Debian package, we can create a fake merge commit for being able to “import” the changes from the next Debian release in a practical way:

workdir/glibc$ git checkout rbpios/buster
workdir/glibc$ git merge -s ours debian/buster
  1. Importing changes from a new Debian Extended LTS release

Let’s consider now a new release of glibc was published, taking glibc_2.28-10+deb10u3 as example. It is from this version that you want to import the security fixes. Again we’ll use snapshot.debian.org as a source for our howto, but you’ll be getting your updates from the Freexian ELTS repo.

After downloading the new release, import the new source package with gbp import-dsc and merge it into the debian/buster branch:

workdir/glibc$ gbp import-dsc --pristine-tar --debian-branch=debian/buster --upstream-branch=upstream/2.28.x ../glibc_2.28-10+deb10u3.dsc

You can take a look at the differences between the two glibc Debian releases. These differences should be the patches that have been included in the last release, and that you want to apply to the Raspberry PI OS package. Again, to keep this document short, we show only part of the output:

workdir/glibc$ git diff debian/2.28-10+deb10u2 debian/2.28-10+deb10u3
[...]
diff --git a/debian/patches/series b/debian/patches/series
index 211d5981..023965ab 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -175,3 +175,6 @@ all/git-CVE-2021-33574-mq_notify-use-after-free.diff
 all/git-CVE-2021-35942-wordexp-handle-overflow-in-positional-parameter-numb.diff
 all/git-CVE-2022-23218-Buffer-overflow-in-sunrpc-svcunix_cre.diff
 all/git-CVE-2022-23219-Buffer-overflow-in-sunrpc-clnt_create.diff
+
+all/git-0001-iconv-ISO-2022-CN-EXT-fix-out-of-bound-writes-when-w.patch
+all/git-0002-misc-test-errno-linux-Handle-EINVAL-from-quotactl.patch

[...]

If you take a look at the debian/changelog from debian/2.28-10+deb10u3, you will find that these two patches listed above related to CVE-2024-2961. To import the last debian sources (including the patches) into the Raspberry PI OS buster branch, run git merge:

workdir/glibc$ git checkout rbpios/buster
workdir/glibc$ git merge debian/buster
Auto-merging debian/changelog
CONFLICT (content): Merge conflict in debian/changelog
Auto-merging debian/patches/series
Automatic merge failed; fix conflicts and then commit the result.

You should manually fix the conflicts in debian/changelog, resulting in something like this:

glibc (2.28-10+deb10u3) buster-security; urgency=medium

  * Non-maintainer upload by the LTS Team.
  * CVE-2024-2961: Out-of-bounds write in iconv ISO-2022-CN-EXT module
  * Don't ignore test failures during the build.

 -- Adrian Bunk <bunk@debian.org>  Tue, 23 Apr 2024 19:23:00 +0300

glibc (2.28-10+rpt2+rpi1+deb10u2) buster; urgency=medium

  * arm/glibc-tls-libwidevinecdm.so-since-4.10.2252.0-has-TLS-with.patch
    - https://lkml.org/lkml/2020/7/3/754
  * arm/sht_relr_new.diff
    - https://github.com/xbmc/inputstream.adaptive/issues/678#issuecomment-839295299
  * Disable arm/unsubmitted-ldconfig-cache-abi.diff
  * Disable arm/unsubmitted-ldso-abi-check.diff

 -- Serge Schneider <serge@raspberrypi.com>  Thu, 25 May 2023 16:59:39 +0100

You can check that the differences with the debian/buster branch are similar to those before importing the new release:

workdir/glibc$ git diff debian/buster HEAD
[...]
diff --git a/debian/patches/series b/debian/patches/series
index 023965ab..b4ba2d60 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -28,12 +28,14 @@ alpha/submitted-fts64.diff
 alpha/submitted-makecontext.diff
 
 arm/local-sigaction.diff
-arm/unsubmitted-ldconfig-cache-abi.diff
-arm/unsubmitted-ldso-abi-check.diff
+#arm/unsubmitted-ldconfig-cache-abi.diff
+#arm/unsubmitted-ldso-abi-check.diff
 arm/local-soname-hack.diff
 arm/local-vfp-sysdeps.diff
 arm/unsubmitted-ldso-multilib.diff
 arm/local-arm-futex.diff
+arm/sht_relr_new.diff
+arm/glibc-tls-libwidevinecdm.so-since-4.10.2252.0-has-TLS-with.patch
 
 hppa/local-inlining.diff
 
diff --git a/debian/rules b/debian/rules
index de564b5f..cda61b8f 100755
--- a/debian/rules
+++ b/debian/rules
@@ -98,7 +98,7 @@ BASE_CXX = g++
 BASE_MIG = mig
 DEB_GCC_VERSION ?= -8
 
-RUN_TESTSUITE = yes
+RUN_TESTSUITE = no
 TIMEOUTFACTOR = 25
 
 # Set cross and native compiler names, including version.

[...]

For creating a new release based on this merge, you need to add a new changelog entry. You can use gbp dch for that, but you need to adjust the version manually, to make sure the new version will be higher than the one currently available in Raspberry PI OS. In this case, the version should be 2.28-10+rpt2+rpi1+deb10u3, and the resulting debian/changelog:

glibc(2.28-10+rpt2+rpi1+deb10u3) buster; urgency=medium

  * Import changes from Debian changes 2.28-10+deb10u3

 -- Package Maintainer <maintainer@example.com>  Thu, 04 Jul 2024 15:10:25 -0300

You need to verify that the patches apply cleanly:

workdir/glibc$ export QUILT_PATCHES=debian/patches
workdir/glibc$ quilt push -a

If everything goes well, quilt should be able to apply the full list of patches without conflicts or fuzz:

[...]
Applying patch debian/patches/all/git-0002-misc-test-errno-linux-Handle-EINVAL-from-quotactl.patch
patching file sysdeps/unix/sysv/linux/test-errno-linux.c

Now at patch debian/patches/all/git-0002-misc-test-errno-linux-Handle-EINVAL-from-quotactl.patch

In case quilt cannot apply a patch or a patch applies with fuzz, you should manually fix the conflicts and refresh the patch with quilt refresh. Patches that apply with fuzz usually do not require editing and only need a quilt refresh. Repeat iteratively until all the patches apply cleanly.

  1. Build the source package

Once you are finished updating the patches, you can create the source package with debuild or gbp buildpackage. For example:

workdir/glibc$ gbp buildpackage --git-builder=/usr/bin/debuild --git-debian-branch=rbpios/buster --git-no-create-orig -us -uc -S -nc

You should find the files that compose the debian source package (.dsc etc.) in the parent directory (workdir/ in this example), and you can use them to build the binary package from them.

For future releases, you should only need to repeat steps 2 and 3.

Making your packages available in a repository

Beyond integrating the security fixes and building the binary packages, you may be interested in making your packages available via a repository for apt. There are different tools that can be used for that purpose. Describing them in detail is beyond the scope of this document, but we list some of the here for convenience:

You can find more information about in the Debian Administrator’s Handbook.

References

The workflow described here relies on the git-buildpackage and quilt tools. You can find more information about them in: