Package: release.debian.org
Severity: normal
Tags: trixie
X-Debbugs-Cc: [email protected], [email protected]
Control: affects -1 + src:rauc
User: [email protected]
Usertags: pu

  * CVE-2026-34155: Improper Signing of Plain Bundles Exceeding 2 GiB
diffstat for rauc-1.13 rauc-1.13

 changelog                                                               |    7 
 patches/0001-src-signature-protect-against-integer-overflows-with.patch |   45 
++
 patches/0002-src-signature-reject-plain-bundles-with-payload-exce.patch |  173 
++++++++++
 patches/series                                                          |    4 
 4 files changed, 229 insertions(+)

diff -Nru rauc-1.13/debian/changelog rauc-1.13/debian/changelog
--- rauc-1.13/debian/changelog  2025-04-16 09:14:43.000000000 +0300
+++ rauc-1.13/debian/changelog  2026-06-28 21:27:01.000000000 +0300
@@ -1,3 +1,10 @@
+rauc (1.13-3+deb13u1) trixie; urgency=medium
+
+  * Non-maintainer upload.
+  * CVE-2026-34155: Improper Signing of Plain Bundles Exceeding 2 GiB
+
+ -- Adrian Bunk <[email protected]>  Sun, 28 Jun 2026 21:27:01 +0300
+
 rauc (1.13-3) unstable; urgency=medium
 
   * Add patches from upstream to prevent an incompatibility introduced in
diff -Nru 
rauc-1.13/debian/patches/0001-src-signature-protect-against-integer-overflows-with.patch
 
rauc-1.13/debian/patches/0001-src-signature-protect-against-integer-overflows-with.patch
--- 
rauc-1.13/debian/patches/0001-src-signature-protect-against-integer-overflows-with.patch
    1970-01-01 02:00:00.000000000 +0200
+++ 
rauc-1.13/debian/patches/0001-src-signature-protect-against-integer-overflows-with.patch
    2026-06-28 21:26:23.000000000 +0300
@@ -0,0 +1,45 @@
+From ae603ef8d2edf115888ffb350870bdc63fb50b40 Mon Sep 17 00:00:00 2001
+From: Jan Luebbe <[email protected]>
+Date: Wed, 25 Mar 2026 18:02:36 +0100
+Subject: src/signature: protect against integer overflows with
+ BIO_new_mem_buf()
+
+BIO_new_mem_buf()'s len argument is of type int, so it cannot support
+lengths exceeding 2 GiB. Reject larger lengths and additionally check
+that we have created the BIO correctly.
+
+These are only internal checks, GError handling will be added in a later
+commit.
+
+Signed-off-by: Jan Luebbe <[email protected]>
+---
+ src/signature.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/src/signature.c b/src/signature.c
+index d7c9b3bd..a872c5b7 100644
+--- a/src/signature.c
++++ b/src/signature.c
+@@ -410,11 +410,19 @@ static BIO *bytes_as_bio(GBytes *bytes)
+               g_error("bytes_as_bio: no data");
+       if (size == 0)
+               g_error("bytes_as_bio: size is zero");
++      if (size > INT_MAX)
++              g_error("bytes_as_bio: size is too large for BIO_new_mem_buf");
+ 
+       bio = BIO_new_mem_buf(data, size);
+       if (!bio)
+               g_error("bytes_as_bio: BIO_new_mem_buf() failed");
+ 
++      /* ensure that we've passed the data correctly */
++      const BUF_MEM *bio_mem_buf = NULL;
++      BIO_get_mem_ptr(bio, &bio_mem_buf);
++      g_assert(bio_mem_buf->data == data);
++      g_assert(bio_mem_buf->length == size);
++
+       return bio;
+ }
+ 
+-- 
+2.47.3
+
diff -Nru 
rauc-1.13/debian/patches/0002-src-signature-reject-plain-bundles-with-payload-exce.patch
 
rauc-1.13/debian/patches/0002-src-signature-reject-plain-bundles-with-payload-exce.patch
--- 
rauc-1.13/debian/patches/0002-src-signature-reject-plain-bundles-with-payload-exce.patch
    1970-01-01 02:00:00.000000000 +0200
+++ 
rauc-1.13/debian/patches/0002-src-signature-reject-plain-bundles-with-payload-exce.patch
    2026-06-28 21:26:23.000000000 +0300
