diff --git a/package/rauc/0001-fix-cve-2026-34155.patch b/package/rauc/0001-fix-cve-2026-34155.patch new file mode 100644 index 0000000000..dccb6f0d4c --- /dev/null +++ b/package/rauc/0001-fix-cve-2026-34155.patch @@ -0,0 +1,219 @@ +From f482e9f2ce34697844332db531b4b8be1e4b6043 Mon Sep 17 00:00:00 2001 +From: Titouan Christophe +Date: Tue, 31 Mar 2026 08:49:13 +0200 +Subject: [PATCH] Fix CVE-2026-34155 + +This is the concatenation of the 2 upstream commits that make the actual +change between rauc v1.15.1 and 1.15.2; rebased on top of rauc v1.13 + +=============================================================================== +[1/2] 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 + +Upstream: https://github.com/rauc/rauc/commit/bbdf9f04a96a7094e11cfa822d695bc7f33dbf61 +=============================================================================== +[2/2] 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 + +Upstream: https://github.com/rauc/rauc/commit/662a212fc16b736bfed163ebb7349a53881803cd +=============================================================================== + +CVE: CVE-2026-34155 + +Signed-off-by: Titouan Christophe +--- + src/signature.c | 32 ++++++++++++++++++++++++++++++++ + test/signature.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 78 insertions(+) + +diff --git a/src/signature.c b/src/signature.c +index 88f6e790..ca06bfa6 100644 +--- a/src/signature.c ++++ b/src/signature.c +@@ -414,11 +414,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; + } + +@@ -1420,6 +1428,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); +@@ -1434,6 +1443,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); +@@ -1479,6 +1499,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); +@@ -1515,6 +1536,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.53.0 +