@@ -0,0 +1,173 @@
+From 5c1cac2abbc7261d44695a4e350042af5474bc24 Mon Sep 17 00:00:00 2001
+From: Jan Luebbe <[email protected]>
+Date: Wed, 25 Mar 2026 18:06:29 +0100
+Subject: src/signature: reject plain bundles with payload exceeding 2 GiB
+
+Due to BIO_new_mem_buf() only supporting buffers of up to 2 GiB, we
+cannot sign or verify bundles with a payload larger than that.
+
+This fixes an integer overflow which would lead to calling
+BIO_new_mem_buf() with a negative len, which will cause it to use
+strlen() to  to determine the buffer size automatically. As a result,
+the buffer is truncated at the first '\0' byte in the SquashFS header.
+The first 4 bytes are a fixed magic number ("hsqs"), and since a '\0'
+byte appears within the inode count field at bytes 5-8 in most SquashFS
+images, the resulting signature will only cover this part of the
+SquashFS header.
+
+As we sign or verify the payload directly via OpenSSL only for the
+'plain' format, the 'verity' and 'crypt' formats are not affected.
+
+Fix this by checking the content size before calling cms_sign_file() or
+cms_verify_bytes(), which call BIO_new_mem_buf() via bytes_as_bio().
+
+Signed-off-by: Jan Luebbe <[email protected]>
+---
+ src/signature.c  | 24 ++++++++++++++++++++++++
+ test/signature.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 70 insertions(+)
+
+diff --git a/src/signature.c b/src/signature.c
+index a872c5b7..624aca46 100644
+--- a/src/signature.c
++++ b/src/signature.c
+@@ -1424,6 +1424,7 @@ GBytes *cms_sign_file(const gchar *filename, const gchar 
*certfile, const gchar
+       GError *ierror = NULL;
+       g_autoptr(GMappedFile) file = NULL;
+       g_autoptr(GBytes) content = NULL;
++      gsize content_size = 0;
+       GBytes *sig = NULL;
+ 
+       g_return_val_if_fail(filename != NULL, FALSE);
+@@ -1438,6 +1439,17 @@ GBytes *cms_sign_file(const gchar *filename, const 
gchar *certfile, const gchar
+       }
+       content = g_mapped_file_get_bytes(file);
+ 
++      G_STATIC_ASSERT(INT_MAX >= INT32_MAX);
++      content_size = g_bytes_get_size(content);
++      if (content_size > INT32_MAX) {
++              g_set_error(
++                              error,
++                              R_SIGNATURE_ERROR,
++                              R_SIGNATURE_ERROR_LOAD_FAILED,
++                              "Bundle payload size %"G_GSIZE_FORMAT " exceeds 
maximum for bundles using plain format (2 GiB)", content_size);
++              goto out;
++      }
++
+       sig = cms_sign(content, TRUE, certfile, keyfile, interfiles, &ierror);
+       if (sig == NULL) {
+               g_propagate_error(error, ierror);
+@@ -1483,6 +1495,7 @@ gboolean cms_verify_fd(gint fd, GBytes *sig, goffset 
limit, X509_STORE *store, C
+       GError *ierror = NULL;
+       g_autoptr(GMappedFile) file = NULL;
+       g_autoptr(GBytes) content = NULL;
++      gsize content_size = 0;
+       gboolean res = FALSE;
+ 
+       g_return_val_if_fail(fd >= 0, FALSE);
+@@ -1519,6 +1532,17 @@ gboolean cms_verify_fd(gint fd, GBytes *sig, goffset 
limit, X509_STORE *store, C
+               content = tmp;
+       }
+ 
++      G_STATIC_ASSERT(INT_MAX >= INT32_MAX);
++      content_size = g_bytes_get_size(content);
++      if (content_size > INT32_MAX) {
++              g_set_error(
++                              error,
++                              R_SIGNATURE_ERROR,
++                              R_SIGNATURE_ERROR_LOAD_FAILED,
++                              "Bundle payload size %"G_GSIZE_FORMAT " exceeds 
maximum for bundles using plain format (2 GiB)", content_size);
++              goto out;
++      }
++
+       res = cms_verify_bytes(content, sig, store, cms, NULL, &ierror);
+       if (!res) {
+               g_propagate_error(error, ierror);
+diff --git a/test/signature.c b/test/signature.c
+index 7fc9a4f3..7a16c1b1 100644
+--- a/test/signature.c
++++ b/test/signature.c
+@@ -10,6 +10,7 @@
+ #include "common.h"
+ 
+ typedef struct {
++      gchar *tmpdir;
+       GBytes *content;
+       GBytes *sig;
+       GError *error;
+@@ -23,6 +24,8 @@ static void signature_set_up(SignatureFixture *fixture,
+ {
+       r_context_conf();
+ 
++      fixture->tmpdir = g_dir_make_tmp("rauc-XXXXXX", NULL);
++      g_assert_nonnull(fixture->tmpdir);
+       fixture->content = read_file("test/openssl-ca/manifest", NULL);
+       g_assert_nonnull(fixture->content);
+       fixture->sig = NULL;
+@@ -39,6 +42,10 @@ static void signature_set_up(SignatureFixture *fixture,
+ static void signature_tear_down(SignatureFixture *fixture,
+               gconstpointer user_data)
+ {
++      if (fixture->tmpdir)
++              g_assert_true(rm_tree(fixture->tmpdir, NULL));
++
++      g_free(fixture->tmpdir);
+       g_bytes_unref(fixture->content);
+       g_bytes_unref(fixture->sig);
+       g_clear_error(&fixture->error);
+@@ -275,6 +282,44 @@ static void signature_verify_file(SignatureFixture 
*fixture,
+       g_clear_error(&fixture->error);
+ }
+ 
++static void signature_too_large(SignatureFixture *fixture,
++              gconstpointer user_data)
++{
++      gboolean res = FALSE;
++
++      g_autofree gchar *payloadname = write_random_file(fixture->tmpdir, 
"payload", 1024, 1234);
++      g_assert_nonnull(payloadname);
++      fixture->sig = read_file("test/openssl-ca/manifest-r1.sig", NULL);
++      g_assert_nonnull(fixture->sig);
++
++      goffset large_size = (goffset)INT32_MAX+1;
++
++      g_assert_cmpint(truncate(payloadname, large_size), ==, 0);
++      g_autoptr(GBytes) sig = cms_sign_file(payloadname,
++                      "test/openssl-ca/rel/release-1.cert.pem",
++                      "test/openssl-ca/rel/private/release-1.pem",
++                      NULL,
++                      &fixture->error);
++      g_assert_null(sig);
++      g_assert_error(fixture->error, R_SIGNATURE_ERROR, 
R_SIGNATURE_ERROR_LOAD_FAILED);
++      g_clear_error(&fixture->error);
++
++      g_assert_cmpint(truncate(payloadname, large_size + 1024), ==, 0);
++      gint fd = g_open(payloadname, O_RDONLY|O_CLOEXEC, 0);
++      g_assert_cmpint(fd, >=, 0);
++      res = cms_verify_fd(fd,
++                      fixture->sig,
++                      large_size,
++                      fixture->store,
++                      &fixture->cms,
++                      &fixture->error);
++      g_assert_false(res);
++      g_assert_error(fixture->error, R_SIGNATURE_ERROR, 
R_SIGNATURE_ERROR_LOAD_FAILED);
++      g_assert_null(fixture->cms);
++      g_clear_error(&fixture->error);
++      g_close(fd, NULL);
++}
++
+ static void signature_loopback_detached(SignatureFixture *fixture,
+               gconstpointer user_data)
+ {
+@@ -828,6 +873,7 @@ int main(int argc, char *argv[])
+       g_test_add("/signature/verify_valid", SignatureFixture, NULL, 
signature_set_up, signature_verify_valid, signature_tear_down);
+       g_test_add("/signature/verify_invalid", SignatureFixture, NULL, 
signature_set_up, signature_verify_invalid, signature_tear_down);
+       g_test_add("/signature/verify_file", SignatureFixture, NULL, 
signature_set_up, signature_verify_file, signature_tear_down);
++      g_test_add("/signature/too_large", SignatureFixture, NULL, 
signature_set_up, signature_too_large, signature_tear_down);
+       g_test_add("/signature/loopback_detached", SignatureFixture, NULL, 
signature_set_up, signature_loopback_detached, signature_tear_down);
+       g_test_add("/signature/loopback_inline", SignatureFixture, NULL, 
signature_set_up, signature_loopback_inline, signature_tear_down);
+       g_test_add("/signature/get_cert_chain", SignatureFixture, NULL, 
signature_set_up, signature_get_cert_chain, signature_tear_down);
+-- 
+2.47.3
+
diff -Nru rauc-1.13/debian/patches/series rauc-1.13/debian/patches/series
--- rauc-1.13/debian/patches/series     2025-04-16 09:07:54.000000000 +0300
+++ rauc-1.13/debian/patches/series     2026-06-28 21:26:58.000000000 +0300
@@ -5,3 +5,7 @@
 # local adaptions for Debian
 disable-network-tests.patch
 install-wrapper-to-pkgdatadir.patch
+
+# CVE backports
+0001-src-signature-protect-against-integer-overflows-with.patch
+0002-src-signature-reject-plain-bundles-with-payload-exce.patch

Reply via email to