diff options
Diffstat (limited to 'meta/recipes-devtools')
377 files changed, 31479 insertions, 2708 deletions
diff --git a/meta/recipes-devtools/apt/apt.inc b/meta/recipes-devtools/apt/apt.inc index 3c4fc6df07..251795eeca 100644 --- a/meta/recipes-devtools/apt/apt.inc +++ b/meta/recipes-devtools/apt/apt.inc @@ -18,6 +18,7 @@ SRC_URI = "https://launchpad.net/ubuntu/+archive/primary/+sourcefiles/${BPN}/${P file://0001-environment.mak-musl-based-systems-can-generate-shar.patch \ file://0001-apt-1.2.12-Fix-musl-build.patch \ file://0001-Include-array.h-for-std-array.patch \ + file://CVE-2020-3810.patch \ " SRC_URI[md5sum] = "d30eed9304e82ea8238c854b5c5a34d9" SRC_URI[sha256sum] = "03ded4f5e9b8d43ecec083704b2dcabf20c182ed382db9ac7251da0b0b038059" @@ -36,5 +37,9 @@ do_configure_prepend() { rm -rf ${S}/buildlib/config.guess } +# there are code generation issues with some compilers in the SHA256 implementation +# turn off strict-aliasing to avoid these issues +CXXFLAGS:append = " -fno-strict-aliasing" + USERADD_PACKAGES = "${PN}" USERADD_PARAM_${PN} = "--system --no-create-home --home-dir /nonexistent --shell /bin/false --user-group _apt" diff --git a/meta/recipes-devtools/apt/apt/CVE-2020-3810.patch b/meta/recipes-devtools/apt/apt/CVE-2020-3810.patch new file mode 100644 index 0000000000..cf1206a3fa --- /dev/null +++ b/meta/recipes-devtools/apt/apt/CVE-2020-3810.patch @@ -0,0 +1,174 @@ +From dceb1e49e4b8e4dadaf056be34088b415939cda6 Mon Sep 17 00:00:00 2001 +From: Julian Andres Klode <julian.klode@canonical.com> +Date: Tue, 12 May 2020 11:49:09 +0200 +Subject: [PATCH] SECURITY UPDATE: Fix out of bounds read in .ar and .tar + implementation (CVE-2020-3810) + +When normalizing ar member names by removing trailing whitespace +and slashes, an out-out-bound read can be caused if the ar member +name consists only of such characters, because the code did not +stop at 0, but would wrap around and continue reading from the +stack, without any limit. + +Add a check to abort if we reached the first character in the +name, effectively rejecting the use of names consisting just +of slashes and spaces. + +Furthermore, certain error cases in arfile.cc and extracttar.cc have +included member names in the output that were not checked at all and +might hence not be nul terminated, leading to further out of bound reads. + +Fixes Debian/apt#111 +LP: #1878177 + +CVE: CVE-2020-3810 + +Upstream-Status: Backport: +https://salsa.debian.org/apt-team/apt/-/commit/dceb1e49e4b8e4dadaf056be34088b415939cda6 + +Signed-off-by: Davide Gardenal <davide.gardenal@huawei.com> +--- +apt-inst/contrib/arfile.cc | 11 ++- +apt-inst/contrib/extracttar.cc | 2 +- +.../test-github-111-invalid-armember | 88 +++++++++++++++++++ + 3 files changed, 98 insertions(+), 3 deletions(-) + create mode 100755 test/integration/test-github-111-invalid-armember + +diff --git a/apt-inst/contrib/arfile.cc b/st/contrib/arfile.cc +index 3fc3afedb..5cb43c690 100644 +--- a/apt-inst/contrib/arfile.cc ++++ b/apt-inst/contrib/arfile.cc +@@ -92,7 +92,7 @@ bool ARArchive::LoadHeaders() + StrToNum(Head.Size,Memb->Size,sizeof(Head.Size)) == false) + { + delete Memb; +- return _error->Error(_("Invalid archive member header %s"), Head.Name); ++ return _error->Error(_("Invalid archive member header")); + } + + // Check for an extra long name string +@@ -119,7 +119,14 @@ bool ARArchive::LoadHeaders() + else + { + unsigned int I = sizeof(Head.Name) - 1; +- for (; Head.Name[I] == ' ' || Head.Name[I] == '/'; I--); ++ for (; Head.Name[I] == ' ' || Head.Name[I] == '/'; I--) ++ { ++ if (I == 0) ++ { ++ delete Memb; ++ return _error->Error(_("Invalid archive member header")); ++ } ++ } + Memb->Name = std::string(Head.Name,I+1); + } + +diff --git a/apt-inst/contrib/extracttar.cc b/apt-inst/contrib/extracttar.cc +index 9bb0a55c0..b22f59dbc 100644 +--- a/apt-inst/contrib/extracttar.cc ++++ b/apt-inst/contrib/extracttar.cc +@@ -254,7 +254,7 @@ bool ExtractTar::Go(pkgDirStream &Stream) + + default: + BadRecord = true; +- _error->Warning(_("Unknown TAR header type %u, member %s"),(unsigned)Tar->LinkFlag,Tar->Name); ++ _error->Warning(_("Unknown TAR header type %u"), (unsigned)Tar->LinkFlag); + break; + } + +diff --git a/test/integration/test-github-111-invalid-armember b/test/integration/test-github-111-invalid-armember +new file mode 100755 +index 000000000..ec2163bf6 +--- /dev/null ++++ b/test/integration/test-github-111-invalid-armember +@@ -0,0 +1,88 @@ ++#!/bin/sh ++set -e ++ ++TESTDIR="$(readlink -f "$(dirname "$0")")" ++. "$TESTDIR/framework" ++setupenvironment ++configarchitecture "amd64" ++setupaptarchive ++ ++# this used to crash, but it should treat it as an invalid member header ++touch ' ' ++ar -q test.deb ' ' ++testsuccessequal "E: Invalid archive member header" ${BUILDDIRECTORY}/../test/interactive-helper/testdeb test.deb ++ ++ ++rm test.deb ++touch 'x' ++ar -q test.deb 'x' ++testsuccessequal "E: This is not a valid DEB archive, missing 'debian-binary' member" ${BUILDDIRECTORY}/../test/interactive-helper/testdeb test.deb ++ ++ ++# <name><size> [ other fields] - name is not nul terminated here, it ends in . ++msgmsg "Unterminated ar member name" ++printf '!<arch>\0120123456789ABCDE.A123456789A.01234.01234.0123456.012345678.0.' > test.deb ++testsuccessequal "E: Invalid archive member header" ${BUILDDIRECTORY}/../test/interactive-helper/testdeb test.deb ++ ++ ++# unused source code for generating $tar below ++maketar() { ++ cat > maketar.c << EOF ++ #include <stdio.h> ++ #include <string.h> ++ struct tar { ++ char Name[100]; ++ char Mode[8]; ++ char UserID[8]; ++ char GroupID[8]; ++ char Size[12]; ++ char MTime[12]; ++ char Checksum[8]; ++ char LinkFlag; ++ char LinkName[100]; ++ char MagicNumber[8]; ++ char UserName[32]; ++ char GroupName[32]; ++ char Major[8]; ++ char Minor[8]; ++ }; ++ ++ int main(void) ++ { ++ union { ++ struct tar t; ++ char buf[512]; ++ } t; ++ for (int i = 0; i < sizeof(t.buf); i++) ++ t.buf[i] = '7'; ++ memcpy(t.t.Name, "unterminatedName", 16); ++ memcpy(t.t.UserName, "userName", 8); ++ memcpy(t.t.GroupName, "thisIsAGroupNamethisIsAGroupName", 32); ++ t.t.LinkFlag = 'X'; // I AM BROKEN ++ memcpy(t.t.Size, "000000000000", sizeof(t.t.Size)); ++ memset(t.t.Checksum,' ',sizeof(t.t.Checksum)); ++ ++ unsigned long sum = 0; ++ for (int i = 0; i < sizeof(t.buf); i++) ++ sum += t.buf[i]; ++ ++ int written = sprintf(t.t.Checksum, "%lo", sum); ++ for (int i = written; i < sizeof(t.t.Checksum); i++) ++ t.t.Checksum[i] = ' '; ++ fwrite(t.buf, sizeof(t.buf), 1, stdout); ++ } ++EOF ++ ++ gcc maketar.c -o maketar -Wall ++ ./maketar ++} ++ ++ ++# ++tar="unterminatedName77777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777700000000000077777777777773544 X777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777userName777777777777777777777777thisIsAGroupNamethisIsAGroupName777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777" ++printf '%s' "$tar" | gzip > control.tar.gz ++cp control.tar.gz data.tar.gz ++touch debian-binary ++rm test.deb ++ar -q test.deb debian-binary control.tar.gz data.tar.gz ++testsuccessequal "W: Unknown TAR header type 88" ${BUILDDIRECTORY}/../test/interactive-helper/testdeb test.deb +-- +GitLab diff --git a/meta/recipes-devtools/binutils/binutils-2.34.inc b/meta/recipes-devtools/binutils/binutils-2.34.inc index 3e10279b1d..032263fe63 100644 --- a/meta/recipes-devtools/binutils/binutils-2.34.inc +++ b/meta/recipes-devtools/binutils/binutils-2.34.inc @@ -24,7 +24,7 @@ BRANCH ?= "binutils-2_34-branch" UPSTREAM_CHECK_GITTAGREGEX = "binutils-(?P<pver>\d+_(\d_?)*)" -SRCREV ?= "d4b50999b3b287b5f984ade2f8734aa8c9359440" +SRCREV ?= "c4e78c0868a22971680217a41fdb73516a26813d" BINUTILS_GIT_URI ?= "git://sourceware.org/git/binutils-gdb.git;branch=${BRANCH};protocol=git" SRC_URI = "\ ${BINUTILS_GIT_URI} \ @@ -42,11 +42,25 @@ SRC_URI = "\ file://0015-sync-with-OE-libtool-changes.patch \ file://0016-Check-for-clang-before-checking-gcc-version.patch \ file://0017-binutils-drop-redundant-program_name-definition-fno-.patch \ + file://0018-Include-members-in-the-variable-table-used-when-reso.patch \ file://CVE-2020-0551.patch \ file://0001-gas-improve-reproducibility-for-stabs-debugging-data.patch \ file://CVE-2020-16592.patch \ file://CVE-2020-16598.patch \ file://CVE-2021-20197.patch \ file://CVE-2021-3487.patch \ + file://CVE-2021-3549.patch \ + file://CVE-2020-16593.patch \ + file://0001-CVE-2021-45078.patch \ + file://CVE-2022-38533.patch \ + file://CVE-2023-25588.patch \ + file://CVE-2021-46174.patch \ + file://CVE-2023-25584.patch \ + file://CVE-2022-47007.patch \ + file://CVE-2022-47008.patch \ + file://CVE-2022-47010.patch \ + file://CVE-2022-47011.patch \ + file://CVE-2022-48063.patch \ + file://CVE-2022-47695.patch \ " S = "${WORKDIR}/git" diff --git a/meta/recipes-devtools/binutils/binutils/0001-CVE-2021-45078.patch b/meta/recipes-devtools/binutils/binutils/0001-CVE-2021-45078.patch new file mode 100644 index 0000000000..2af82477ac --- /dev/null +++ b/meta/recipes-devtools/binutils/binutils/0001-CVE-2021-45078.patch @@ -0,0 +1,257 @@ +From 161e87d12167b1e36193385485c1f6ce92f74f02 Mon Sep 17 00:00:00 2001 +From: Alan Modra <amodra@gmail.com> +Date: Wed, 15 Dec 2021 11:48:42 +1030 +Subject: [PATCH] PR28694, Out-of-bounds write in stab_xcoff_builtin_type + + PR 28694 + * stabs.c (stab_xcoff_builtin_type): Make typenum unsigned. + Negate typenum earlier, simplifying bounds checking. Correct + off-by-one indexing. Adjust switch cases. + + +CVE: CVE-2021-45078 +Upstream-Status: Backport [https://sourceware.org/git/?p=binutils-gdb.git;a=patch;h=161e87d12167b1e36193385485c1f6ce92f74f02] + +Signed-off-by: Sundeep KOKKONDA <sundeep.kokkonda@gmail.com> +Signed-off-by: Purushottam Choudhary <purushottam.choudhary@kpit.com> +Signed-off-by: Purushottam Choudhary <purushottamchoudhary29@gmail.com> +--- + binutils/stabs.c | 87 ++++++++++++++++++++++++------------------------ + 1 file changed, 43 insertions(+), 44 deletions(-) + + +diff --git a/binutils/stabs.c b/binutils/stabs.c +index 274bfb0e7fa..83ee3ea5fa4 100644 +--- a/binutils/stabs.c ++++ b/binutils/stabs.c +@@ -202,7 +202,7 @@ static debug_type stab_find_type (void *, struct stab_handle *, const int *); + static bfd_boolean stab_record_type + (void *, struct stab_handle *, const int *, debug_type); + static debug_type stab_xcoff_builtin_type +- (void *, struct stab_handle *, int); ++ (void *, struct stab_handle *, unsigned int); + static debug_type stab_find_tagged_type + (void *, struct stab_handle *, const char *, int, enum debug_type_kind); + static debug_type *stab_demangle_argtypes +@@ -3496,166 +3496,167 @@ stab_record_type (void *dhandle ATTRIBUTE_UNUSED, struct stab_handle *info, + + static debug_type + stab_xcoff_builtin_type (void *dhandle, struct stab_handle *info, +- int typenum) ++ unsigned int typenum) + { + debug_type rettype; + const char *name; + +- if (typenum >= 0 || typenum < -XCOFF_TYPE_COUNT) ++ typenum = -typenum - 1; ++ if (typenum >= XCOFF_TYPE_COUNT) + { +- fprintf (stderr, _("Unrecognized XCOFF type %d\n"), typenum); ++ fprintf (stderr, _("Unrecognized XCOFF type %d\n"), -typenum - 1); + return DEBUG_TYPE_NULL; + } +- if (info->xcoff_types[-typenum] != NULL) +- return info->xcoff_types[-typenum]; ++ if (info->xcoff_types[typenum] != NULL) ++ return info->xcoff_types[typenum]; + +- switch (-typenum) ++ switch (typenum) + { +- case 1: ++ case 0: + /* The size of this and all the other types are fixed, defined + by the debugging format. */ + name = "int"; + rettype = debug_make_int_type (dhandle, 4, FALSE); + break; +- case 2: ++ case 1: + name = "char"; + rettype = debug_make_int_type (dhandle, 1, FALSE); + break; +- case 3: ++ case 2: + name = "short"; + rettype = debug_make_int_type (dhandle, 2, FALSE); + break; +- case 4: ++ case 3: + name = "long"; + rettype = debug_make_int_type (dhandle, 4, FALSE); + break; +- case 5: ++ case 4: + name = "unsigned char"; + rettype = debug_make_int_type (dhandle, 1, TRUE); + break; +- case 6: ++ case 5: + name = "signed char"; + rettype = debug_make_int_type (dhandle, 1, FALSE); + break; +- case 7: ++ case 6: + name = "unsigned short"; + rettype = debug_make_int_type (dhandle, 2, TRUE); + break; +- case 8: ++ case 7: + name = "unsigned int"; + rettype = debug_make_int_type (dhandle, 4, TRUE); + break; +- case 9: ++ case 8: + name = "unsigned"; + rettype = debug_make_int_type (dhandle, 4, TRUE); + break; +- case 10: ++ case 9: + name = "unsigned long"; + rettype = debug_make_int_type (dhandle, 4, TRUE); + break; +- case 11: ++ case 10: + name = "void"; + rettype = debug_make_void_type (dhandle); + break; +- case 12: ++ case 11: + /* IEEE single precision (32 bit). */ + name = "float"; + rettype = debug_make_float_type (dhandle, 4); + break; +- case 13: ++ case 12: + /* IEEE double precision (64 bit). */ + name = "double"; + rettype = debug_make_float_type (dhandle, 8); + break; +- case 14: ++ case 13: + /* This is an IEEE double on the RS/6000, and different machines + with different sizes for "long double" should use different + negative type numbers. See stabs.texinfo. */ + name = "long double"; + rettype = debug_make_float_type (dhandle, 8); + break; +- case 15: ++ case 14: + name = "integer"; + rettype = debug_make_int_type (dhandle, 4, FALSE); + break; +- case 16: ++ case 15: + name = "boolean"; + rettype = debug_make_bool_type (dhandle, 4); + break; +- case 17: ++ case 16: + name = "short real"; + rettype = debug_make_float_type (dhandle, 4); + break; +- case 18: ++ case 17: + name = "real"; + rettype = debug_make_float_type (dhandle, 8); + break; +- case 19: ++ case 18: + /* FIXME */ + name = "stringptr"; + rettype = NULL; + break; +- case 20: ++ case 19: + /* FIXME */ + name = "character"; + rettype = debug_make_int_type (dhandle, 1, TRUE); + break; +- case 21: ++ case 20: + name = "logical*1"; + rettype = debug_make_bool_type (dhandle, 1); + break; +- case 22: ++ case 21: + name = "logical*2"; + rettype = debug_make_bool_type (dhandle, 2); + break; +- case 23: ++ case 22: + name = "logical*4"; + rettype = debug_make_bool_type (dhandle, 4); + break; +- case 24: ++ case 23: + name = "logical"; + rettype = debug_make_bool_type (dhandle, 4); + break; +- case 25: ++ case 24: + /* Complex type consisting of two IEEE single precision values. */ + name = "complex"; + rettype = debug_make_complex_type (dhandle, 8); + break; +- case 26: ++ case 25: + /* Complex type consisting of two IEEE double precision values. */ + name = "double complex"; + rettype = debug_make_complex_type (dhandle, 16); + break; +- case 27: ++ case 26: + name = "integer*1"; + rettype = debug_make_int_type (dhandle, 1, FALSE); + break; +- case 28: ++ case 27: + name = "integer*2"; + rettype = debug_make_int_type (dhandle, 2, FALSE); + break; +- case 29: ++ case 28: + name = "integer*4"; + rettype = debug_make_int_type (dhandle, 4, FALSE); + break; +- case 30: ++ case 29: + /* FIXME */ + name = "wchar"; + rettype = debug_make_int_type (dhandle, 2, FALSE); + break; +- case 31: ++ case 30: + name = "long long"; + rettype = debug_make_int_type (dhandle, 8, FALSE); + break; +- case 32: ++ case 31: + name = "unsigned long long"; + rettype = debug_make_int_type (dhandle, 8, TRUE); + break; +- case 33: ++ case 32: + name = "logical*8"; + rettype = debug_make_bool_type (dhandle, 8); + break; +- case 34: ++ case 33: + name = "integer*8"; + rettype = debug_make_int_type (dhandle, 8, FALSE); + break; +@@ -3664,9 +3665,7 @@ stab_xcoff_builtin_type (void *dhandle, struct stab_handle *info, + } + + rettype = debug_name_type (dhandle, name, rettype); +- +- info->xcoff_types[-typenum] = rettype; +- ++ info->xcoff_types[typenum] = rettype; + return rettype; + } + +-- +2.27.0 + diff --git a/meta/recipes-devtools/binutils/binutils/0009-warn-for-uses-of-system-directories-when-cross-linki.patch b/meta/recipes-devtools/binutils/binutils/0009-warn-for-uses-of-system-directories-when-cross-linki.patch index 11a8110d40..88cce49e46 100644 --- a/meta/recipes-devtools/binutils/binutils/0009-warn-for-uses-of-system-directories-when-cross-linki.patch +++ b/meta/recipes-devtools/binutils/binutils/0009-warn-for-uses-of-system-directories-when-cross-linki.patch @@ -1,4 +1,4 @@ -From 7b24f81e04c9d00d96de7dbd250beade6d2c6e44 Mon Sep 17 00:00:00 2001 +From 12b658c0fe5771d16067baef933b7f34ed455def Mon Sep 17 00:00:00 2001 From: Khem Raj <raj.khem@gmail.com> Date: Fri, 15 Jan 2016 06:31:09 +0000 Subject: [PATCH] warn for uses of system directories when cross linking @@ -59,8 +59,8 @@ Signed-off-by: Khem Raj <raj.khem@gmail.com> ld/ldfile.c | 17 +++++++++++++++++ ld/ldlex.h | 2 ++ ld/ldmain.c | 2 ++ - ld/lexsup.c | 15 +++++++++++++++ - 9 files changed, 85 insertions(+) + ld/lexsup.c | 16 ++++++++++++++++ + 9 files changed, 86 insertions(+) diff --git a/ld/config.in b/ld/config.in index d93c9b0830..5da2742bea 100644 @@ -77,10 +77,10 @@ index d93c9b0830..5da2742bea 100644 #undef EXTRA_SHLIB_EXTENSION diff --git a/ld/configure b/ld/configure -index 811134a503..f8c17c19ae 100755 +index f432f4637d..a9da3c115e 100755 --- a/ld/configure +++ b/ld/configure -@@ -826,6 +826,7 @@ with_lib_path +@@ -830,6 +830,7 @@ with_lib_path enable_targets enable_64_bit_bfd with_sysroot @@ -88,7 +88,7 @@ index 811134a503..f8c17c19ae 100755 enable_gold enable_got enable_compressed_debug_sections -@@ -1491,6 +1492,8 @@ Optional Features: +@@ -1495,6 +1496,8 @@ Optional Features: --disable-largefile omit support for large files --enable-targets alternative target configurations --enable-64-bit-bfd 64-bit support (on hosts with narrower word sizes) @@ -97,7 +97,7 @@ index 811134a503..f8c17c19ae 100755 --enable-gold[=ARG] build gold [ARG={default,yes,no}] --enable-got=<type> GOT handling scheme (target, single, negative, multigot) -@@ -15788,6 +15791,19 @@ fi +@@ -16624,6 +16627,19 @@ fi @@ -222,10 +222,10 @@ index 5287f19a7f..55096e4fc9 100644 /* The initial parser states. */ diff --git a/ld/ldmain.c b/ld/ldmain.c -index da1ad17763..12d0b07d8a 100644 +index c4af10f4e9..95b56b2d2d 100644 --- a/ld/ldmain.c +++ b/ld/ldmain.c -@@ -274,6 +274,8 @@ main (int argc, char **argv) +@@ -273,6 +273,8 @@ main (int argc, char **argv) command_line.warn_mismatch = TRUE; command_line.warn_search_mismatch = TRUE; command_line.check_section_addresses = -1; @@ -235,7 +235,7 @@ index da1ad17763..12d0b07d8a 100644 /* We initialize DEMANGLING based on the environment variable COLLECT_NO_DEMANGLE. The gcc collect2 program will demangle the diff --git a/ld/lexsup.c b/ld/lexsup.c -index 3d15cc491d..0e8b4f2b7a 100644 +index 3d15cc491d..6478821443 100644 --- a/ld/lexsup.c +++ b/ld/lexsup.c @@ -550,6 +550,14 @@ static const struct ld_option ld_options[] = @@ -253,10 +253,10 @@ index 3d15cc491d..0e8b4f2b7a 100644 }; #define OPTION_COUNT ARRAY_SIZE (ld_options) -@@ -1603,6 +1611,13 @@ parse_args (unsigned argc, char **argv) - +@@ -1604,6 +1612,14 @@ parse_args (unsigned argc, char **argv) case OPTION_PRINT_MAP_DISCARDED: config.print_map_discarded = TRUE; + break; + + case OPTION_NO_POISON_SYSTEM_DIRECTORIES: + command_line.poison_system_directories = FALSE; @@ -264,6 +264,6 @@ index 3d15cc491d..0e8b4f2b7a 100644 + + case OPTION_ERROR_POISON_SYSTEM_DIRECTORIES: + command_line.error_poison_system_directories = TRUE; - break; ++ break; } } diff --git a/meta/recipes-devtools/binutils/binutils/0018-Include-members-in-the-variable-table-used-when-reso.patch b/meta/recipes-devtools/binutils/binutils/0018-Include-members-in-the-variable-table-used-when-reso.patch new file mode 100644 index 0000000000..dc1e09d46b --- /dev/null +++ b/meta/recipes-devtools/binutils/binutils/0018-Include-members-in-the-variable-table-used-when-reso.patch @@ -0,0 +1,32 @@ +From bf2252dca8c76e4c1f1c2dbf98dab7ffc9f5e5af Mon Sep 17 00:00:00 2001 +From: Nick Clifton <nickc@redhat.com> +Date: Sat, 29 Aug 2020 08:03:15 +0100 +Subject: [PATCH] Include members in the variable table used when resolving + DW_AT_specification tags. + + PR 26520 + * dwarf2.c (scan_unit_for_symbols): Add member entries to the + variable table. + +Upstream-Status: Backport [https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=e6f04d55f681149a69102a73937d0987719c3f16] +--- + bfd/dwarf2.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/bfd/dwarf2.c b/bfd/dwarf2.c +index dd3568a8532..ef2f6a3c63c 100644 +--- a/bfd/dwarf2.c ++++ b/bfd/dwarf2.c +@@ -3248,7 +3248,8 @@ scan_unit_for_symbols (struct comp_unit *unit) + else + { + func = NULL; +- if (abbrev->tag == DW_TAG_variable) ++ if (abbrev->tag == DW_TAG_variable ++ || abbrev->tag == DW_TAG_member) + { + bfd_size_type amt = sizeof (struct varinfo); + var = (struct varinfo *) bfd_zalloc (abfd, amt); +-- +2.34.1 + diff --git a/meta/recipes-devtools/binutils/binutils/CVE-2020-16593.patch b/meta/recipes-devtools/binutils/binutils/CVE-2020-16593.patch new file mode 100644 index 0000000000..c7c7829261 --- /dev/null +++ b/meta/recipes-devtools/binutils/binutils/CVE-2020-16593.patch @@ -0,0 +1,204 @@ +From aec72fda3b320c36eb99fc1c4cf95b10fc026729 Mon Sep 17 00:00:00 2001 +From: Alan Modra <amodra@gmail.com> +Date: Thu, 16 Apr 2020 17:49:38 +0930 +Subject: [PATCH] PR25827, Null pointer dereferencing in scan_unit_for_symbols + + PR 25827 + * dwarf2.c (scan_unit_for_symbols): Wrap overlong lines. Don't + strdup(0). + +Upstream-Status: Backport +https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=aec72fda3b320c36eb99fc1c4cf95b10fc026729 +CVE: CVE-2020-16593 +Signed-off-by: Armin Kuster <akuster@mvista.com> + + +Index: git/bfd/dwarf2.c +=================================================================== +--- git.orig/bfd/dwarf2.c ++++ git/bfd/dwarf2.c +@@ -295,12 +295,12 @@ struct comp_unit + /* This data structure holds the information of an abbrev. */ + struct abbrev_info + { +- unsigned int number; /* Number identifying abbrev. */ +- enum dwarf_tag tag; /* DWARF tag. */ +- int has_children; /* Boolean. */ +- unsigned int num_attrs; /* Number of attributes. */ +- struct attr_abbrev *attrs; /* An array of attribute descriptions. */ +- struct abbrev_info *next; /* Next in chain. */ ++ unsigned int number; /* Number identifying abbrev. */ ++ enum dwarf_tag tag; /* DWARF tag. */ ++ bfd_boolean has_children; /* TRUE if the abbrev has children. */ ++ unsigned int num_attrs; /* Number of attributes. */ ++ struct attr_abbrev * attrs; /* An array of attribute descriptions. */ ++ struct abbrev_info * next; /* Next in chain. */ + }; + + struct attr_abbrev +@@ -1487,6 +1487,8 @@ struct varinfo + { + /* Pointer to previous variable in list of all variables */ + struct varinfo *prev_var; ++ /* The offset of the varinfo from the start of the unit. */ ++ bfd_uint64_t unit_offset; + /* Source location file name */ + char *file; + /* Source location line number */ +@@ -1497,7 +1499,7 @@ struct varinfo + /* Where the symbol is defined */ + asection *sec; + /* Is this a stack variable? */ +- unsigned int stack: 1; ++ bfd_boolean stack; + }; + + /* Return TRUE if NEW_LINE should sort after LINE. */ +@@ -2871,7 +2873,7 @@ lookup_symbol_in_variable_table (struct + struct varinfo* each; + + for (each = unit->variable_table; each; each = each->prev_var) +- if (each->stack == 0 ++ if (! each->stack + && each->file != NULL + && each->name != NULL + && each->addr == addr +@@ -3166,6 +3168,20 @@ read_rangelist (struct comp_unit *unit, + return TRUE; + } + ++static struct varinfo * ++lookup_var_by_offset (bfd_uint64_t offset, struct varinfo * table) ++{ ++ while (table) ++ { ++ if (table->unit_offset == offset) ++ return table; ++ table = table->prev_var; ++ } ++ ++ return NULL; ++} ++ ++ + /* DWARF2 Compilation unit functions. */ + + /* Scan over each die in a comp. unit looking for functions to add +@@ -3202,6 +3218,9 @@ scan_unit_for_symbols (struct comp_unit + bfd_vma low_pc = 0; + bfd_vma high_pc = 0; + bfd_boolean high_pc_relative = FALSE; ++ bfd_uint64_t current_offset; ++ ++ current_offset = info_ptr - unit->info_ptr_unit; + + /* PR 17512: file: 9f405d9d. */ + if (info_ptr >= info_ptr_end) +@@ -3234,12 +3253,13 @@ scan_unit_for_symbols (struct comp_unit + goto fail; + } + +- var = NULL; + if (abbrev->tag == DW_TAG_subprogram + || abbrev->tag == DW_TAG_entry_point + || abbrev->tag == DW_TAG_inlined_subroutine) + { + bfd_size_type amt = sizeof (struct funcinfo); ++ ++ var = NULL; + func = (struct funcinfo *) bfd_zalloc (abfd, amt); + if (func == NULL) + goto fail; +@@ -3268,13 +3288,15 @@ scan_unit_for_symbols (struct comp_unit + if (var == NULL) + goto fail; + var->tag = abbrev->tag; +- var->stack = 1; ++ var->stack = TRUE; + var->prev_var = unit->variable_table; + unit->variable_table = var; ++ var->unit_offset = current_offset; + /* PR 18205: Missing debug information can cause this + var to be attached to an already cached unit. */ + } +- ++ else ++ var = NULL; + /* No inline function in scope at this nesting level. */ + nested_funcs[nesting_level].func = 0; + } +@@ -3362,6 +3384,33 @@ scan_unit_for_symbols (struct comp_unit + { + switch (attr.name) + { ++ case DW_AT_specification: ++ if (attr.u.val) ++ { ++ struct varinfo * spec_var; ++ ++ spec_var = lookup_var_by_offset (attr.u.val, ++ unit->variable_table); ++ if (spec_var == NULL) ++ { ++ _bfd_error_handler (_("DWARF error: could not find " ++ "variable specification " ++ "at offset %lx"), ++ (unsigned long) attr.u.val); ++ break; ++ } ++ ++ if (var->name == NULL) ++ var->name = spec_var->name; ++ if (var->file == NULL && spec_var->file != NULL) ++ var->file = strdup (spec_var->file); ++ if (var->line == 0) ++ var->line = spec_var->line; ++ if (var->sec == NULL) ++ var->sec = spec_var->sec; ++ } ++ break; ++ + case DW_AT_name: + if (is_str_attr (attr.form)) + var->name = attr.u.str; +@@ -3378,7 +3427,7 @@ scan_unit_for_symbols (struct comp_unit + + case DW_AT_external: + if (attr.u.val != 0) +- var->stack = 0; ++ var->stack = FALSE; + break; + + case DW_AT_location: +@@ -3392,7 +3441,7 @@ scan_unit_for_symbols (struct comp_unit + if (attr.u.blk->data != NULL + && *attr.u.blk->data == DW_OP_addr) + { +- var->stack = 0; ++ var->stack = FALSE; + + /* Verify that DW_OP_addr is the only opcode in the + location, in which case the block size will be 1 +@@ -3888,7 +3937,7 @@ comp_unit_hash_info (struct dwarf2_debug + each_var = each_var->prev_var) + { + /* Skip stack vars and vars with no files or names. */ +- if (each_var->stack == 0 ++ if (! each_var->stack + && each_var->file != NULL + && each_var->name != NULL) + /* There is no need to copy name string into hash table as +Index: git/bfd/ChangeLog +=================================================================== +--- git.orig/bfd/ChangeLog ++++ git/bfd/ChangeLog +@@ -1,3 +1,9 @@ ++2020-04-16 Alan Modra <amodra@gmail.com> ++ ++ PR 25827 ++ * dwarf2.c (scan_unit_for_symbols): Wrap overlong lines. Don't ++ strdup(0). ++ + 2021-05-03 Alan Modra <amodra@gmail.com> + + PR 27755 diff --git a/meta/recipes-devtools/binutils/binutils/CVE-2021-3549.patch b/meta/recipes-devtools/binutils/binutils/CVE-2021-3549.patch new file mode 100644 index 0000000000..5f56dd7696 --- /dev/null +++ b/meta/recipes-devtools/binutils/binutils/CVE-2021-3549.patch @@ -0,0 +1,183 @@ +From 1cfcf3004e1830f8fe9112cfcd15285508d2c2b7 Mon Sep 17 00:00:00 2001 +From: Alan Modra <amodra@gmail.com> +Date: Thu, 11 Feb 2021 16:56:42 +1030 +Subject: [PATCH] PR27290, PR27293, PR27295, various avr objdump fixes + +Adds missing sanity checks for avr device info note, to avoid +potential buffer overflows. Uses bfd_malloc_and_get_section for +sanity checking section size. + + PR 27290 + PR 27293 + PR 27295 + * od-elf32_avr.c (elf32_avr_get_note_section_contents): Formatting. + Use bfd_malloc_and_get_section. + (elf32_avr_get_note_desc): Formatting. Return descsz. Sanity + check namesz. Return NULL if descsz is too small. Ensure + string table is terminated. + (elf32_avr_get_device_info): Formatting. Add note_size param. + Sanity check note. + (elf32_avr_dump_mem_usage): Adjust to suit. + +Upstream-Status: Backport +CVE: CVE-2021-3549 +Signed-of-by: Armin Kuster <akuster@mvista.com> + +--- +diff --git a/binutils/ChangeLog b/binutils/ChangeLog +index 1e9a96c9bb6..02e5019204e 100644 +--- a/binutils/ChangeLog ++++ b/binutils/ChangeLog +@@ -1,3 +1,17 @@ ++2021-02-11 Alan Modra <amodra@gmail.com> ++ ++ PR 27290 ++ PR 27293 ++ PR 27295 ++ * od-elf32_avr.c (elf32_avr_get_note_section_contents): Formatting. ++ Use bfd_malloc_and_get_section. ++ (elf32_avr_get_note_desc): Formatting. Return descsz. Sanity ++ check namesz. Return NULL if descsz is too small. Ensure ++ string table is terminated. ++ (elf32_avr_get_device_info): Formatting. Add note_size param. ++ Sanity check note. ++ (elf32_avr_dump_mem_usage): Adjust to suit. ++ + 2020-03-25 H.J. Lu <hongjiu.lu@intel.com> + + * ar.c (main): Update bfd_plugin_set_program_name call. +diff --git a/binutils/od-elf32_avr.c b/binutils/od-elf32_avr.c +index 5ec99957fe9..1d32bce918e 100644 +--- a/binutils/od-elf32_avr.c ++++ b/binutils/od-elf32_avr.c +@@ -77,23 +77,29 @@ elf32_avr_filter (bfd *abfd) + return bfd_get_flavour (abfd) == bfd_target_elf_flavour; + } + +-static char* ++static char * + elf32_avr_get_note_section_contents (bfd *abfd, bfd_size_type *size) + { + asection *section; ++ bfd_byte *contents; + +- if ((section = bfd_get_section_by_name (abfd, ".note.gnu.avr.deviceinfo")) == NULL) ++ section = bfd_get_section_by_name (abfd, ".note.gnu.avr.deviceinfo"); ++ if (section == NULL) + return NULL; + +- *size = bfd_section_size (section); +- char *contents = (char *) xmalloc (*size); +- bfd_get_section_contents (abfd, section, contents, 0, *size); ++ if (!bfd_malloc_and_get_section (abfd, section, &contents)) ++ { ++ free (contents); ++ contents = NULL; ++ } + +- return contents; ++ *size = bfd_section_size (section); ++ return (char *) contents; + } + +-static char* elf32_avr_get_note_desc (bfd *abfd, char *contents, +- bfd_size_type size) ++static char * ++elf32_avr_get_note_desc (bfd *abfd, char *contents, bfd_size_type size, ++ bfd_size_type *descsz) + { + Elf_External_Note *xnp = (Elf_External_Note *) contents; + Elf_Internal_Note in; +@@ -107,42 +113,54 @@ static char* elf32_avr_get_note_desc (bfd *abfd, char *contents, + if (in.namesz > contents - in.namedata + size) + return NULL; + ++ if (in.namesz != 4 || strcmp (in.namedata, "AVR") != 0) ++ return NULL; ++ + in.descsz = bfd_get_32 (abfd, xnp->descsz); + in.descdata = in.namedata + align_power (in.namesz, 2); +- if (in.descsz != 0 +- && (in.descdata >= contents + size +- || in.descsz > contents - in.descdata + size)) ++ if (in.descsz < 6 * sizeof (uint32_t) ++ || in.descdata >= contents + size ++ || in.descsz > contents - in.descdata + size) + return NULL; + +- if (strcmp (in.namedata, "AVR") != 0) +- return NULL; ++ /* If the note has a string table, ensure it is 0 terminated. */ ++ if (in.descsz > 8 * sizeof (uint32_t)) ++ in.descdata[in.descsz - 1] = 0; + ++ *descsz = in.descsz; + return in.descdata; + } + + static void + elf32_avr_get_device_info (bfd *abfd, char *description, +- deviceinfo *device) ++ bfd_size_type desc_size, deviceinfo *device) + { + if (description == NULL) + return; + + const bfd_size_type memory_sizes = 6; + +- memcpy (device, description, memory_sizes * sizeof(uint32_t)); +- device->name = NULL; ++ memcpy (device, description, memory_sizes * sizeof (uint32_t)); ++ desc_size -= memory_sizes * sizeof (uint32_t); ++ if (desc_size < 8) ++ return; + +- uint32_t *stroffset_table = ((uint32_t *) description) + memory_sizes; ++ uint32_t *stroffset_table = (uint32_t *) description + memory_sizes; + bfd_size_type stroffset_table_size = bfd_get_32 (abfd, stroffset_table); +- char *str_table = ((char *) stroffset_table) + stroffset_table_size; + + /* If the only content is the size itself, there's nothing in the table */ +- if (stroffset_table_size == 4) ++ if (stroffset_table_size < 8) + return; ++ if (desc_size <= stroffset_table_size) ++ return; ++ desc_size -= stroffset_table_size; + + /* First entry is the device name index. */ + uint32_t device_name_index = bfd_get_32 (abfd, stroffset_table + 1); ++ if (device_name_index >= desc_size) ++ return; + ++ char *str_table = (char *) stroffset_table + stroffset_table_size; + device->name = str_table + device_name_index; + } + +@@ -183,7 +201,7 @@ static void + elf32_avr_dump_mem_usage (bfd *abfd) + { + char *description = NULL; +- bfd_size_type note_section_size = 0; ++ bfd_size_type sec_size, desc_size; + + deviceinfo device = { 0, 0, 0, 0, 0, 0, NULL }; + device.name = "Unknown"; +@@ -192,13 +210,13 @@ elf32_avr_dump_mem_usage (bfd *abfd) + bfd_size_type text_usage = 0; + bfd_size_type eeprom_usage = 0; + +- char *contents = elf32_avr_get_note_section_contents (abfd, +- ¬e_section_size); ++ char *contents = elf32_avr_get_note_section_contents (abfd, &sec_size); + + if (contents != NULL) + { +- description = elf32_avr_get_note_desc (abfd, contents, note_section_size); +- elf32_avr_get_device_info (abfd, description, &device); ++ description = elf32_avr_get_note_desc (abfd, contents, sec_size, ++ &desc_size); ++ elf32_avr_get_device_info (abfd, description, desc_size, &device); + } + + elf32_avr_get_memory_usage (abfd, &text_usage, &data_usage, diff --git a/meta/recipes-devtools/binutils/binutils/CVE-2021-46174.patch b/meta/recipes-devtools/binutils/binutils/CVE-2021-46174.patch new file mode 100644 index 0000000000..2addf5139e --- /dev/null +++ b/meta/recipes-devtools/binutils/binutils/CVE-2021-46174.patch @@ -0,0 +1,35 @@ +From 46322722ad40ac1a75672ae0f62f4969195f1368 Mon Sep 17 00:00:00 2001 +From: Alan Modra <amodra@gmail.com> +Date: Thu, 20 Jan 2022 13:58:38 +1030 +Subject: [PATCH] PR28753, buffer overflow in read_section_stabs_debugging_info + + PR 28753 + * rddbg.c (read_section_stabs_debugging_info): Don't read past + end of section when concatentating stab strings. + +CVE: CVE-2021-46174 +Upstream-Status: Backport [https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=cad4d6b91e97] + +(cherry picked from commit 085b299b71721e15f5c5c5344dc3e4e4536dadba) +(cherry picked from commit cad4d6b91e97b6962807d33c04ed7e7797788438) +Signed-off-by: poojitha adireddy <pooadire@cisco.com> +--- + binutils/rddbg.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/binutils/rddbg.c b/binutils/rddbg.c +index 72e934055b5..5e76d94a3c4 100644 +--- a/binutils/rddbg.c ++++ b/binutils/rddbg.c +@@ -207,7 +207,7 @@ read_section_stabs_debugging_info (bfd *abfd, asymbol **syms, long symcount, + an attempt to read the byte before 'strings' would occur. */ + while ((len = strlen (s)) > 0 + && s[len - 1] == '\\' +- && stab + 12 < stabs + stabsize) ++ && stab + 16 <= stabs + stabsize) + { + char *p; + +-- +2.23.1 + diff --git a/meta/recipes-devtools/binutils/binutils/CVE-2022-38533.patch b/meta/recipes-devtools/binutils/binutils/CVE-2022-38533.patch new file mode 100644 index 0000000000..102d65f8a6 --- /dev/null +++ b/meta/recipes-devtools/binutils/binutils/CVE-2022-38533.patch @@ -0,0 +1,37 @@ +From ef186fe54aa6d281a3ff8a9528417e5cc614c797 Mon Sep 17 00:00:00 2001 +From: Alan Modra <amodra@gmail.com> +Date: Sat, 13 Aug 2022 15:32:47 +0930 +Subject: [PATCH] PR29482 - strip: heap-buffer-overflow + + PR 29482 + * coffcode.h (coff_set_section_contents): Sanity check _LIB. + +CVE: CVE-2022-38533 +Upstream-Status: Backport [https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=ef186fe54aa6d281a3ff8a9528417e5cc614c797] + +Signed-off-by: Florin Diaconescu <florin.diaconescu009@gmail.com> + +--- + bfd/coffcode.h | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/bfd/coffcode.h b/bfd/coffcode.h +index dec2e9c6370..75c18d88602 100644 +--- a/bfd/coffcode.h ++++ b/bfd/coffcode.h +@@ -4170,10 +4170,13 @@ coff_set_section_contents (bfd * abfd, + + rec = (bfd_byte *) location; + recend = rec + count; +- while (rec < recend) ++ while (recend - rec >= 4) + { ++ size_t len = bfd_get_32 (abfd, rec); ++ if (len == 0 || len > (size_t) (recend - rec) / 4) ++ break; ++ rec += len * 4; + ++section->lma; +- rec += bfd_get_32 (abfd, rec) * 4; + } + + BFD_ASSERT (rec == recend); diff --git a/meta/recipes-devtools/binutils/binutils/CVE-2022-47007.patch b/meta/recipes-devtools/binutils/binutils/CVE-2022-47007.patch new file mode 100644 index 0000000000..ddb564bc8c --- /dev/null +++ b/meta/recipes-devtools/binutils/binutils/CVE-2022-47007.patch @@ -0,0 +1,32 @@ +From 0ebc886149c22aceaf8ed74267821a59ca9d03eb Mon Sep 17 00:00:00 2001 +From: Alan Modra <amodra@gmail.com> +Date: Fri, 17 Jun 2022 09:00:41 +0930 +Subject: [PATCH] PR29254, memory leak in stab_demangle_v3_arg + + PR 29254 + * stabs.c (stab_demangle_v3_arg): Free dt on failure path. +Upstream-Status: Backport [https://sourceware.org/git/?p=binutils-gdb.git;a=commitdiff_plain;h=0ebc886149c22aceaf8ed74267821a59ca9d03eb] +CVE: CVE-2022-47007 +Signed-off-by: Virendra Thakur <virendrak@kpit.com> +Comment: Patch refreshed based on codebase. +--- + binutils/stabs.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/binutils/stabs.c b/binutils/stabs.c +index 2b5241637c1..796ff85b86a 100644 +--- a/binutils/stabs.c ++++ b/binutils/stabs.c +@@ -5476,7 +5476,10 @@ + dc->u.s_binary.right, + &varargs); + if (pargs == NULL) +- return NULL; ++ { ++ free (dt); ++ return NULL; ++ } + + return debug_make_function_type (dhandle, dt, pargs, varargs); + } + diff --git a/meta/recipes-devtools/binutils/binutils/CVE-2022-47008.patch b/meta/recipes-devtools/binutils/binutils/CVE-2022-47008.patch new file mode 100644 index 0000000000..9527390ccf --- /dev/null +++ b/meta/recipes-devtools/binutils/binutils/CVE-2022-47008.patch @@ -0,0 +1,64 @@ +From d6e1d48c83b165c129cb0aa78905f7ca80a1f682 Mon Sep 17 00:00:00 2001 +From: Alan Modra <amodra@gmail.com> +Date: Fri, 17 Jun 2022 09:13:38 +0930 +Subject: [PATCH] PR29255, memory leak in make_tempdir + + PR 29255 + * bucomm.c (make_tempdir, make_tempname): Free template on all + failure paths. +Upstream-Status: Backport [https://sourceware.org/git/?p=binutils-gdb.git;a=commitdiff_plain;h=d6e1d48c83b165c129cb0aa78905f7ca80a1f682] +CVE: CVE-2022-47008 +Signed-off-by: Virendra Thakur <virendrak@kpit.com> +Comment: Patch refreshed based on codebase. +--- + binutils/bucomm.c | 20 +++++++++++--------- + 1 file changed, 11 insertions(+), 9 deletions(-) + +diff --git a/binutils/bucomm.c b/binutils/bucomm.c +index fdc2209df9c..4395cb9f7f5 100644 +--- a/binutils/bucomm.c ++++ b/binutils/bucomm.c +@@ -542,8 +542,9 @@ + #else + tmpname = mktemp (tmpname); + if (tmpname == NULL) +- return NULL; +- fd = open (tmpname, O_RDWR | O_CREAT | O_EXCL, 0600); ++ fd = -1; ++ else ++ fd = open (tmpname, O_RDWR | O_CREAT | O_EXCL, 0600); + #endif + if (fd == -1) + { +@@ -561,22 +562,23 @@ + make_tempdir (const char *filename) + { + char *tmpname = template_in_dir (filename); ++ char *ret; + + #ifdef HAVE_MKDTEMP +- return mkdtemp (tmpname); ++ ret = mkdtemp (tmpname); + #else +- tmpname = mktemp (tmpname); +- if (tmpname == NULL) +- return NULL; ++ ret = mktemp (tmpname); + #if defined (_WIN32) && !defined (__CYGWIN32__) + if (mkdir (tmpname) != 0) +- return NULL; ++ ret = NULL; + #else + if (mkdir (tmpname, 0700) != 0) +- return NULL; ++ ret = NULL; + #endif +- return tmpname; + #endif ++ if (ret == NULL) ++ free (tmpname); ++ return ret; + } + + /* Parse a string into a VMA, with a fatal error if it can't be + diff --git a/meta/recipes-devtools/binutils/binutils/CVE-2022-47010.patch b/meta/recipes-devtools/binutils/binutils/CVE-2022-47010.patch new file mode 100644 index 0000000000..d831ed4756 --- /dev/null +++ b/meta/recipes-devtools/binutils/binutils/CVE-2022-47010.patch @@ -0,0 +1,34 @@ +From 0d02e70b197c786f26175b9a73f94e01d14abdab Mon Sep 17 00:00:00 2001 +From: Alan Modra <amodra@gmail.com> +Date: Mon, 20 Jun 2022 10:39:31 +0930 +Subject: [PATCH] PR29262, memory leak in pr_function_type + + PR 29262 + * prdbg.c (pr_function_type): Free "s" on failure path. +Upstream-Status: Backport [https://sourceware.org/git/?p=binutils-gdb.git;a=commitdiff_plain;h=0d02e70b197c786f26175b9a73f94e01d14abdab] +CVE: CVE-2022-47010 +Signed-off-by: Virendra Thakur <virendrak@kpit.com> +Comment: Patch refreshed based on codebase. +--- + binutils/prdbg.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/binutils/prdbg.c b/binutils/prdbg.c +index c1e41628d26..bb42a5b6c2d 100644 +--- a/binutils/prdbg.c ++++ b/binutils/prdbg.c +@@ -778,12 +778,9 @@ + + strcat (s, ")"); + +- if (! substitute_type (info, s)) +- return FALSE; +- ++ bfd_boolean ret = substitute_type (info, s); + free (s); +- +- return TRUE; ++ return ret; + } + + /* Turn the top type on the stack into a reference to that type. */ diff --git a/meta/recipes-devtools/binutils/binutils/CVE-2022-47011.patch b/meta/recipes-devtools/binutils/binutils/CVE-2022-47011.patch new file mode 100644 index 0000000000..250756bd38 --- /dev/null +++ b/meta/recipes-devtools/binutils/binutils/CVE-2022-47011.patch @@ -0,0 +1,31 @@ +From 8a24927bc8dbf6beac2000593b21235c3796dc35 Mon Sep 17 00:00:00 2001 +From: Alan Modra <amodra@gmail.com> +Date: Mon, 20 Jun 2022 10:39:13 +0930 +Subject: [PATCH] PR29261, memory leak in parse_stab_struct_fields + + PR 29261 + * stabs.c (parse_stab_struct_fields): Free "fields" on failure path. +Upstream-Status: Backport [https://sourceware.org/git/?p=binutils-gdb.git;a=commitdiff_plain;h=8a24927bc8dbf6beac2000593b21235c3796dc35] +CVE: CVE-2022-47011 +Signed-off-by: Virendra Thakur <virendrak@kpit.com> +Comment: Patch refreshed based on codebase. +--- + binutils/stabs.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/binutils/stabs.c b/binutils/stabs.c +index 796ff85b86a..bf3f578cbcc 100644 +--- a/binutils/stabs.c ++++ b/binutils/stabs.c +@@ -2368,7 +2368,10 @@ + + if (! parse_stab_one_struct_field (dhandle, info, pp, p, fields + c, + staticsp, p_end)) +- return FALSE; ++ { ++ free (fields); ++ return FALSE; ++ } + + ++c; + } diff --git a/meta/recipes-devtools/binutils/binutils/CVE-2022-47695.patch b/meta/recipes-devtools/binutils/binutils/CVE-2022-47695.patch new file mode 100644 index 0000000000..101a4cdb4e --- /dev/null +++ b/meta/recipes-devtools/binutils/binutils/CVE-2022-47695.patch @@ -0,0 +1,57 @@ +From 3d3af4ba39e892b1c544d667ca241846bc3df386 Mon Sep 17 00:00:00 2001 +From: Alan Modra <amodra@gmail.com> +Date: Sun, 4 Dec 2022 22:15:40 +1030 +Subject: [PATCH] PR29846, segmentation fault in objdump.c compare_symbols + +Fixes a fuzzed object file problem where plt relocs were manipulated +in such a way that two synthetic symbols were generated at the same +plt location. Won't occur in real object files. + + PR 29846 + PR 20337 + * objdump.c (compare_symbols): Test symbol flags to exclude + section and synthetic symbols before attempting to check flavour. +Upstream-Status: Backport [https://sourceware.org/git/?p=binutils-gdb.git;a=commitdiff;h=3d3af4ba39e892b1c544d667ca241846bc3df386] +CVE: CVE-2022-47695 +Signed-off-by: Virendra Thakur <virendrak@kpit.com> +Comment: Patch refreshed based on codebase. +--- + binutils/objdump.c | 23 ++++++++++------------- + 1 file changed, 10 insertions(+), 13 deletions(-) + +diff --git a/binutils/objdump.c b/binutils/objdump.c +index e8481b2d928..d95c8b68bf0 100644 +--- a/binutils/objdump.c ++++ b/binutils/objdump.c +@@ -935,20 +935,17 @@ + return 1; + } + +- if (bfd_get_flavour (bfd_asymbol_bfd (a)) == bfd_target_elf_flavour ++ /* Sort larger size ELF symbols before smaller. See PR20337. */ ++ bfd_vma asz = 0; ++ if ((a->flags & (BSF_SECTION_SYM | BSF_SYNTHETIC)) == 0 ++ && bfd_get_flavour (bfd_asymbol_bfd (a)) == bfd_target_elf_flavour) ++ asz = ((elf_symbol_type *) a)->internal_elf_sym.st_size; ++ bfd_vma bsz = 0; ++ if ((b->flags & (BSF_SECTION_SYM | BSF_SYNTHETIC)) == 0 + && bfd_get_flavour (bfd_asymbol_bfd (b)) == bfd_target_elf_flavour) +- { +- bfd_vma asz, bsz; +- +- asz = 0; +- if ((a->flags & (BSF_SECTION_SYM | BSF_SYNTHETIC)) == 0) +- asz = ((elf_symbol_type *) a)->internal_elf_sym.st_size; +- bsz = 0; +- if ((b->flags & (BSF_SECTION_SYM | BSF_SYNTHETIC)) == 0) +- bsz = ((elf_symbol_type *) b)->internal_elf_sym.st_size; +- if (asz != bsz) +- return asz > bsz ? -1 : 1; +- } ++ bsz = ((elf_symbol_type *) b)->internal_elf_sym.st_size; ++ if (asz != bsz) ++ return asz > bsz ? -1 : 1; + + /* Symbols that start with '.' might be section names, so sort them + after symbols that don't start with '.'. */ + diff --git a/meta/recipes-devtools/binutils/binutils/CVE-2022-48063.patch b/meta/recipes-devtools/binutils/binutils/CVE-2022-48063.patch new file mode 100644 index 0000000000..f41c02a02b --- /dev/null +++ b/meta/recipes-devtools/binutils/binutils/CVE-2022-48063.patch @@ -0,0 +1,49 @@ +From 75393a2d54bcc40053e5262a3de9d70c5ebfbbfd Mon Sep 17 00:00:00 2001 +From: Nick Clifton <nickc@redhat.com> +Date: Wed, 21 Dec 2022 11:51:23 +0000 +Subject: [PATCH] Fix an attempt to allocate an unreasonably large amount of + memory when parsing a corrupt ELF file. + + PR 29924 + * objdump.c (load_specific_debug_section): Check for excessively + large sections. +Upstream-Status: Backport [https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=75393a2d54bcc40053e5262a3de9d70c5ebfbbfd] +CVE: CVE-2022-48063 +Signed-off-by: Virendra Thakur <virendrak@kpit.com> +Comment: Patch refreshed based on codebase. +--- + binutils/ChangeLog | 6 ++++++ + binutils/objdump.c | 4 +++- + 2 files changed, 9 insertions(+), 1 deletion(-) + +diff --git a/binutils/ChangeLog b/binutils/ChangeLog +index e7f918d3f65..020e09f3700 100644 +--- a/binutils/ChangeLog ++++ b/binutils/ChangeLog +@@ -1,3 +1,9 @@ ++2022-12-21 Nick Clifton <nickc@redhat.com> ++ ++ PR 29924 ++ * objdump.c (load_specific_debug_section): Check for excessively ++ large sections. ++ + 2021-02-11 Alan Modra <amodra@gmail.com> + + PR 27290 + +diff --git a/binutils/objdump.c b/binutils/objdump.c +index d51abbe3858..2eb02de0e76 100644 +--- a/binutils/objdump.c ++++ b/binutils/objdump.c +@@ -3479,7 +3479,9 @@ + section->size = bfd_section_size (sec); + /* PR 24360: On 32-bit hosts sizeof (size_t) < sizeof (bfd_size_type). */ + alloced = amt = section->size + 1; +- if (alloced != amt || alloced == 0) ++ if (alloced != amt ++ || alloced == 0 ++ || (bfd_get_size (abfd) != 0 && alloced >= bfd_get_size (abfd))) + { + section->start = NULL; + free_debug_section (debug); + diff --git a/meta/recipes-devtools/binutils/binutils/CVE-2023-25584.patch b/meta/recipes-devtools/binutils/binutils/CVE-2023-25584.patch new file mode 100644 index 0000000000..732ea43210 --- /dev/null +++ b/meta/recipes-devtools/binutils/binutils/CVE-2023-25584.patch @@ -0,0 +1,530 @@ +CVE: CVE-2023-25584 +Upstream-Status: Backport [ import from ubuntu http://archive.ubuntu.com/ubuntu/pool/main/b/binutils/binutils_2.34-6ubuntu1.7.debian.tar.xz upstream https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=77c225bdeb410cf60da804879ad41622f5f1aa44 ] +Signed-off-by: Lee Chee Yang <chee.yang.lee@intel.com> + +[Ubuntu note: this is backport of the original patch, no major changes just + fix this patch for this release] +From 77c225bdeb410cf60da804879ad41622f5f1aa44 Mon Sep 17 00:00:00 2001 +From: Alan Modra <amodra@gmail.com> +Date: Mon, 12 Dec 2022 18:28:49 +1030 +Subject: [PATCH] Lack of bounds checking in vms-alpha.c parse_module + + PR 29873 + PR 29874 + PR 29875 + PR 29876 + PR 29877 + PR 29878 + PR 29879 + PR 29880 + PR 29881 + PR 29882 + PR 29883 + PR 29884 + PR 29885 + PR 29886 + PR 29887 + PR 29888 + PR 29889 + PR 29890 + PR 29891 + * vms-alpha.c (parse_module): Make length param bfd_size_type. + Delete length == -1 checks. Sanity check record_length. + Sanity check DST__K_MODBEG, DST__K_RTNBEG, DST__K_RTNEND lengths. + Sanity check DST__K_SOURCE and DST__K_LINE_NUM elements + before accessing. + (build_module_list): Pass dst_section size to parse_module. +--- + bfd/vms-alpha.c | 213 ++++++++++++++++++++++++++++++++++++++---------- + 1 file changed, 168 insertions(+), 45 deletions(-) + +--- binutils-2.34.orig/bfd/vms-alpha.c ++++ binutils-2.34/bfd/vms-alpha.c +@@ -4267,7 +4267,7 @@ new_module (bfd *abfd) + + static void + parse_module (bfd *abfd, struct module *module, unsigned char *ptr, +- int length) ++ bfd_size_type length) + { + unsigned char *maxptr = ptr + length; + unsigned char *src_ptr, *pcl_ptr; +@@ -4284,7 +4284,7 @@ parse_module (bfd *abfd, struct module * + curr_line = (struct lineinfo *) bfd_zalloc (abfd, sizeof (struct lineinfo)); + module->line_table = curr_line; + +- while (length == -1 || ptr < maxptr) ++ while (ptr < maxptr) + { + /* The first byte is not counted in the recorded length. */ + int rec_length = bfd_getl16 (ptr) + 1; +@@ -4292,15 +4292,19 @@ parse_module (bfd *abfd, struct module * + + vms_debug2 ((2, "DST record: leng %d, type %d\n", rec_length, rec_type)); + +- if (length == -1 && rec_type == DST__K_MODEND) ++ if (rec_length > maxptr - ptr) ++ break; ++ if (rec_type == DST__K_MODEND) + break; + + switch (rec_type) + { + case DST__K_MODBEG: ++ if (rec_length <= DST_S_B_MODBEG_NAME) ++ break; + module->name + = _bfd_vms_save_counted_string (abfd, ptr + DST_S_B_MODBEG_NAME, +- maxptr - (ptr + DST_S_B_MODBEG_NAME)); ++ rec_length - DST_S_B_MODBEG_NAME); + + curr_pc = 0; + prev_pc = 0; +@@ -4314,11 +4318,13 @@ parse_module (bfd *abfd, struct module * + break; + + case DST__K_RTNBEG: ++ if (rec_length <= DST_S_B_RTNBEG_NAME) ++ break; + funcinfo = (struct funcinfo *) + bfd_zalloc (abfd, sizeof (struct funcinfo)); + funcinfo->name + = _bfd_vms_save_counted_string (abfd, ptr + DST_S_B_RTNBEG_NAME, +- maxptr - (ptr + DST_S_B_RTNBEG_NAME)); ++ rec_length - DST_S_B_RTNBEG_NAME); + funcinfo->low = bfd_getl32 (ptr + DST_S_L_RTNBEG_ADDRESS); + funcinfo->next = module->func_table; + module->func_table = funcinfo; +@@ -4328,6 +4334,8 @@ parse_module (bfd *abfd, struct module * + break; + + case DST__K_RTNEND: ++ if (rec_length < DST_S_L_RTNEND_SIZE + 4) ++ break; + module->func_table->high = module->func_table->low + + bfd_getl32 (ptr + DST_S_L_RTNEND_SIZE) - 1; + +@@ -4358,13 +4366,66 @@ parse_module (bfd *abfd, struct module * + + vms_debug2 ((3, "source info\n")); + +- while (src_ptr < ptr + rec_length) ++ while (src_ptr - ptr < rec_length) + { + int cmd = src_ptr[0], cmd_length, data; + + switch (cmd) + { + case DST__K_SRC_DECLFILE: ++ if (src_ptr - ptr + DST_S_B_SRC_DF_LENGTH >= rec_length) ++ cmd_length = 0x10000; ++ else ++ cmd_length = src_ptr[DST_S_B_SRC_DF_LENGTH] + 2; ++ break; ++ ++ case DST__K_SRC_DEFLINES_B: ++ cmd_length = 2; ++ break; ++ ++ case DST__K_SRC_DEFLINES_W: ++ cmd_length = 3; ++ break; ++ ++ case DST__K_SRC_INCRLNUM_B: ++ cmd_length = 2; ++ break; ++ ++ case DST__K_SRC_SETFILE: ++ cmd_length = 3; ++ break; ++ ++ case DST__K_SRC_SETLNUM_L: ++ cmd_length = 5; ++ break; ++ ++ case DST__K_SRC_SETLNUM_W: ++ cmd_length = 3; ++ break; ++ ++ case DST__K_SRC_SETREC_L: ++ cmd_length = 5; ++ break; ++ ++ case DST__K_SRC_SETREC_W: ++ cmd_length = 3; ++ break; ++ ++ case DST__K_SRC_FORMFEED: ++ cmd_length = 1; ++ break; ++ ++ default: ++ cmd_length = 2; ++ break; ++ } ++ ++ if (src_ptr - ptr + cmd_length > rec_length) ++ break; ++ ++ switch (cmd) ++ { ++ case DST__K_SRC_DECLFILE: + { + unsigned int fileid + = bfd_getl16 (src_ptr + DST_S_W_SRC_DF_FILEID); +@@ -4384,7 +4445,6 @@ parse_module (bfd *abfd, struct module * + + module->file_table [fileid].name = filename; + module->file_table [fileid].srec = 1; +- cmd_length = src_ptr[DST_S_B_SRC_DF_LENGTH] + 2; + vms_debug2 ((4, "DST_S_C_SRC_DECLFILE: %d, %s\n", + fileid, module->file_table [fileid].name)); + } +@@ -4401,7 +4461,6 @@ parse_module (bfd *abfd, struct module * + srec->sfile = curr_srec->sfile; + curr_srec->next = srec; + curr_srec = srec; +- cmd_length = 2; + vms_debug2 ((4, "DST_S_C_SRC_DEFLINES_B: %d\n", data)); + break; + +@@ -4416,14 +4475,12 @@ parse_module (bfd *abfd, struct module * + srec->sfile = curr_srec->sfile; + curr_srec->next = srec; + curr_srec = srec; +- cmd_length = 3; + vms_debug2 ((4, "DST_S_C_SRC_DEFLINES_W: %d\n", data)); + break; + + case DST__K_SRC_INCRLNUM_B: + data = src_ptr[DST_S_B_SRC_UNSBYTE]; + curr_srec->line += data; +- cmd_length = 2; + vms_debug2 ((4, "DST_S_C_SRC_INCRLNUM_B: %d\n", data)); + break; + +@@ -4431,21 +4488,18 @@ parse_module (bfd *abfd, struct module * + data = bfd_getl16 (src_ptr + DST_S_W_SRC_UNSWORD); + curr_srec->sfile = data; + curr_srec->srec = module->file_table[data].srec; +- cmd_length = 3; + vms_debug2 ((4, "DST_S_C_SRC_SETFILE: %d\n", data)); + break; + + case DST__K_SRC_SETLNUM_L: + data = bfd_getl32 (src_ptr + DST_S_L_SRC_UNSLONG); + curr_srec->line = data; +- cmd_length = 5; + vms_debug2 ((4, "DST_S_C_SRC_SETLNUM_L: %d\n", data)); + break; + + case DST__K_SRC_SETLNUM_W: + data = bfd_getl16 (src_ptr + DST_S_W_SRC_UNSWORD); + curr_srec->line = data; +- cmd_length = 3; + vms_debug2 ((4, "DST_S_C_SRC_SETLNUM_W: %d\n", data)); + break; + +@@ -4453,7 +4507,6 @@ parse_module (bfd *abfd, struct module * + data = bfd_getl32 (src_ptr + DST_S_L_SRC_UNSLONG); + curr_srec->srec = data; + module->file_table[curr_srec->sfile].srec = data; +- cmd_length = 5; + vms_debug2 ((4, "DST_S_C_SRC_SETREC_L: %d\n", data)); + break; + +@@ -4461,19 +4514,16 @@ parse_module (bfd *abfd, struct module * + data = bfd_getl16 (src_ptr + DST_S_W_SRC_UNSWORD); + curr_srec->srec = data; + module->file_table[curr_srec->sfile].srec = data; +- cmd_length = 3; + vms_debug2 ((4, "DST_S_C_SRC_SETREC_W: %d\n", data)); + break; + + case DST__K_SRC_FORMFEED: +- cmd_length = 1; + vms_debug2 ((4, "DST_S_C_SRC_FORMFEED\n")); + break; + + default: + _bfd_error_handler (_("unknown source command %d"), + cmd); +- cmd_length = 2; + break; + } + +@@ -4486,7 +4536,7 @@ parse_module (bfd *abfd, struct module * + + vms_debug2 ((3, "line info\n")); + +- while (pcl_ptr < ptr + rec_length) ++ while (pcl_ptr - ptr < rec_length) + { + /* The command byte is signed so we must sign-extend it. */ + int cmd = ((signed char *)pcl_ptr)[0], cmd_length, data; +@@ -4494,10 +4544,106 @@ parse_module (bfd *abfd, struct module * + switch (cmd) + { + case DST__K_DELTA_PC_W: ++ cmd_length = 3; ++ break; ++ ++ case DST__K_DELTA_PC_L: ++ cmd_length = 5; ++ break; ++ ++ case DST__K_INCR_LINUM: ++ cmd_length = 2; ++ break; ++ ++ case DST__K_INCR_LINUM_W: ++ cmd_length = 3; ++ break; ++ ++ case DST__K_INCR_LINUM_L: ++ cmd_length = 5; ++ break; ++ ++ case DST__K_SET_LINUM_INCR: ++ cmd_length = 2; ++ break; ++ ++ case DST__K_SET_LINUM_INCR_W: ++ cmd_length = 3; ++ break; ++ ++ case DST__K_RESET_LINUM_INCR: ++ cmd_length = 1; ++ break; ++ ++ case DST__K_BEG_STMT_MODE: ++ cmd_length = 1; ++ break; ++ ++ case DST__K_END_STMT_MODE: ++ cmd_length = 1; ++ break; ++ ++ case DST__K_SET_LINUM_B: ++ cmd_length = 2; ++ break; ++ ++ case DST__K_SET_LINUM: ++ cmd_length = 3; ++ break; ++ ++ case DST__K_SET_LINUM_L: ++ cmd_length = 5; ++ break; ++ ++ case DST__K_SET_PC: ++ cmd_length = 2; ++ break; ++ ++ case DST__K_SET_PC_W: ++ cmd_length = 3; ++ break; ++ ++ case DST__K_SET_PC_L: ++ cmd_length = 5; ++ break; ++ ++ case DST__K_SET_STMTNUM: ++ cmd_length = 2; ++ break; ++ ++ case DST__K_TERM: ++ cmd_length = 2; ++ break; ++ ++ case DST__K_TERM_W: ++ cmd_length = 3; ++ break; ++ ++ case DST__K_TERM_L: ++ cmd_length = 5; ++ break; ++ ++ case DST__K_SET_ABS_PC: ++ cmd_length = 5; ++ break; ++ ++ default: ++ if (cmd <= 0) ++ cmd_length = 1; ++ else ++ cmd_length = 2; ++ break; ++ } ++ ++ if (pcl_ptr - ptr + cmd_length > rec_length) ++ break; ++ ++ switch (cmd) ++ { ++ case DST__K_DELTA_PC_W: + data = bfd_getl16 (pcl_ptr + DST_S_W_PCLINE_UNSWORD); + curr_pc += data; + curr_linenum += 1; +- cmd_length = 3; + vms_debug2 ((4, "DST__K_DELTA_PC_W: %d\n", data)); + break; + +@@ -4505,131 +4651,111 @@ parse_module (bfd *abfd, struct module * + data = bfd_getl32 (pcl_ptr + DST_S_L_PCLINE_UNSLONG); + curr_pc += data; + curr_linenum += 1; +- cmd_length = 5; + vms_debug2 ((4, "DST__K_DELTA_PC_L: %d\n", data)); + break; + + case DST__K_INCR_LINUM: + data = pcl_ptr[DST_S_B_PCLINE_UNSBYTE]; + curr_linenum += data; +- cmd_length = 2; + vms_debug2 ((4, "DST__K_INCR_LINUM: %d\n", data)); + break; + + case DST__K_INCR_LINUM_W: + data = bfd_getl16 (pcl_ptr + DST_S_W_PCLINE_UNSWORD); + curr_linenum += data; +- cmd_length = 3; + vms_debug2 ((4, "DST__K_INCR_LINUM_W: %d\n", data)); + break; + + case DST__K_INCR_LINUM_L: + data = bfd_getl32 (pcl_ptr + DST_S_L_PCLINE_UNSLONG); + curr_linenum += data; +- cmd_length = 5; + vms_debug2 ((4, "DST__K_INCR_LINUM_L: %d\n", data)); + break; + + case DST__K_SET_LINUM_INCR: + _bfd_error_handler + (_("%s not implemented"), "DST__K_SET_LINUM_INCR"); +- cmd_length = 2; + break; + + case DST__K_SET_LINUM_INCR_W: + _bfd_error_handler + (_("%s not implemented"), "DST__K_SET_LINUM_INCR_W"); +- cmd_length = 3; + break; + + case DST__K_RESET_LINUM_INCR: + _bfd_error_handler + (_("%s not implemented"), "DST__K_RESET_LINUM_INCR"); +- cmd_length = 1; + break; + + case DST__K_BEG_STMT_MODE: + _bfd_error_handler + (_("%s not implemented"), "DST__K_BEG_STMT_MODE"); +- cmd_length = 1; + break; + + case DST__K_END_STMT_MODE: + _bfd_error_handler + (_("%s not implemented"), "DST__K_END_STMT_MODE"); +- cmd_length = 1; + break; + + case DST__K_SET_LINUM_B: + data = pcl_ptr[DST_S_B_PCLINE_UNSBYTE]; + curr_linenum = data; +- cmd_length = 2; + vms_debug2 ((4, "DST__K_SET_LINUM_B: %d\n", data)); + break; + + case DST__K_SET_LINUM: + data = bfd_getl16 (pcl_ptr + DST_S_W_PCLINE_UNSWORD); + curr_linenum = data; +- cmd_length = 3; + vms_debug2 ((4, "DST__K_SET_LINE_NUM: %d\n", data)); + break; + + case DST__K_SET_LINUM_L: + data = bfd_getl32 (pcl_ptr + DST_S_L_PCLINE_UNSLONG); + curr_linenum = data; +- cmd_length = 5; + vms_debug2 ((4, "DST__K_SET_LINUM_L: %d\n", data)); + break; + + case DST__K_SET_PC: + _bfd_error_handler + (_("%s not implemented"), "DST__K_SET_PC"); +- cmd_length = 2; + break; + + case DST__K_SET_PC_W: + _bfd_error_handler + (_("%s not implemented"), "DST__K_SET_PC_W"); +- cmd_length = 3; + break; + + case DST__K_SET_PC_L: + _bfd_error_handler + (_("%s not implemented"), "DST__K_SET_PC_L"); +- cmd_length = 5; + break; + + case DST__K_SET_STMTNUM: + _bfd_error_handler + (_("%s not implemented"), "DST__K_SET_STMTNUM"); +- cmd_length = 2; + break; + + case DST__K_TERM: + data = pcl_ptr[DST_S_B_PCLINE_UNSBYTE]; + curr_pc += data; +- cmd_length = 2; + vms_debug2 ((4, "DST__K_TERM: %d\n", data)); + break; + + case DST__K_TERM_W: + data = bfd_getl16 (pcl_ptr + DST_S_W_PCLINE_UNSWORD); + curr_pc += data; +- cmd_length = 3; + vms_debug2 ((4, "DST__K_TERM_W: %d\n", data)); + break; + + case DST__K_TERM_L: + data = bfd_getl32 (pcl_ptr + DST_S_L_PCLINE_UNSLONG); + curr_pc += data; +- cmd_length = 5; + vms_debug2 ((4, "DST__K_TERM_L: %d\n", data)); + break; + + case DST__K_SET_ABS_PC: + data = bfd_getl32 (pcl_ptr + DST_S_L_PCLINE_UNSLONG); + curr_pc = data; +- cmd_length = 5; + vms_debug2 ((4, "DST__K_SET_ABS_PC: 0x%x\n", data)); + break; + +@@ -4638,15 +4764,11 @@ parse_module (bfd *abfd, struct module * + { + curr_pc -= cmd; + curr_linenum += 1; +- cmd_length = 1; + vms_debug2 ((4, "bump pc to 0x%lx and line to %d\n", + (unsigned long)curr_pc, curr_linenum)); + } + else +- { +- _bfd_error_handler (_("unknown line command %d"), cmd); +- cmd_length = 2; +- } ++ _bfd_error_handler (_("unknown line command %d"), cmd); + break; + } + +@@ -4778,7 +4900,7 @@ build_module_list (bfd *abfd) + return NULL; + + module = new_module (abfd); +- parse_module (abfd, module, PRIV (dst_section)->contents, -1); ++ parse_module (abfd, module, PRIV (dst_section)->contents, PRIV (dst_section)->size); + list = module; + } + diff --git a/meta/recipes-devtools/binutils/binutils/CVE-2023-25588.patch b/meta/recipes-devtools/binutils/binutils/CVE-2023-25588.patch new file mode 100644 index 0000000000..aa5ce5f3ff --- /dev/null +++ b/meta/recipes-devtools/binutils/binutils/CVE-2023-25588.patch @@ -0,0 +1,149 @@ +From d12f8998d2d086f0a6606589e5aedb7147e6f2f1 Mon Sep 17 00:00:00 2001 +From: Alan Modra <amodra@gmail.com> +Date: Fri, 14 Oct 2022 10:30:21 +1030 +Subject: [PATCH] PR29677, Field `the_bfd` of `asymbol` is uninitialised + +Besides not initialising the_bfd of synthetic symbols, counting +symbols when sizing didn't match symbols created if there were any +dynsyms named "". We don't want synthetic symbols without names +anyway, so get rid of them. Also, simplify and correct sanity checks. + + PR 29677 + * mach-o.c (bfd_mach_o_get_synthetic_symtab): Rewrite. +--- +Upstream-Status: Backport from [https://sourceware.org/git/?p=binutils-gdb.git;a=patch;h=d12f8998d2d086f0a6606589e5aedb7147e6f2f1] +CVE: CVE-2023-25588 +CVE: CVE-2022-47696 + +Signed-off-by: Ashish Sharma <asharma@mvista.com> +Signed-off-by: poojitha adireddy <pooadire@cisco.com> + + bfd/mach-o.c | 72 ++++++++++++++++++++++------------------------------ + 1 file changed, 31 insertions(+), 41 deletions(-) + +diff --git a/bfd/mach-o.c b/bfd/mach-o.c +index acb35e7f0c6..5279343768c 100644 +--- a/bfd/mach-o.c ++++ b/bfd/mach-o.c +@@ -938,11 +938,9 @@ bfd_mach_o_get_synthetic_symtab (bfd *abfd, + bfd_mach_o_symtab_command *symtab = mdata->symtab; + asymbol *s; + char * s_start; +- char * s_end; + unsigned long count, i, j, n; + size_t size; + char *names; +- char *nul_name; + const char stub [] = "$stub"; + + *ret = NULL; +@@ -955,27 +953,27 @@ bfd_mach_o_get_synthetic_symtab (bfd *abfd, + /* We need to allocate a bfd symbol for every indirect symbol and to + allocate the memory for its name. */ + count = dysymtab->nindirectsyms; +- size = count * sizeof (asymbol) + 1; +- ++ size = 0; + for (j = 0; j < count; j++) + { +- const char * strng; + unsigned int isym = dysymtab->indirect_syms[j]; ++ const char *str; + + /* Some indirect symbols are anonymous. */ +- if (isym < symtab->nsyms && (strng = symtab->symbols[isym].symbol.name)) +- /* PR 17512: file: f5b8eeba. */ +- size += strnlen (strng, symtab->strsize - (strng - symtab->strtab)) + sizeof (stub); ++ if (isym < symtab->nsyms ++ && (str = symtab->symbols[isym].symbol.name) != NULL) ++ { ++ /* PR 17512: file: f5b8eeba. */ ++ size += strnlen (str, symtab->strsize - (str - symtab->strtab)); ++ size += sizeof (stub); ++ } + } + +- s_start = bfd_malloc (size); ++ s_start = bfd_malloc (size + count * sizeof (asymbol)); + s = *ret = (asymbol *) s_start; + if (s == NULL) + return -1; + names = (char *) (s + count); +- nul_name = names; +- *names++ = 0; +- s_end = s_start + size; + + n = 0; + for (i = 0; i < mdata->nsects; i++) +@@ -997,47 +995,39 @@ bfd_mach_o_get_synthetic_symtab (bfd *abfd, + entry_size = bfd_mach_o_section_get_entry_size (abfd, sec); + + /* PR 17512: file: 08e15eec. */ +- if (first >= count || last >= count || first > last) ++ if (first >= count || last > count || first > last) + goto fail; + + for (j = first; j < last; j++) + { + unsigned int isym = dysymtab->indirect_syms[j]; +- +- /* PR 17512: file: 04d64d9b. */ +- if (((char *) s) + sizeof (* s) > s_end) +- goto fail; +- +- s->flags = BSF_GLOBAL | BSF_SYNTHETIC; +- s->section = sec->bfdsection; +- s->value = addr - sec->addr; +- s->udata.p = NULL; ++ const char *str; ++ size_t len; + + if (isym < symtab->nsyms +- && symtab->symbols[isym].symbol.name) ++ && (str = symtab->symbols[isym].symbol.name) != NULL) + { +- const char *sym = symtab->symbols[isym].symbol.name; +- size_t len; +- +- s->name = names; +- len = strlen (sym); +- /* PR 17512: file: 47dfd4d2. */ +- if (names + len >= s_end) ++ /* PR 17512: file: 04d64d9b. */ ++ if (n >= count) + goto fail; +- memcpy (names, sym, len); +- names += len; +- /* PR 17512: file: 18f340a4. */ +- if (names + sizeof (stub) >= s_end) ++ len = strnlen (str, symtab->strsize - (str - symtab->strtab)); ++ /* PR 17512: file: 47dfd4d2, 18f340a4. */ ++ if (size < len + sizeof (stub)) + goto fail; +- memcpy (names, stub, sizeof (stub)); +- names += sizeof (stub); ++ memcpy (names, str, len); ++ memcpy (names + len, stub, sizeof (stub)); ++ s->name = names; ++ names += len + sizeof (stub); ++ size -= len + sizeof (stub); ++ s->the_bfd = symtab->symbols[isym].symbol.the_bfd; ++ s->flags = BSF_GLOBAL | BSF_SYNTHETIC; ++ s->section = sec->bfdsection; ++ s->value = addr - sec->addr; ++ s->udata.p = NULL; ++ s++; ++ n++; + } +- else +- s->name = nul_name; +- + addr += entry_size; +- s++; +- n++; + } + break; + default: +-- +2.39.3 + diff --git a/meta/recipes-devtools/bootchart2/bootchart2/0001-bootchartd.in-make-sure-only-one-bootchartd-process.patch b/meta/recipes-devtools/bootchart2/bootchart2/0001-bootchartd.in-make-sure-only-one-bootchartd-process.patch new file mode 100644 index 0000000000..3cb8a3c2a2 --- /dev/null +++ b/meta/recipes-devtools/bootchart2/bootchart2/0001-bootchartd.in-make-sure-only-one-bootchartd-process.patch @@ -0,0 +1,68 @@ +From 988ca784d4840c87509e770a21d5d22105af8668 Mon Sep 17 00:00:00 2001 +From: Mingli Yu <mingli.yu@windriver.com> +Date: Fri, 5 Nov 2021 11:18:07 +0800 +Subject: [PATCH] bootchartd.in: make sure only one bootchartd process + +When boot with "init=/sbin/bootchartd" as below: + # runqemu qemux86 bootparams="init=/sbin/bootchartd" + +There are two bootchartd process after boot [1]. + # ps -ef | grep bootchart +root 101 1 0 03:27 ? 00:00:00 /bin/sh /sbin/bootchartd +root 103 101 8 03:27 ? 00:00:02 /lib64/bootchart/bootchart-collector 50 +root 106 1 0 03:27 ? 00:00:00 /bin/sh /sbin/bootchartd +root 792 106 0 03:27 ? 00:00:00 /lib64/bootchart/bootchart-collector --usleep 1000000 +root 794 725 0 03:27 ttyS0 00:00:00 grep bootchart + + # /sbin/bootchartd stop +[bootchart] bootchart-collector started as pid 596 with 2 args: +[bootchart] '--dump' +[bootchart] '/tmp/bootchart.3lXpVDAq3v' +[bootchart] Extracting profile data from pid 204 +[bootchart] map 0xbed9a000 -> 0xbedbb000 size: 132k from 'bed9a000' 'bedbb000' +[bootchart] read 135168 bytes of 135168 +[bootchart] reading 150 chunks (of 150) ... +[bootchart] wrote 18760 kbB +[bootchart] bootchart-collector pid: 596 unmounted proc / clean exit + +But there still one process exist after the above stop command finish. + # ps -ef | grep bootchartd +root 202 1 0 09:09 ? 00:00:00 /bin/sh /sbin/bootchartd +root 629 516 0 09:10 ? 00:00:00 grep bootchartd + +Remove the wait_boot which used to wait the boot process to finish to +make sure only one bootchartd process and meanwhile we don't need the +wait_boot logic because we either use "/sbin/bootchartd stop" to stop +the bootchartd manually or install package bootchartd-stop-initscript +altogether with bootchart2 to stop bootchartd automatically after boot. + +After patch: + # ps -ef | grep bootchart + root 101 1 0 03:36 ? 00:00:00 /bin/sh /sbin/bootchartd + root 103 101 6 03:36 ? 00:00:04 /lib64/bootchart/bootchart-collector 50 + root 596 592 0 03:37 ttyS0 00:00:00 grep bootchart + +[1] https://github.com/xrmx/bootchart/issues/94 + +Upstream-Status: Submitted [https://github.com/xrmx/bootchart/pull/95] + +Signed-off-by: Mingli Yu <mingli.yu@windriver.com> +--- + bootchartd.in | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/bootchartd.in b/bootchartd.in +index 7979ef9..f0e466d 100755 +--- a/bootchartd.in ++++ b/bootchartd.in +@@ -183,7 +183,6 @@ if [ $$ -eq 1 ]; then + else # running inside the main system + echo "bootchart: no initrd used; starting" + start & +- wait_boot & + # wait a little, until the collector is going, before allowing + # the rest of the system to charge ahead, so we catch it + $USLEEP 250000 +-- +2.17.1 + diff --git a/meta/recipes-devtools/bootchart2/bootchart2_0.14.9.bb b/meta/recipes-devtools/bootchart2/bootchart2_0.14.9.bb index 6571c19938..7f05bd1b0b 100644 --- a/meta/recipes-devtools/bootchart2/bootchart2_0.14.9.bb +++ b/meta/recipes-devtools/bootchart2/bootchart2_0.14.9.bb @@ -90,10 +90,11 @@ LIC_FILES_CHKSUM = "file://COPYING;md5=44ac4678311254db62edf8fd39cb8124" UPSTREAM_CHECK_GITTAGREGEX = "(?P<pver>\d+\.\d+(\.\d+)*)" -SRC_URI = "git://github.com/xrmx/bootchart.git \ +SRC_URI = "git://github.com/xrmx/bootchart.git;branch=master;protocol=https \ file://bootchartd_stop.sh \ file://0001-collector-Allocate-space-on-heap-for-chunks.patch \ file://0001-bootchart2-support-usrmerge.patch \ + file://0001-bootchartd.in-make-sure-only-one-bootchartd-process.patch \ " S = "${WORKDIR}/git" @@ -143,7 +144,7 @@ do_install () { PACKAGES =+ "pybootchartgui" FILES_pybootchartgui += "${PYTHON_SITEPACKAGES_DIR}/pybootchartgui ${bindir}/pybootchartgui" -RDEPENDS_pybootchartgui = "python3-pycairo python3-compression python3-image python3-shell python3-compression python3-codecs" +RDEPENDS_pybootchartgui = "python3-pycairo python3-compression python3-image python3-math python3-shell python3-compression python3-codecs" RDEPENDS_${PN}_class-target += "${@bb.utils.contains('DISTRO_FEATURES', 'sysvinit', 'sysvinit-pidof', 'procps', d)}" RDEPENDS_${PN}_class-target += "lsb-release" DEPENDS_append_class-native = " python3-pycairo-native" diff --git a/meta/recipes-devtools/btrfs-tools/btrfs-tools_5.4.1.bb b/meta/recipes-devtools/btrfs-tools/btrfs-tools_5.4.1.bb index 4112cf484f..be61916cc6 100644 --- a/meta/recipes-devtools/btrfs-tools/btrfs-tools_5.4.1.bb +++ b/meta/recipes-devtools/btrfs-tools/btrfs-tools_5.4.1.bb @@ -15,7 +15,7 @@ DEPENDS_append_class-target = " udev" RDEPENDS_${PN} = "libgcc" SRCREV = "3fc2326d3474a5e4df2449f5e3043f7298501334" -SRC_URI = "git://git.kernel.org/pub/scm/linux/kernel/git/kdave/btrfs-progs.git \ +SRC_URI = "git://git.kernel.org/pub/scm/linux/kernel/git/kdave/btrfs-progs.git;branch=master \ file://0001-Add-a-possibility-to-specify-where-python-modules-ar.patch \ " diff --git a/meta/recipes-devtools/build-compare/build-compare_git.bb b/meta/recipes-devtools/build-compare/build-compare_git.bb index b0560cc277..6afa9a0d68 100644 --- a/meta/recipes-devtools/build-compare/build-compare_git.bb +++ b/meta/recipes-devtools/build-compare/build-compare_git.bb @@ -5,7 +5,7 @@ HOMEPAGE = "https://github.com/openSUSE/build-compare" LICENSE = "GPLv2" LIC_FILES_CHKSUM = "file://COPYING;md5=751419260aa954499f7abaabaa882bbe" -SRC_URI = "git://github.com/openSUSE/build-compare.git \ +SRC_URI = "git://github.com/openSUSE/build-compare.git;branch=master;protocol=https \ file://Ignore-DWARF-sections.patch;striplevel=1 \ " diff --git a/meta/recipes-devtools/cmake/cmake-native_3.16.5.bb b/meta/recipes-devtools/cmake/cmake-native_3.16.5.bb index b2952ee5f5..96a7be6770 100644 --- a/meta/recipes-devtools/cmake/cmake-native_3.16.5.bb +++ b/meta/recipes-devtools/cmake/cmake-native_3.16.5.bb @@ -7,6 +7,7 @@ SRC_URI += "file://OEToolchainConfig.cmake \ file://environment.d-cmake.sh \ file://0001-CMakeDetermineSystem-use-oe-environment-vars-to-load.patch \ file://0005-Disable-use-of-ext2fs-ext2_fs.h-by-cmake-s-internal-.patch \ + file://0006-cmake-FindGTest-Add-target-for-gmock-library.patch \ " diff --git a/meta/recipes-devtools/cmake/cmake/0006-cmake-FindGTest-Add-target-for-gmock-library.patch b/meta/recipes-devtools/cmake/cmake/0006-cmake-FindGTest-Add-target-for-gmock-library.patch new file mode 100644 index 0000000000..267f586a71 --- /dev/null +++ b/meta/recipes-devtools/cmake/cmake/0006-cmake-FindGTest-Add-target-for-gmock-library.patch @@ -0,0 +1,255 @@ +From 39eae0d6c1b398f18761abac7f55944f0290f8a1 Mon Sep 17 00:00:00 2001 +From: Eero Aaltonen <eero.aaltonen@iki.fi> +Date: Sun, 17 Oct 2021 17:13:07 +0300 +Subject: [PATCH] FindGTest: Add target for gmock library + +`googlemock` has been absorbed into the +[googletest](https://github.com/google/googletest) project and is built +and installed from the same source tree. + +As GTest may be built with or without GMock, skip GMock if it is not +present. + +Do not provide result variables for GMock. They are not provided by +upstream GTest's CMake Package Configuration File. + +Also update the test case to cover linking to `GTest::gmock`. + +The patch was imported from the Kitware git server +(git@gitlab.kitware.com:cmake/cmake.git) as of commit id +50bf457a0dd857cf976b22c5be7d333493233d1e + +Patch was modified to support upper case variable `GTEST_FOUND`. + +Upstream-Status: Accepted [https://gitlab.kitware.com/cmake/cmake/-/merge_requests/6632] +Milestone: 3.23.0 + +Signed-off-by: Eero Aaltonen <eero.aaltonen@vaisala.com> +--- + .../dev/FindGTest-target-for-gmock.rst | 4 + + Modules/FindGTest.cmake | 133 +++++++++++++++--- + Tests/FindGTest/Test/CMakeLists.txt | 4 + + 3 files changed, 121 insertions(+), 20 deletions(-) + create mode 100644 Help/release/dev/FindGTest-target-for-gmock.rst + +diff --git a/Help/release/dev/FindGTest-target-for-gmock.rst b/Help/release/dev/FindGTest-target-for-gmock.rst +new file mode 100644 +index 0000000000..f78242c80e +--- /dev/null ++++ b/Help/release/dev/FindGTest-target-for-gmock.rst +@@ -0,0 +1,4 @@ ++FindGTest-target-for-gmock ++-------------------------- ++ ++* The :module:`FindGTest` module now provides a target for GMock, if found. +diff --git a/Modules/FindGTest.cmake b/Modules/FindGTest.cmake +index e015a9840f..0331049594 100644 +--- a/Modules/FindGTest.cmake ++++ b/Modules/FindGTest.cmake +@@ -7,10 +7,23 @@ FindGTest + + Locate the Google C++ Testing Framework. + ++.. versionadded:: 3.20 ++ Upstream ``GTestConfig.cmake`` is used if possible. ++ + Imported targets + ^^^^^^^^^^^^^^^^ + +-This module defines the following :prop_tgt:`IMPORTED` targets: ++ This module defines the following :prop_tgt:`IMPORTED` targets: ++ ++``GTest::gtest`` ++ The Google Test ``gtest`` library, if found; adds Thread::Thread ++ automatically ++``GTest::gtest_main`` ++ The Google Test ``gtest_main`` library, if found ++ ++.. deprecated:: 3.20 ++ For backwards compatibility, this module defines additionally the ++ following deprecated :prop_tgt:`IMPORTED` targets (available since 3.5): + + ``GTest::GTest`` + The Google Test ``gtest`` library, if found; adds Thread::Thread +@@ -18,7 +31,6 @@ This module defines the following :prop_tgt:`IMPORTED` targets: + ``GTest::Main`` + The Google Test ``gtest_main`` library, if found + +- + Result variables + ^^^^^^^^^^^^^^^^ + +@@ -146,8 +158,42 @@ function(__gtest_import_library _target _var _config) + endif() + endfunction() + ++function(__gtest_define_backwards_compatible_library_targets) ++ set(GTEST_BOTH_LIBRARIES ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES} PARENT_SCOPE) ++ ++ # Add targets mapping the same library names as defined in ++ # older versions of CMake's FindGTest ++ if(NOT TARGET GTest::GTest) ++ add_library(GTest::GTest INTERFACE IMPORTED) ++ target_link_libraries(GTest::GTest INTERFACE GTest::gtest) ++ endif() ++ if(NOT TARGET GTest::Main) ++ add_library(GTest::Main INTERFACE IMPORTED) ++ target_link_libraries(GTest::Main INTERFACE GTest::gtest_main) ++ endif() ++endfunction() ++ + # + ++include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) ++ ++# first specifically look for the CMake version of GTest ++find_package(GTest QUIET NO_MODULE) ++ ++# if we found the GTest cmake package then we are done, and ++# can print what we found and return. ++if(GTest_FOUND) ++ set(GTEST_FOUND ${GTest_FOUND}) ++ FIND_PACKAGE_HANDLE_STANDARD_ARGS(GTest HANDLE_COMPONENTS CONFIG_MODE) ++ ++ set(GTEST_LIBRARIES GTest::gtest) ++ set(GTEST_MAIN_LIBRARIES GTest::gtest_main) ++ ++ __gtest_define_backwards_compatible_library_targets() ++ ++ return() ++endif() ++ + if(NOT DEFINED GTEST_MSVC_SEARCH) + set(GTEST_MSVC_SEARCH MD) + endif() +@@ -194,50 +240,97 @@ if(MSVC AND GTEST_MSVC_SEARCH STREQUAL "MD") + __gtest_find_library(GTEST_LIBRARY_DEBUG gtest-mdd gtestd) + __gtest_find_library(GTEST_MAIN_LIBRARY gtest_main-md gtest_main) + __gtest_find_library(GTEST_MAIN_LIBRARY_DEBUG gtest_main-mdd gtest_maind) ++ __gtest_find_library(GMOCK_LIBRARY gmock-md gmock) ++ __gtest_find_library(GMOCK_LIBRARY_DEBUG gmock-mdd gmockd) ++ __gtest_find_library(GMOCK_MAIN_LIBRARY gmock_main-md gmock_main) ++ __gtest_find_library(GMOCK_MAIN_LIBRARY_DEBUG gmock_main-mdd gmock_maind) + else() + __gtest_find_library(GTEST_LIBRARY gtest) + __gtest_find_library(GTEST_LIBRARY_DEBUG gtestd) + __gtest_find_library(GTEST_MAIN_LIBRARY gtest_main) + __gtest_find_library(GTEST_MAIN_LIBRARY_DEBUG gtest_maind) ++ __gtest_find_library(GMOCK_LIBRARY gmock) ++ __gtest_find_library(GMOCK_LIBRARY_DEBUG gmockd) ++ __gtest_find_library(GMOCK_MAIN_LIBRARY gmock_main) ++ __gtest_find_library(GMOCK_MAIN_LIBRARY_DEBUG gmock_maind) + endif() + +-include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(GTest DEFAULT_MSG GTEST_LIBRARY GTEST_INCLUDE_DIR GTEST_MAIN_LIBRARY) + +-if(GTEST_FOUND) ++if(GMOCK_LIBRARY AND GMOCK_MAIN_LIBRARY) ++ set(GMock_FOUND True) ++else() ++ set(GMock_FOUND False) ++endif() ++ ++if(GTest_FOUND) + set(GTEST_INCLUDE_DIRS ${GTEST_INCLUDE_DIR}) + __gtest_append_debugs(GTEST_LIBRARIES GTEST_LIBRARY) + __gtest_append_debugs(GTEST_MAIN_LIBRARIES GTEST_MAIN_LIBRARY) +- set(GTEST_BOTH_LIBRARIES ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES}) + + find_package(Threads QUIET) + +- if(NOT TARGET GTest::GTest) ++ if(NOT TARGET GTest::gtest) + __gtest_determine_library_type(GTEST_LIBRARY) +- add_library(GTest::GTest ${GTEST_LIBRARY_TYPE} IMPORTED) ++ add_library(GTest::gtest ${GTEST_LIBRARY_TYPE} IMPORTED) + if(TARGET Threads::Threads) +- set_target_properties(GTest::GTest PROPERTIES ++ set_target_properties(GTest::gtest PROPERTIES + INTERFACE_LINK_LIBRARIES Threads::Threads) + endif() + if(GTEST_LIBRARY_TYPE STREQUAL "SHARED") +- set_target_properties(GTest::GTest PROPERTIES ++ set_target_properties(GTest::gtest PROPERTIES + INTERFACE_COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1") + endif() + if(GTEST_INCLUDE_DIRS) +- set_target_properties(GTest::GTest PROPERTIES ++ set_target_properties(GTest::gtest PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${GTEST_INCLUDE_DIRS}") + endif() +- __gtest_import_library(GTest::GTest GTEST_LIBRARY "") +- __gtest_import_library(GTest::GTest GTEST_LIBRARY "RELEASE") +- __gtest_import_library(GTest::GTest GTEST_LIBRARY "DEBUG") ++ __gtest_import_library(GTest::gtest GTEST_LIBRARY "") ++ __gtest_import_library(GTest::gtest GTEST_LIBRARY "RELEASE") ++ __gtest_import_library(GTest::gtest GTEST_LIBRARY "DEBUG") + endif() +- if(NOT TARGET GTest::Main) ++ if(NOT TARGET GTest::gtest_main) + __gtest_determine_library_type(GTEST_MAIN_LIBRARY) +- add_library(GTest::Main ${GTEST_MAIN_LIBRARY_TYPE} IMPORTED) +- set_target_properties(GTest::Main PROPERTIES +- INTERFACE_LINK_LIBRARIES "GTest::GTest") +- __gtest_import_library(GTest::Main GTEST_MAIN_LIBRARY "") +- __gtest_import_library(GTest::Main GTEST_MAIN_LIBRARY "RELEASE") +- __gtest_import_library(GTest::Main GTEST_MAIN_LIBRARY "DEBUG") ++ add_library(GTest::gtest_main ${GTEST_MAIN_LIBRARY_TYPE} IMPORTED) ++ set_target_properties(GTest::gtest_main PROPERTIES ++ INTERFACE_LINK_LIBRARIES "GTest::gtest") ++ __gtest_import_library(GTest::gtest_main GTEST_MAIN_LIBRARY "") ++ __gtest_import_library(GTest::gtest_main GTEST_MAIN_LIBRARY "RELEASE") ++ __gtest_import_library(GTest::gtest_main GTEST_MAIN_LIBRARY "DEBUG") ++ endif() ++ ++ __gtest_define_backwards_compatible_library_targets() ++endif() ++ ++if(GMock_FOUND) ++ if(NOT TARGET GTest::gmock) ++ __gtest_determine_library_type(GMOCK_LIBRARY) ++ add_library(GTest::gmock ${GMOCK_LIBRARY_TYPE} IMPORTED) ++ set(_gmock_link_libraries "GTest::gtest") ++ if(TARGET Threads::Threads) ++ list(APPEND _gmock_link_libraries Threads::Threads) ++ endif() ++ set_target_properties(GTest::gmock PROPERTIES ++ INTERFACE_LINK_LIBRARIES "${_gmock_link_libraries}") ++ if(GMOCK_LIBRARY_TYPE STREQUAL "SHARED") ++ set_target_properties(GTest::gmock PROPERTIES ++ INTERFACE_COMPILE_DEFINITIONS "GMOCK_LINKED_AS_SHARED_LIBRARY=1") ++ endif() ++ if(GTEST_INCLUDE_DIRS) ++ set_target_properties(GTest::gmock PROPERTIES ++ INTERFACE_INCLUDE_DIRECTORIES "${GTEST_INCLUDE_DIRS}") ++ endif() ++ __gtest_import_library(GTest::gmock GMOCK_LIBRARY "") ++ __gtest_import_library(GTest::gmock GMOCK_LIBRARY "RELEASE") ++ __gtest_import_library(GTest::gmock GMOCK_LIBRARY "DEBUG") ++ endif() ++ if(NOT TARGET GTest::gmock_main) ++ __gtest_determine_library_type(GMOCK_MAIN_LIBRARY) ++ add_library(GTest::gmock_main ${GMOCK_MAIN_LIBRARY_TYPE} IMPORTED) ++ set_target_properties(GTest::gmock_main PROPERTIES ++ INTERFACE_LINK_LIBRARIES "GTest::gmock") ++ __gtest_import_library(GTest::gmock_main GMOCK_MAIN_LIBRARY "") ++ __gtest_import_library(GTest::gmock_main GMOCK_MAIN_LIBRARY "RELEASE") ++ __gtest_import_library(GTest::gmock_main GMOCK_MAIN_LIBRARY "DEBUG") + endif() + endif() +diff --git a/Tests/FindGTest/Test/CMakeLists.txt b/Tests/FindGTest/Test/CMakeLists.txt +index b65b9d28f6..7d3a378a65 100644 +--- a/Tests/FindGTest/Test/CMakeLists.txt ++++ b/Tests/FindGTest/Test/CMakeLists.txt +@@ -12,3 +12,7 @@ add_executable(test_gtest_var main.cxx) + target_include_directories(test_gtest_var PRIVATE ${GTEST_INCLUDE_DIRS}) + target_link_libraries(test_gtest_var PRIVATE ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) + add_test(NAME test_gtest_var COMMAND test_gtest_var) ++ ++add_executable(test_gmock_tgt main.cxx) ++target_link_libraries(test_gmock_tgt GTest::gmock_main) ++add_test(NAME test_gmock_tgt COMMAND test_gmock_tgt) +-- +2.17.1 + diff --git a/meta/recipes-devtools/cmake/cmake/OEToolchainConfig.cmake b/meta/recipes-devtools/cmake/cmake/OEToolchainConfig.cmake index 398069eef2..870009c2ba 100644 --- a/meta/recipes-devtools/cmake/cmake/OEToolchainConfig.cmake +++ b/meta/recipes-devtools/cmake/cmake/OEToolchainConfig.cmake @@ -2,7 +2,6 @@ set( CMAKE_SYSTEM_NAME Linux ) set( CMAKE_C_FLAGS $ENV{CFLAGS} CACHE STRING "" FORCE ) set( CMAKE_CXX_FLAGS $ENV{CXXFLAGS} CACHE STRING "" FORCE ) set( CMAKE_ASM_FLAGS ${CMAKE_C_FLAGS} CACHE STRING "" FORCE ) -set( CMAKE_LDFLAGS_FLAGS ${CMAKE_CXX_FLAGS} CACHE STRING "" FORCE ) set( CMAKE_SYSROOT $ENV{OECORE_TARGET_SYSROOT} ) set( CMAKE_FIND_ROOT_PATH $ENV{OECORE_TARGET_SYSROOT} ) @@ -13,13 +12,13 @@ set( CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY ) set(CMAKE_FIND_LIBRARY_CUSTOM_LIB_SUFFIX "$ENV{OE_CMAKE_FIND_LIBRARY_CUSTOM_LIB_SUFFIX}") -# Set CMAKE_SYSTEM_PROCESSOR from the sysroot name (assuming processor-distro-os). -if ($ENV{SDKTARGETSYSROOT} MATCHES "/sysroots/([a-zA-Z0-9_-]+)-.+-.+") - set(CMAKE_SYSTEM_PROCESSOR ${CMAKE_MATCH_1}) -endif() +set( CMAKE_SYSTEM_PROCESSOR $ENV{OECORE_TARGET_ARCH} ) # Include the toolchain configuration subscripts file( GLOB toolchain_config_files "${CMAKE_TOOLCHAIN_FILE}.d/*.cmake" ) foreach(config ${toolchain_config_files}) include(${config}) endforeach() + +unset(CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES) +unset(CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES) diff --git a/meta/recipes-devtools/createrepo-c/createrepo-c_0.15.7.bb b/meta/recipes-devtools/createrepo-c/createrepo-c_0.15.7.bb index c6a53ffece..3c403a4077 100644 --- a/meta/recipes-devtools/createrepo-c/createrepo-c_0.15.7.bb +++ b/meta/recipes-devtools/createrepo-c/createrepo-c_0.15.7.bb @@ -4,7 +4,7 @@ HOMEPAGE = "https://github.com/rpm-software-management/createrepo_c/wiki" LICENSE = "GPLv2" LIC_FILES_CHKSUM = "file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263" -SRC_URI = "git://github.com/rpm-software-management/createrepo_c \ +SRC_URI = "git://github.com/rpm-software-management/createrepo_c;branch=master;protocol=https \ file://0001-Do-not-set-PYTHON_INSTALL_DIR-by-running-python.patch \ " diff --git a/meta/recipes-devtools/distcc/distcc_3.3.3.bb b/meta/recipes-devtools/distcc/distcc_3.3.3.bb index 9a36cfe525..2a74a068f1 100644 --- a/meta/recipes-devtools/distcc/distcc_3.3.3.bb +++ b/meta/recipes-devtools/distcc/distcc_3.3.3.bb @@ -15,7 +15,7 @@ PACKAGECONFIG[popt] = "--without-included-popt,--with-included-popt,popt" RRECOMMENDS_${PN}-server = "avahi-daemon" -SRC_URI = "git://github.com/distcc/distcc.git \ +SRC_URI = "git://github.com/distcc/distcc.git;branch=master;protocol=https \ file://fix-gnome.patch \ file://separatebuilddir.patch \ file://default \ diff --git a/meta/recipes-devtools/dmidecode/dmidecode/CVE-2023-30630-dependent_p1.patch b/meta/recipes-devtools/dmidecode/dmidecode/CVE-2023-30630-dependent_p1.patch new file mode 100644 index 0000000000..f1d449acbe --- /dev/null +++ b/meta/recipes-devtools/dmidecode/dmidecode/CVE-2023-30630-dependent_p1.patch @@ -0,0 +1,236 @@ +From 24def311c6168d0dfb7c5f0f183b72b709c49265 Mon Sep 17 00:00:00 2001 +From: Jean Delvare <jdelvare@suse.de> +Date: Mon, 20 Feb 2023 14:53:21 +0100 +Subject: [PATCH] dmidecode: Split table fetching from decoding + +Clean up function dmi_table so that it does only one thing: +* dmi_table() is renamed to dmi_table_get(). It now retrieves the + DMI table, but does not process it any longer. +* Decoding or dumping the table is now done in smbios3_decode(), + smbios_decode() and legacy_decode(). +No functional change. + +A side effect of this change is that writing the header and body of +dump files is now done in a single location. This is required to +further consolidate the writing of dump files. + +CVE-ID: CVE-2023-30630 +Upstream-Status: Backport [https://git.savannah.nongnu.org/cgit/dmidecode.git/commit/?id=39b2dd7b6ab7] + +Backport Changes: +- In the file dmidecode.c, the commit [dd593d2] in v3.3 introduces + pr_info(). This is backported to printf() as per v3.2. + +Signed-off-by: Jean Delvare <jdelvare@suse.de> +Reviewed-by: Jerry Hoemann <jerry.hoemann@hpe.com> +(cherry picked from commit 39b2dd7b6ab719b920e96ed832cfb4bdd664e808) +Signed-off-by: Dhairya Nagodra <dnagodra@cisco.com> +--- + dmidecode.c | 86 ++++++++++++++++++++++++++++++++++++++--------------- + 1 file changed, 62 insertions(+), 24 deletions(-) + +diff --git a/dmidecode.c b/dmidecode.c +index a3e9d6c..d6eedd1 100644 +--- a/dmidecode.c ++++ b/dmidecode.c +@@ -5211,8 +5211,9 @@ static void dmi_table_decode(u8 *buf, u32 len, u16 num, u16 ver, u32 flags) + } + } + +-static void dmi_table(off_t base, u32 len, u16 num, u32 ver, const char *devmem, +- u32 flags) ++/* Allocates a buffer for the table, must be freed by the caller */ ++static u8 *dmi_table_get(off_t base, u32 *len, u16 num, u32 ver, ++ const char *devmem, u32 flags) + { + u8 *buf; + +@@ -5231,7 +5232,7 @@ static void dmi_table(off_t base, u32 len, u16 num, u32 ver, const char *devmem, + { + if (num) + printf("%u structures occupying %u bytes.\n", +- num, len); ++ num, *len); + if (!(opt.flags & FLAG_FROM_DUMP)) + printf("Table at 0x%08llX.\n", + (unsigned long long)base); +@@ -5249,19 +5250,19 @@ static void dmi_table(off_t base, u32 len, u16 num, u32 ver, const char *devmem, + * would be the result of the kernel truncating the table on + * parse error. + */ +- size_t size = len; ++ size_t size = *len; + buf = read_file(flags & FLAG_NO_FILE_OFFSET ? 0 : base, + &size, devmem); +- if (!(opt.flags & FLAG_QUIET) && num && size != (size_t)len) ++ if (!(opt.flags & FLAG_QUIET) && num && size != (size_t)*len) + { + fprintf(stderr, "Wrong DMI structures length: %u bytes " + "announced, only %lu bytes available.\n", +- len, (unsigned long)size); ++ *len, (unsigned long)size); + } +- len = size; ++ *len = size; + } + else +- buf = mem_chunk(base, len, devmem); ++ buf = mem_chunk(base, *len, devmem); + + if (buf == NULL) + { +@@ -5271,15 +5272,9 @@ static void dmi_table(off_t base, u32 len, u16 num, u32 ver, const char *devmem, + fprintf(stderr, + "Try compiling dmidecode with -DUSE_MMAP.\n"); + #endif +- return; + } + +- if (opt.flags & FLAG_DUMP_BIN) +- dmi_table_dump(buf, len); +- else +- dmi_table_decode(buf, len, num, ver >> 8, flags); +- +- free(buf); ++ return buf; + } + + +@@ -5314,8 +5309,9 @@ static void overwrite_smbios3_address(u8 *buf) + + static int smbios3_decode(u8 *buf, const char *devmem, u32 flags) + { +- u32 ver; ++ u32 ver, len; + u64 offset; ++ u8 *table; + + /* Don't let checksum run beyond the buffer */ + if (buf[0x06] > 0x20) +@@ -5341,8 +5337,12 @@ static int smbios3_decode(u8 *buf, const char *devmem, u32 flags) + return 0; + } + +- dmi_table(((off_t)offset.h << 32) | offset.l, +- DWORD(buf + 0x0C), 0, ver, devmem, flags | FLAG_STOP_AT_EOT); ++ /* Maximum length, may get trimmed */ ++ len = DWORD(buf + 0x0C); ++ table = dmi_table_get(((off_t)offset.h << 32) | offset.l, &len, 0, ver, ++ devmem, flags | FLAG_STOP_AT_EOT); ++ if (table == NULL) ++ return 1; + + if (opt.flags & FLAG_DUMP_BIN) + { +@@ -5351,18 +5351,28 @@ static int smbios3_decode(u8 *buf, const char *devmem, u32 flags) + memcpy(crafted, buf, 32); + overwrite_smbios3_address(crafted); + ++ dmi_table_dump(table, len); + if (!(opt.flags & FLAG_QUIET)) + printf("# Writing %d bytes to %s.\n", crafted[0x06], + opt.dumpfile); + write_dump(0, crafted[0x06], crafted, opt.dumpfile, 1); + } ++ else ++ { ++ dmi_table_decode(table, len, 0, ver >> 8, ++ flags | FLAG_STOP_AT_EOT); ++ } ++ ++ free(table); + + return 1; + } + + static int smbios_decode(u8 *buf, const char *devmem, u32 flags) + { +- u16 ver; ++ u16 ver, num; ++ u32 len; ++ u8 *table; + + /* Don't let checksum run beyond the buffer */ + if (buf[0x05] > 0x20) +@@ -5402,8 +5412,13 @@ static int smbios_decode(u8 *buf, const char *devmem, u32 flags) + printf("SMBIOS %u.%u present.\n", + ver >> 8, ver & 0xFF); + +- dmi_table(DWORD(buf + 0x18), WORD(buf + 0x16), WORD(buf + 0x1C), +- ver << 8, devmem, flags); ++ /* Maximum length, may get trimmed */ ++ len = WORD(buf + 0x16); ++ num = WORD(buf + 0x1C); ++ table = dmi_table_get(DWORD(buf + 0x18), &len, num, ver << 8, ++ devmem, flags); ++ if (table == NULL) ++ return 1; + + if (opt.flags & FLAG_DUMP_BIN) + { +@@ -5412,27 +5427,43 @@ static int smbios_decode(u8 *buf, const char *devmem, u32 flags) + memcpy(crafted, buf, 32); + overwrite_dmi_address(crafted + 0x10); + ++ dmi_table_dump(table, len); + if (!(opt.flags & FLAG_QUIET)) + printf("# Writing %d bytes to %s.\n", crafted[0x05], + opt.dumpfile); + write_dump(0, crafted[0x05], crafted, opt.dumpfile, 1); + } ++ else ++ { ++ dmi_table_decode(table, len, num, ver, flags); ++ } ++ ++ free(table); + + return 1; + } + + static int legacy_decode(u8 *buf, const char *devmem, u32 flags) + { ++ u16 ver, num; ++ u32 len; ++ u8 *table; ++ + if (!checksum(buf, 0x0F)) + return 0; + ++ ver = ((buf[0x0E] & 0xF0) << 4) + (buf[0x0E] & 0x0F); + if (!(opt.flags & FLAG_QUIET)) + printf("Legacy DMI %u.%u present.\n", + buf[0x0E] >> 4, buf[0x0E] & 0x0F); + +- dmi_table(DWORD(buf + 0x08), WORD(buf + 0x06), WORD(buf + 0x0C), +- ((buf[0x0E] & 0xF0) << 12) + ((buf[0x0E] & 0x0F) << 8), +- devmem, flags); ++ /* Maximum length, may get trimmed */ ++ len = WORD(buf + 0x06); ++ num = WORD(buf + 0x0C); ++ table = dmi_table_get(DWORD(buf + 0x08), &len, num, ver << 8, ++ devmem, flags); ++ if (table == NULL) ++ return 1; + + if (opt.flags & FLAG_DUMP_BIN) + { +@@ -5441,11 +5472,18 @@ static int legacy_decode(u8 *buf, const char *devmem, u32 flags) + memcpy(crafted, buf, 16); + overwrite_dmi_address(crafted); + ++ dmi_table_dump(table, len); + if (!(opt.flags & FLAG_QUIET)) + printf("# Writing %d bytes to %s.\n", 0x0F, + opt.dumpfile); + write_dump(0, 0x0F, crafted, opt.dumpfile, 1); + } ++ else ++ { ++ dmi_table_decode(table, len, num, ver, flags); ++ } ++ ++ free(table); + + return 1; + } diff --git a/meta/recipes-devtools/dmidecode/dmidecode/CVE-2023-30630-dependent_p2.patch b/meta/recipes-devtools/dmidecode/dmidecode/CVE-2023-30630-dependent_p2.patch new file mode 100644 index 0000000000..353c2553f5 --- /dev/null +++ b/meta/recipes-devtools/dmidecode/dmidecode/CVE-2023-30630-dependent_p2.patch @@ -0,0 +1,198 @@ +From 58e8a07b1aef0e53af1642b30248255e53e42790 Mon Sep 17 00:00:00 2001 +From: Jean Delvare <jdelvare@suse.de> +Date: Mon, 20 Feb 2023 14:53:25 +0100 +Subject: [PATCH] dmidecode: Write the whole dump file at once + +When option --dump-bin is used, write the whole dump file at once, +instead of opening and closing the file separately for the table +and then for the entry point. + +As the file writing function is no longer generic, it gets moved +from util.c to dmidecode.c. + +One minor functional change resulting from the new implementation is +that the entry point is written first now, so the messages printed +are swapped. + +CVE: CVE-2023-30630 +Upstream-Status: Backport [https://git.savannah.nongnu.org/cgit/dmidecode.git/commit/?id=d8cfbc808f38] + +Backport Changes: +- In the file dmidecode.c, the commit [2241f1d] in v3.3 introduces + pr_info(). This is backported to printf() as per v3.2. + +Signed-off-by: Jean Delvare <jdelvare@suse.de> +Reviewed-by: Jerry Hoemann <jerry.hoemann@hpe.com> +(cherry picked from commit d8cfbc808f387e87091c25e7d5b8c2bb348bb206) +Signed-off-by: Dhairya Nagodra <dnagodra@cisco.com> + +--- + dmidecode.c | 69 +++++++++++++++++++++++++++++++++++++++-------------- + util.c | 40 ------------------------------- + util.h | 1 - + 3 files changed, 51 insertions(+), 59 deletions(-) + +diff --git a/dmidecode.c b/dmidecode.c +index d6eedd1..b91e53b 100644 +--- a/dmidecode.c ++++ b/dmidecode.c +@@ -5094,11 +5094,56 @@ static void dmi_table_string(const struct dmi_header *h, const u8 *data, u16 ver + } + } + +-static void dmi_table_dump(const u8 *buf, u32 len) ++static int dmi_table_dump(const u8 *ep, u32 ep_len, const u8 *table, ++ u32 table_len) + { ++ FILE *f; ++ ++ f = fopen(opt.dumpfile, "wb"); ++ if (!f) ++ { ++ fprintf(stderr, "%s: ", opt.dumpfile); ++ perror("fopen"); ++ return -1; ++ } ++ ++ if (!(opt.flags & FLAG_QUIET)) ++ printf("# Writing %d bytes to %s.\n", ep_len, opt.dumpfile); ++ if (fwrite(ep, ep_len, 1, f) != 1) ++ { ++ fprintf(stderr, "%s: ", opt.dumpfile); ++ perror("fwrite"); ++ goto err_close; ++ } ++ ++ if (fseek(f, 32, SEEK_SET) != 0) ++ { ++ fprintf(stderr, "%s: ", opt.dumpfile); ++ perror("fseek"); ++ goto err_close; ++ } ++ + if (!(opt.flags & FLAG_QUIET)) +- printf("# Writing %d bytes to %s.\n", len, opt.dumpfile); +- write_dump(32, len, buf, opt.dumpfile, 0); ++ printf("# Writing %d bytes to %s.\n", table_len, opt.dumpfile); ++ if (fwrite(table, table_len, 1, f) != 1) ++ { ++ fprintf(stderr, "%s: ", opt.dumpfile); ++ perror("fwrite"); ++ goto err_close; ++ } ++ ++ if (fclose(f)) ++ { ++ fprintf(stderr, "%s: ", opt.dumpfile); ++ perror("fclose"); ++ return -1; ++ } ++ ++ return 0; ++ ++err_close: ++ fclose(f); ++ return -1; + } + + static void dmi_table_decode(u8 *buf, u32 len, u16 num, u16 ver, u32 flags) +@@ -5351,11 +5396,7 @@ static int smbios3_decode(u8 *buf, const char *devmem, u32 flags) + memcpy(crafted, buf, 32); + overwrite_smbios3_address(crafted); + +- dmi_table_dump(table, len); +- if (!(opt.flags & FLAG_QUIET)) +- printf("# Writing %d bytes to %s.\n", crafted[0x06], +- opt.dumpfile); +- write_dump(0, crafted[0x06], crafted, opt.dumpfile, 1); ++ dmi_table_dump(crafted, crafted[0x06], table, len); + } + else + { +@@ -5427,11 +5468,7 @@ static int smbios_decode(u8 *buf, const char *devmem, u32 flags) + memcpy(crafted, buf, 32); + overwrite_dmi_address(crafted + 0x10); + +- dmi_table_dump(table, len); +- if (!(opt.flags & FLAG_QUIET)) +- printf("# Writing %d bytes to %s.\n", crafted[0x05], +- opt.dumpfile); +- write_dump(0, crafted[0x05], crafted, opt.dumpfile, 1); ++ dmi_table_dump(crafted, crafted[0x05], table, len); + } + else + { +@@ -5472,11 +5509,7 @@ static int legacy_decode(u8 *buf, const char *devmem, u32 flags) + memcpy(crafted, buf, 16); + overwrite_dmi_address(crafted); + +- dmi_table_dump(table, len); +- if (!(opt.flags & FLAG_QUIET)) +- printf("# Writing %d bytes to %s.\n", 0x0F, +- opt.dumpfile); +- write_dump(0, 0x0F, crafted, opt.dumpfile, 1); ++ dmi_table_dump(crafted, 0x0F, table, len); + } + else + { +diff --git a/util.c b/util.c +index eeffdae..2e1931c 100644 +--- a/util.c ++++ b/util.c +@@ -247,46 +247,6 @@ out: + return p; + } + +-int write_dump(size_t base, size_t len, const void *data, const char *dumpfile, int add) +-{ +- FILE *f; +- +- f = fopen(dumpfile, add ? "r+b" : "wb"); +- if (!f) +- { +- fprintf(stderr, "%s: ", dumpfile); +- perror("fopen"); +- return -1; +- } +- +- if (fseek(f, base, SEEK_SET) != 0) +- { +- fprintf(stderr, "%s: ", dumpfile); +- perror("fseek"); +- goto err_close; +- } +- +- if (fwrite(data, len, 1, f) != 1) +- { +- fprintf(stderr, "%s: ", dumpfile); +- perror("fwrite"); +- goto err_close; +- } +- +- if (fclose(f)) +- { +- fprintf(stderr, "%s: ", dumpfile); +- perror("fclose"); +- return -1; +- } +- +- return 0; +- +-err_close: +- fclose(f); +- return -1; +-} +- + /* Returns end - start + 1, assuming start < end */ + u64 u64_range(u64 start, u64 end) + { +diff --git a/util.h b/util.h +index 3094cf8..ef24eb9 100644 +--- a/util.h ++++ b/util.h +@@ -27,5 +27,4 @@ + int checksum(const u8 *buf, size_t len); + void *read_file(off_t base, size_t *len, const char *filename); + void *mem_chunk(off_t base, size_t len, const char *devmem); +-int write_dump(size_t base, size_t len, const void *data, const char *dumpfile, int add); + u64 u64_range(u64 start, u64 end); diff --git a/meta/recipes-devtools/dmidecode/dmidecode/CVE-2023-30630.patch b/meta/recipes-devtools/dmidecode/dmidecode/CVE-2023-30630.patch new file mode 100644 index 0000000000..bf4d060c8c --- /dev/null +++ b/meta/recipes-devtools/dmidecode/dmidecode/CVE-2023-30630.patch @@ -0,0 +1,62 @@ +From b7dacccff32294ea522df32a9391d0218e7600ea Mon Sep 17 00:00:00 2001 +From: Jean Delvare <jdelvare@suse.de> +Date: Mon, 20 Feb 2023 14:53:31 +0100 +Subject: [PATCH] dmidecode: Do not let --dump-bin overwrite an existing file + +Make sure that the file passed to option --dump-bin does not already +exist. In practice, it is rather unlikely that an honest user would +want to overwrite an existing dump file, while this possibility +could be used by a rogue user to corrupt a system file. + +CVE: CVE-2023-30630 +Upstream-Status: Backport [https://git.savannah.nongnu.org/cgit/dmidecode.git/commit/?id=6ca381c1247c] + +Backport Changes: +- Ignored changes in man/dmidecode.8 file. + +Signed-off-by: Jean Delvare <jdelvare@suse.de> +Reviewed-by: Jerry Hoemann <jerry.hoemann@hpe.com> +(cherry picked from commit 6ca381c1247c81f74e1ca4e7706f70bdda72e6f2) +Signed-off-by: Dhairya Nagodra <dnagodra@cisco.com> + +--- + dmidecode.c | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/dmidecode.c b/dmidecode.c +index b91e53b..846d9a1 100644 +--- a/dmidecode.c ++++ b/dmidecode.c +@@ -60,6 +60,7 @@ + * https://www.dmtf.org/sites/default/files/DSP0270_1.0.1.pdf + */ + ++#include <fcntl.h> + #include <stdio.h> + #include <string.h> + #include <strings.h> +@@ -5097,13 +5098,22 @@ static void dmi_table_string(const struct dmi_header *h, const u8 *data, u16 ver + static int dmi_table_dump(const u8 *ep, u32 ep_len, const u8 *table, + u32 table_len) + { ++ int fd; + FILE *f; + +- f = fopen(opt.dumpfile, "wb"); ++ fd = open(opt.dumpfile, O_WRONLY|O_CREAT|O_EXCL, 0666); ++ if (fd == -1) ++ { ++ fprintf(stderr, "%s: ", opt.dumpfile); ++ perror("open"); ++ return -1; ++ } ++ ++ f = fdopen(fd, "wb"); + if (!f) + { + fprintf(stderr, "%s: ", opt.dumpfile); +- perror("fopen"); ++ perror("fdopen"); + return -1; + } + diff --git a/meta/recipes-devtools/dmidecode/dmidecode_3.2.bb b/meta/recipes-devtools/dmidecode/dmidecode_3.2.bb index 8caffb5cc3..1e7c38dc8a 100644 --- a/meta/recipes-devtools/dmidecode/dmidecode_3.2.bb +++ b/meta/recipes-devtools/dmidecode/dmidecode_3.2.bb @@ -6,6 +6,9 @@ LIC_FILES_CHKSUM = "file://LICENSE;md5=b234ee4d69f5fce4486a80fdaf4a4263" SRC_URI = "${SAVANNAH_NONGNU_MIRROR}/dmidecode/${BP}.tar.xz \ file://0001-Committing-changes-from-do_unpack_extra.patch \ + file://CVE-2023-30630-dependent_p1.patch \ + file://CVE-2023-30630-dependent_p2.patch \ + file://CVE-2023-30630.patch \ " COMPATIBLE_HOST = "(i.86|x86_64|aarch64|arm|powerpc|powerpc64).*-linux" diff --git a/meta/recipes-devtools/dnf/dnf/0040-Keep-installed-packages-in-upgrade-job-RhBug-1728252.patch b/meta/recipes-devtools/dnf/dnf/0040-Keep-installed-packages-in-upgrade-job-RhBug-1728252.patch new file mode 100644 index 0000000000..57c2375a54 --- /dev/null +++ b/meta/recipes-devtools/dnf/dnf/0040-Keep-installed-packages-in-upgrade-job-RhBug-1728252.patch @@ -0,0 +1,60 @@ +From c88a77198c0156e425c2725f30e481207de5162f Mon Sep 17 00:00:00 2001 +From: Jaroslav Mracek <jmracek@redhat.com> +Date: Tue, 3 Sep 2019 11:01:51 +0200 +Subject: [PATCH] Keep installed packages in upgrade job + (RhBug:1728252,1644241,1741381) + +In combination with marking of job as TARGETED it prevents from +reinstalling of modified packages with same NEVRA. + +https://bugzilla.redhat.com/show_bug.cgi?id=1728252 +https://bugzilla.redhat.com/show_bug.cgi?id=1644241 +https://bugzilla.redhat.com/show_bug.cgi?id=1741381 + +Closes: #1474 +Approved by: m-blaha + + +Backport to fix bug in dnf in oe-core +from https://github.com/rpm-software-management/dnf + +Removed spec file portion of patch + +Upstream-Status: Backport +Signed-off-by: Jate Sujjavanich <jatedev@gmail.com> +--- + dnf.spec | 4 ++-- + dnf/base.py | 3 --- + dnf/module/module_base.py | 2 +- + 3 files changed, 3 insertions(+), 6 deletions(-) + +diff --git a/dnf/base.py b/dnf/base.py +index b2ced61..628c154 100644 +--- a/dnf/base.py ++++ b/dnf/base.py +@@ -1968,9 +1968,6 @@ class Base(object): + obsoletes=q.installed().union(q.upgrades())) + # add obsoletes into transaction + q = q.union(obsoletes) +- # provide only available packages to solver otherwise selection of available +- # possibilities will be ignored +- q = q.available() + if reponame is not None: + q.filterm(reponame=reponame) + q = self._merge_update_filters(q, pkg_spec=pkg_spec) +diff --git a/dnf/module/module_base.py b/dnf/module/module_base.py +index 976d730..ce70f63 100644 +--- a/dnf/module/module_base.py ++++ b/dnf/module/module_base.py +@@ -214,7 +214,7 @@ class ModuleBase(object): + + if not upgrade_package_set: + logger.error(_("Unable to match profile in argument {}").format(spec)) +- query = self.base.sack.query().available().filterm(name=upgrade_package_set) ++ query = self.base.sack.query().filterm(name=upgrade_package_set) + if query: + sltr = dnf.selector.Selector(self.base.sack) + sltr.set(pkg=query) +-- +2.7.4 + diff --git a/meta/recipes-devtools/dnf/dnf_4.2.2.bb b/meta/recipes-devtools/dnf/dnf_4.2.2.bb index 7831e1ac5a..6b6b233d6d 100644 --- a/meta/recipes-devtools/dnf/dnf_4.2.2.bb +++ b/meta/recipes-devtools/dnf/dnf_4.2.2.bb @@ -8,7 +8,7 @@ LIC_FILES_CHKSUM = "file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263 \ file://PACKAGE-LICENSING;md5=4a0548e303dbc77f067335b4d688e745 \ " -SRC_URI = "git://github.com/rpm-software-management/dnf.git \ +SRC_URI = "git://github.com/rpm-software-management/dnf.git;branch=master;protocol=https \ file://0001-Corretly-install-tmpfiles.d-configuration.patch \ file://0001-Do-not-hardcode-etc-and-systemd-unit-directories.patch \ file://0005-Do-not-prepend-installroot-to-logdir.patch \ @@ -16,6 +16,7 @@ SRC_URI = "git://github.com/rpm-software-management/dnf.git \ file://0030-Run-python-scripts-using-env.patch \ file://Fix-SyntaxWarning.patch \ file://0001-set-python-path-for-completion_helper.patch \ + file://0040-Keep-installed-packages-in-upgrade-job-RhBug-1728252.patch \ " SRCREV = "9947306a55271b8b7c9e2b6e3b7d582885b6045d" diff --git a/meta/recipes-devtools/dpkg/dpkg_1.19.7.bb b/meta/recipes-devtools/dpkg/dpkg_1.19.8.bb index e9dec337b3..9e6e9f2464 100644 --- a/meta/recipes-devtools/dpkg/dpkg_1.19.7.bb +++ b/meta/recipes-devtools/dpkg/dpkg_1.19.8.bb @@ -18,5 +18,5 @@ SRC_URI_append_class-native = " \ file://tweak-options-require-tar-1.27.patch \ " -SRC_URI[md5sum] = "60f57c5494e6dfa177504d47bfa0e383" -SRC_URI[sha256sum] = "4c27fededf620c0aa522fff1a48577ba08144445341257502e7730f2b1a296e8" +SRC_URI[md5sum] = "9d170c8baa1aa36b09698c909f304508" +SRC_URI[sha256sum] = "2632c00b0cf0ea19ed7bd6700e6ec5faca93f0045af629d356dc03ad74ae6f10" diff --git a/meta/recipes-devtools/e2fsprogs/e2fsprogs.inc b/meta/recipes-devtools/e2fsprogs/e2fsprogs.inc index 009f5ed807..57e4665a34 100644 --- a/meta/recipes-devtools/e2fsprogs/e2fsprogs.inc +++ b/meta/recipes-devtools/e2fsprogs/e2fsprogs.inc @@ -3,7 +3,7 @@ DESCRIPTION = "The Ext2 Filesystem Utilities (e2fsprogs) contain all of the stan fixing, configuring , and debugging ext2 filesystems." HOMEPAGE = "http://e2fsprogs.sourceforge.net/" -LICENSE = "GPLv2 & LGPLv2 & BSD & MIT" +LICENSE = "GPLv2 & LGPLv2 & BSD-3-Clause & MIT" LICENSE_e2fsprogs-dumpe2fs = "GPLv2" LICENSE_e2fsprogs-e2fsck = "GPLv2" LICENSE_e2fsprogs-mke2fs = "GPLv2" @@ -19,7 +19,7 @@ LIC_FILES_CHKSUM = "file://NOTICE;md5=d50be0580c0b0a7fbc7a4830bbe6c12b \ SECTION = "base" DEPENDS = "util-linux attr" -SRC_URI = "git://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git" +SRC_URI = "git://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git;branch=master" S = "${WORKDIR}/git" inherit autotools gettext texinfo pkgconfig multilib_header update-alternatives ptest diff --git a/meta/recipes-devtools/e2fsprogs/e2fsprogs/0001-e2fsck-don-t-try-to-rehash-a-deleted-directory.patch b/meta/recipes-devtools/e2fsprogs/e2fsprogs/0001-e2fsck-don-t-try-to-rehash-a-deleted-directory.patch deleted file mode 100644 index ba4e3a3c97..0000000000 --- a/meta/recipes-devtools/e2fsprogs/e2fsprogs/0001-e2fsck-don-t-try-to-rehash-a-deleted-directory.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 71ba13755337e19c9a826dfc874562a36e1b24d3 Mon Sep 17 00:00:00 2001 -From: Theodore Ts'o <tytso@mit.edu> -Date: Thu, 19 Dec 2019 19:45:06 -0500 -Subject: [PATCH] e2fsck: don't try to rehash a deleted directory - -If directory has been deleted in pass1[bcd] processing, then we -shouldn't try to rehash the directory in pass 3a when we try to -rehash/reoptimize directories. - -Signed-off-by: Theodore Ts'o <tytso@mit.edu> - -Upstream-Status: Backport [https://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git/commit/?id=71ba13755337e19c9a826dfc874562a36e1b24d3] -Signed-off-by: Anuj Mittal <anuj.mittal@intel.com> ---- - e2fsck/pass1b.c | 4 ++++ - e2fsck/rehash.c | 2 ++ - 2 files changed, 6 insertions(+) - -diff --git a/e2fsck/pass1b.c b/e2fsck/pass1b.c -index 5693b9cf..bca701ca 100644 ---- a/e2fsck/pass1b.c -+++ b/e2fsck/pass1b.c -@@ -705,6 +705,10 @@ static void delete_file(e2fsck_t ctx, ext2_ino_t ino, - fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx); - if (ctx->inode_bad_map) - ext2fs_unmark_inode_bitmap2(ctx->inode_bad_map, ino); -+ if (ctx->inode_reg_map) -+ ext2fs_unmark_inode_bitmap2(ctx->inode_reg_map, ino); -+ ext2fs_unmark_inode_bitmap2(ctx->inode_dir_map, ino); -+ ext2fs_unmark_inode_bitmap2(ctx->inode_used_map, ino); - ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(dp->inode.i_mode)); - quota_data_sub(ctx->qctx, &dp->inode, ino, - pb.dup_blocks * fs->blocksize); -diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c -index 3dd1e941..2c908be0 100644 ---- a/e2fsck/rehash.c -+++ b/e2fsck/rehash.c -@@ -1028,6 +1028,8 @@ void e2fsck_rehash_directories(e2fsck_t ctx) - if (!ext2fs_u32_list_iterate(iter, &ino)) - break; - } -+ if (!ext2fs_test_inode_bitmap2(ctx->inode_dir_map, ino)) -+ continue; - - pctx.dir = ino; - if (first) { --- -2.24.1 - diff --git a/meta/recipes-devtools/e2fsprogs/e2fsprogs/0001-misc-create_inode.c-set-dir-s-mode-correctly.patch b/meta/recipes-devtools/e2fsprogs/e2fsprogs/0001-misc-create_inode.c-set-dir-s-mode-correctly.patch deleted file mode 100644 index fc4a540986..0000000000 --- a/meta/recipes-devtools/e2fsprogs/e2fsprogs/0001-misc-create_inode.c-set-dir-s-mode-correctly.patch +++ /dev/null @@ -1,41 +0,0 @@ -From f6d188580c2c9599319076fee22f2424652c711c Mon Sep 17 00:00:00 2001 -From: Robert Yang <liezhi.yang@windriver.com> -Date: Wed, 13 Sep 2017 19:55:35 -0700 -Subject: [PATCH] misc/create_inode.c: set dir's mode correctly - -The dir's mode has been set by ext2fs_mkdir() with umask, so -reset it to the source's mode in set_inode_extra(). - -Fixed when source dir's mode is 521, but tarball would be 721, this was -incorrect. - -Upstream-Status: Submitted - -Signed-off-by: Robert Yang <liezhi.yang@windriver.com> ---- - misc/create_inode.c | 9 ++++++++- - 1 file changed, 8 insertions(+), 1 deletion(-) - -diff --git a/misc/create_inode.c b/misc/create_inode.c -index 8ce3faf..50fbaa8 100644 ---- a/misc/create_inode.c -+++ b/misc/create_inode.c -@@ -116,7 +116,14 @@ static errcode_t set_inode_extra(ext2_filsys fs, ext2_ino_t ino, - - inode.i_uid = st->st_uid; - inode.i_gid = st->st_gid; -- inode.i_mode |= st->st_mode; -+ /* -+ * The dir's mode has been set by ext2fs_mkdir() with umask, so -+ * reset it to the source's mode -+ */ -+ if S_ISDIR(st->st_mode) -+ inode.i_mode = LINUX_S_IFDIR | st->st_mode; -+ else -+ inode.i_mode |= st->st_mode; - inode.i_atime = st->st_atime; - inode.i_mtime = st->st_mtime; - inode.i_ctime = st->st_ctime; --- -2.10.2 - diff --git a/meta/recipes-devtools/e2fsprogs/e2fsprogs/CVE-2019-5188.patch b/meta/recipes-devtools/e2fsprogs/e2fsprogs/CVE-2019-5188.patch deleted file mode 100644 index de4bce0037..0000000000 --- a/meta/recipes-devtools/e2fsprogs/e2fsprogs/CVE-2019-5188.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 8dd73c149f418238f19791f9d666089ef9734dff Mon Sep 17 00:00:00 2001 -From: Theodore Ts'o <tytso@mit.edu> -Date: Thu, 19 Dec 2019 19:37:34 -0500 -Subject: [PATCH] e2fsck: abort if there is a corrupted directory block when - rehashing - -In e2fsck pass 3a, when we are rehashing directories, at least in -theory, all of the directories should have had corruptions with -respect to directory entry structure fixed. However, it's possible -(for example, if the user declined a fix) that we can reach this stage -of processing with a corrupted directory entries. - -So check for that case and don't try to process a corrupted directory -block so we don't run into trouble in mutate_name() if there is a -zero-length file name. - -Addresses: TALOS-2019-0973 -Addresses: CVE-2019-5188 -Signed-off-by: Theodore Ts'o <tytso@mit.edu> - -CVE: CVE-2019-5188 -Signed-off-by: Anuj Mittal <anuj.mittal@intel.com> -Upstream-Status: Backport [https://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git/commit/?id=8dd73c149f418238f19791f9d666089ef9734dff] ---- - e2fsck/rehash.c | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c -index a5fc1be1..3dd1e941 100644 ---- a/e2fsck/rehash.c -+++ b/e2fsck/rehash.c -@@ -160,6 +160,10 @@ static int fill_dir_block(ext2_filsys fs, - dir_offset += rec_len; - if (dirent->inode == 0) - continue; -+ if ((name_len) == 0) { -+ fd->err = EXT2_ET_DIR_CORRUPTED; -+ return BLOCK_ABORT; -+ } - if (!fd->compress && (name_len == 1) && - (dirent->name[0] == '.')) - continue; -@@ -401,6 +405,11 @@ static int duplicate_search_and_fix(e2fsck_t ctx, ext2_filsys fs, - continue; - } - new_len = ext2fs_dirent_name_len(ent->dir); -+ if (new_len == 0) { -+ /* should never happen */ -+ ext2fs_unmark_valid(fs); -+ continue; -+ } - memcpy(new_name, ent->dir->name, new_len); - mutate_name(new_name, &new_len); - for (j=0; j < fd->num_array; j++) { --- -2.24.1 - diff --git a/meta/recipes-devtools/e2fsprogs/e2fsprogs/CVE-2022-1304.patch b/meta/recipes-devtools/e2fsprogs/e2fsprogs/CVE-2022-1304.patch new file mode 100644 index 0000000000..34e2567b25 --- /dev/null +++ b/meta/recipes-devtools/e2fsprogs/e2fsprogs/CVE-2022-1304.patch @@ -0,0 +1,42 @@ +From a66071ed6a0d1fa666d22dcb78fa6fcb3bf22df3 Mon Sep 17 00:00:00 2001 +From: Hitendra Prajapati <hprajapati@mvista.com> +Date: Fri, 27 May 2022 14:01:50 +0530 +Subject: [PATCH] CVE-2022-1304 + +Upstream-Status: Backport [https://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git/commit/?h=maint&id=ab51d587bb9b229b1fade1afd02e1574c1ba5c76] +CVE: CVE-2022-1304 +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> + +--- + lib/ext2fs/extent.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/lib/ext2fs/extent.c b/lib/ext2fs/extent.c +index ac3dbfec9..a1b1905cd 100644 +--- a/lib/ext2fs/extent.c ++++ b/lib/ext2fs/extent.c +@@ -495,6 +495,10 @@ retry: + ext2fs_le16_to_cpu(eh->eh_entries); + newpath->max_entries = ext2fs_le16_to_cpu(eh->eh_max); + ++ /* Make sure there is at least one extent present */ ++ if (newpath->left <= 0) ++ return EXT2_ET_EXTENT_NO_DOWN; ++ + if (path->left > 0) { + ix++; + newpath->end_blk = ext2fs_le32_to_cpu(ix->ei_block); +@@ -1630,6 +1634,10 @@ errcode_t ext2fs_extent_delete(ext2_extent_handle_t handle, int flags) + + cp = path->curr; + ++ /* Sanity check before memmove() */ ++ if (path->left < 0) ++ return EXT2_ET_EXTENT_LEAF_BAD; ++ + if (path->left) { + memmove(cp, cp + sizeof(struct ext3_extent_idx), + path->left * sizeof(struct ext3_extent_idx)); +-- +2.25.1 + diff --git a/meta/recipes-devtools/e2fsprogs/e2fsprogs/big-inodes-for-small-fs.patch b/meta/recipes-devtools/e2fsprogs/e2fsprogs/big-inodes-for-small-fs.patch new file mode 100644 index 0000000000..caeb560d32 --- /dev/null +++ b/meta/recipes-devtools/e2fsprogs/e2fsprogs/big-inodes-for-small-fs.patch @@ -0,0 +1,22 @@ +Ensure "small" file systems also have the default inode size (256 bytes) so that +can store 64-bit timestamps and work past 2038. + +The "small" type is any size >3MB and <512MB, which covers a lot of relatively +small filesystems built by OE, especially when they're sized to fit the contents +and expand to the storage on boot. + +Upstream-Status: Inappropriate +Signed-off-by: Ross Burton <ross.burton@arm.com> + +diff --git a/misc/mke2fs.conf.in b/misc/mke2fs.conf.in +index 01e35cf8..29f41dc0 100644 +--- a/misc/mke2fs.conf.in ++++ b/misc/mke2fs.conf.in +@@ -16,7 +16,6 @@ + } + small = { + blocksize = 1024 +- inode_size = 128 + inode_ratio = 4096 + } + floppy = { diff --git a/meta/recipes-devtools/e2fsprogs/e2fsprogs/e2fsck-fix-use-after-free-in-calculate_tree.patch b/meta/recipes-devtools/e2fsprogs/e2fsprogs/e2fsck-fix-use-after-free-in-calculate_tree.patch deleted file mode 100644 index 342a2b855b..0000000000 --- a/meta/recipes-devtools/e2fsprogs/e2fsprogs/e2fsck-fix-use-after-free-in-calculate_tree.patch +++ /dev/null @@ -1,76 +0,0 @@ -From: Wang Shilong <wshilong@ddn.com> -Date: Mon, 30 Dec 2019 19:52:39 -0500 -Subject: e2fsck: fix use after free in calculate_tree() - -The problem is alloc_blocks() will call get_next_block() which might -reallocate outdir->buf, and memory address could be changed after -this. To fix this, pointers that point into outdir->buf, such as -int_limit and root need to be recaulated based on the new starting -address of outdir->buf. - -[ Changed to correctly recalculate int_limit, and to optimize how we - reallocate outdir->buf. -TYT ] - -Addresses-Debian-Bug: 948517 -Signed-off-by: Wang Shilong <wshilong@ddn.com> -Signed-off-by: Theodore Ts'o <tytso@mit.edu> -(cherry picked from commit 101e73e99ccafa0403fcb27dd7413033b587ca01) - -Signed-off-by: Anuj Mittal <anuj.mittal@intel.com> -Upstream-Status: Backport [https://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git/commit/?id=101e73e99ccafa0403fcb27dd7413033b587ca01] ---- - e2fsck/rehash.c | 17 ++++++++++++++++- - 1 file changed, 16 insertions(+), 1 deletion(-) - -diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c -index 0a5888a9..2574e151 100644 ---- a/e2fsck/rehash.c -+++ b/e2fsck/rehash.c -@@ -295,7 +295,11 @@ static errcode_t get_next_block(ext2_filsys fs, struct out_dir *outdir, - errcode_t retval; - - if (outdir->num >= outdir->max) { -- retval = alloc_size_dir(fs, outdir, outdir->max + 50); -+ int increment = outdir->max / 10; -+ -+ if (increment < 50) -+ increment = 50; -+ retval = alloc_size_dir(fs, outdir, outdir->max + increment); - if (retval) - return retval; - } -@@ -637,6 +641,9 @@ static int alloc_blocks(ext2_filsys fs, - if (retval) - return retval; - -+ /* outdir->buf might be reallocated */ -+ *prev_ent = (struct ext2_dx_entry *) (outdir->buf + *prev_offset); -+ - *next_ent = set_int_node(fs, block_start); - *limit = (struct ext2_dx_countlimit *)(*next_ent); - if (next_offset) -@@ -726,6 +733,9 @@ static errcode_t calculate_tree(ext2_filsys fs, - return retval; - } - if (c3 == 0) { -+ int delta1 = (char *)int_limit - outdir->buf; -+ int delta2 = (char *)root - outdir->buf; -+ - retval = alloc_blocks(fs, &limit, &int_ent, - &dx_ent, &int_offset, - NULL, outdir, i, &c2, -@@ -733,6 +743,11 @@ static errcode_t calculate_tree(ext2_filsys fs, - if (retval) - return retval; - -+ /* outdir->buf might be reallocated */ -+ int_limit = (struct ext2_dx_countlimit *) -+ (outdir->buf + delta1); -+ root = (struct ext2_dx_entry *) -+ (outdir->buf + delta2); - } - dx_ent->block = ext2fs_cpu_to_le32(i); - if (c3 != limit->limit) --- -2.24.1 - diff --git a/meta/recipes-devtools/e2fsprogs/e2fsprogs/e2fsprogs-fix-missing-check-for-permission-denied.patch b/meta/recipes-devtools/e2fsprogs/e2fsprogs/e2fsprogs-fix-missing-check-for-permission-denied.patch index 4d335af4cf..284ac90196 100644 --- a/meta/recipes-devtools/e2fsprogs/e2fsprogs/e2fsprogs-fix-missing-check-for-permission-denied.patch +++ b/meta/recipes-devtools/e2fsprogs/e2fsprogs/e2fsprogs-fix-missing-check-for-permission-denied.patch @@ -1,4 +1,4 @@ -From e8331a76983e839a3d193446ab8ae9c1b09daa07 Mon Sep 17 00:00:00 2001 +From b55dfb4b62e507ae4f0814aec7597b56f9d6292a Mon Sep 17 00:00:00 2001 From: Jackie Huang <jackie.huang@windriver.com> Date: Wed, 10 Aug 2016 11:19:44 +0800 Subject: [PATCH] Fix missing check for permission denied. diff --git a/meta/recipes-devtools/e2fsprogs/e2fsprogs/quiet-debugfs.patch b/meta/recipes-devtools/e2fsprogs/e2fsprogs/quiet-debugfs.patch index 95e6a7a2d5..aac88eed98 100644 --- a/meta/recipes-devtools/e2fsprogs/e2fsprogs/quiet-debugfs.patch +++ b/meta/recipes-devtools/e2fsprogs/e2fsprogs/quiet-debugfs.patch @@ -1,4 +1,4 @@ -From de6d6f0dd010f5b9d917553acb9430278f448f23 Mon Sep 17 00:00:00 2001 +From 9aa68ad81b97847dda3493145f4b0a7cc580c551 Mon Sep 17 00:00:00 2001 From: Ross Burton <ross.burton@intel.com> Date: Mon, 23 Dec 2013 13:38:34 +0000 Subject: [PATCH] e2fsprogs: silence debugfs diff --git a/meta/recipes-devtools/e2fsprogs/e2fsprogs/run-ptest b/meta/recipes-devtools/e2fsprogs/e2fsprogs/run-ptest index c97c0377e9..279923db8e 100644 --- a/meta/recipes-devtools/e2fsprogs/e2fsprogs/run-ptest +++ b/meta/recipes-devtools/e2fsprogs/e2fsprogs/run-ptest @@ -8,3 +8,4 @@ rm -f *.tmp rm -f *.ok rm -f *.failed rm -f *.log +cp ../data/test_data.tmp ./ diff --git a/meta/recipes-devtools/e2fsprogs/e2fsprogs_1.45.4.bb b/meta/recipes-devtools/e2fsprogs/e2fsprogs_1.45.7.bb index 439928e433..565c433866 100644 --- a/meta/recipes-devtools/e2fsprogs/e2fsprogs_1.45.4.bb +++ b/meta/recipes-devtools/e2fsprogs/e2fsprogs_1.45.7.bb @@ -4,19 +4,17 @@ SRC_URI += "file://remove.ldconfig.call.patch \ file://run-ptest \ file://ptest.patch \ file://mkdir_p.patch \ - file://0001-misc-create_inode.c-set-dir-s-mode-correctly.patch \ file://0001-configure.ac-correct-AM_GNU_GETTEXT.patch \ file://0001-intl-do-not-try-to-use-gettext-defines-that-no-longe.patch \ - file://CVE-2019-5188.patch \ - file://0001-e2fsck-don-t-try-to-rehash-a-deleted-directory.patch \ - file://e2fsck-fix-use-after-free-in-calculate_tree.patch \ + file://CVE-2022-1304.patch \ " SRC_URI_append_class-native = " file://e2fsprogs-fix-missing-check-for-permission-denied.patch \ file://quiet-debugfs.patch \ + file://big-inodes-for-small-fs.patch \ " -SRCREV = "984ff8d6a0a1d5dc300505f67b38ed5047d51dac" +SRCREV = "5403970e44241cec26f98aaa0124b9881b4bbf4f" UPSTREAM_CHECK_GITTAGREGEX = "v(?P<pver>\d+\.\d+(\.\d+)*)$" EXTRA_OECONF += "--libdir=${base_libdir} --sbindir=${base_sbindir} \ @@ -56,6 +54,7 @@ do_install () { oe_multilib_header ext2fs/ext2_types.h install -d ${D}${base_bindir} mv ${D}${bindir}/chattr ${D}${base_bindir}/chattr.e2fsprogs + mv ${D}${bindir}/lsattr ${D}${base_bindir}/lsattr.e2fsprogs install -v -m 755 ${S}/contrib/populate-extfs.sh ${D}${base_sbindir}/ @@ -104,10 +103,12 @@ FILES_libe2p = "${base_libdir}/libe2p.so.*" FILES_libext2fs = "${libdir}/e2initrd_helper ${base_libdir}/libext2fs.so.*" FILES_${PN}-dev += "${datadir}/*/*.awk ${datadir}/*/*.sed ${base_libdir}/*.so ${bindir}/compile_et ${bindir}/mk_cmds" -ALTERNATIVE_${PN} = "chattr" +ALTERNATIVE_${PN} = "chattr lsattr" ALTERNATIVE_PRIORITY = "100" ALTERNATIVE_LINK_NAME[chattr] = "${base_bindir}/chattr" ALTERNATIVE_TARGET[chattr] = "${base_bindir}/chattr.e2fsprogs" +ALTERNATIVE_LINK_NAME[lsattr] = "${base_bindir}/lsattr" +ALTERNATIVE_TARGET[lsattr] = "${base_bindir}/lsattr.e2fsprogs" ALTERNATIVE_${PN}-doc = "fsck.8" ALTERNATIVE_LINK_NAME[fsck.8] = "${mandir}/man8/fsck.8" @@ -143,4 +144,7 @@ do_install_ptest() { install -d ${D}${PTEST_PATH}/lib install -m 0644 ${B}/lib/config.h ${D}${PTEST_PATH}/lib/ + + install -d ${D}${PTEST_PATH}/data + install -m 0644 ${B}/tests/test_data.tmp ${D}${PTEST_PATH}/data/ } diff --git a/meta/recipes-devtools/elfutils/elfutils_0.178.bb b/meta/recipes-devtools/elfutils/elfutils_0.178.bb index 97d033e356..29a3bbfffb 100644 --- a/meta/recipes-devtools/elfutils/elfutils_0.178.bb +++ b/meta/recipes-devtools/elfutils/elfutils_0.178.bb @@ -34,6 +34,7 @@ SRC_URI = "https://sourceware.org/elfutils/ftp/${PV}/${BP}.tar.bz2 \ file://0001-ppc_initreg.c-Incliude-asm-ptrace.h-for-pt_regs-defi.patch \ file://run-ptest \ file://ptest.patch \ + file://CVE-2021-33294.patch \ " SRC_URI_append_libc-musl = " \ file://0001-musl-obstack-fts.patch \ diff --git a/meta/recipes-devtools/elfutils/files/CVE-2021-33294.patch b/meta/recipes-devtools/elfutils/files/CVE-2021-33294.patch new file mode 100644 index 0000000000..0500a4cf83 --- /dev/null +++ b/meta/recipes-devtools/elfutils/files/CVE-2021-33294.patch @@ -0,0 +1,72 @@ +From 480b6fa3662ba8ffeee274bf0d37423413c01e55 Mon Sep 17 00:00:00 2001 +From: Mark Wielaard <mark@klomp.org> +Date: Wed, 3 Mar 2021 21:40:53 +0100 +Subject: [PATCH] readelf: Sanity check verneed and verdef offsets in handle_symtab. + +We are going through vna_next, vn_next and vd_next in a while loop. +Make sure that all offsets are sane. We don't want things to wrap +around so we go in cycles. + +https://sourceware.org/bugzilla/show_bug.cgi?id=27501 + +Signed-off-by: Mark Wielaard <mark@klomp.org> + +Upstream-Status: Backport [https://sourceware.org/git/?p=elfutils.git;a=commit;h=480b6fa3662ba8ffeee274bf0d37423413c01e55] +CVE: CVE-2021-33294 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + src/ChangeLog | 5 +++++ + src/readelf.c | 10 +++++++++- + 2 files changed, 14 insertions(+), 1 deletion(-) + +diff --git a/src/ChangeLog b/src/ChangeLog +index 6af977e..f0d9e39 100644 +--- a/src/ChangeLog ++++ b/src/ChangeLog +@@ -1,3 +1,8 @@ ++2021-03-03 Mark Wielaard <mark@klomp.org> ++ ++ * readelf.c (handle_symtab): Sanity check verneed vna_next, ++ vn_next and verdef vd_next offsets. ++ + 2019-11-26 Mark Wielaard <mark@klomp.org> + + * Makefile.am (BUILD_STATIC): Add libraries needed for libdw. +diff --git a/src/readelf.c b/src/readelf.c +index 5994615..ab7a1c1 100644 +--- a/src/readelf.c ++++ b/src/readelf.c +@@ -2550,7 +2550,9 @@ handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr) + &vernaux_mem); + while (vernaux != NULL + && vernaux->vna_other != *versym +- && vernaux->vna_next != 0) ++ && vernaux->vna_next != 0 ++ && (verneed_data->d_size - vna_offset ++ >= vernaux->vna_next)) + { + /* Update the offset. */ + vna_offset += vernaux->vna_next; +@@ -2567,6 +2569,9 @@ handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr) + /* Found it. */ + break; + ++ if (verneed_data->d_size - vn_offset < verneed->vn_next) ++ break; ++ + vn_offset += verneed->vn_next; + verneed = (verneed->vn_next == 0 + ? NULL +@@ -2602,6 +2607,9 @@ handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr) + /* Found the definition. */ + break; + ++ if (verdef_data->d_size - vd_offset < verdef->vd_next) ++ break; ++ + vd_offset += verdef->vd_next; + verdef = (verdef->vd_next == 0 + ? NULL +-- +2.25.1 + diff --git a/meta/recipes-devtools/file/file_5.38.bb b/meta/recipes-devtools/file/file_5.38.bb index 2d62ead10b..b19bf03986 100644 --- a/meta/recipes-devtools/file/file_5.38.bb +++ b/meta/recipes-devtools/file/file_5.38.bb @@ -11,7 +11,7 @@ LIC_FILES_CHKSUM = "file://COPYING;beginline=2;md5=0251eaec1188b20d9a72c502ecfdd DEPENDS = "file-replacement-native" DEPENDS_class-native = "bzip2-replacement-native" -SRC_URI = "git://github.com/file/file.git" +SRC_URI = "git://github.com/file/file.git;branch=master;protocol=https" SRCREV = "ec41083645689a787cdd00cb3b5bf578aa79e46c" S = "${WORKDIR}/git" diff --git a/meta/recipes-devtools/flex/flex_2.6.4.bb b/meta/recipes-devtools/flex/flex_2.6.4.bb index 1d43d2228a..50d3bf8de1 100644 --- a/meta/recipes-devtools/flex/flex_2.6.4.bb +++ b/meta/recipes-devtools/flex/flex_2.6.4.bb @@ -26,6 +26,11 @@ SRC_URI[sha256sum] = "e87aae032bf07c26f85ac0ed3250998c37621d95f8bd748b31f15b33c4 UPSTREAM_CHECK_URI = "https://github.com/westes/flex/releases" UPSTREAM_CHECK_REGEX = "flex-(?P<pver>\d+(\.\d+)+)\.tar" +# Disputed - yes there is stack exhaustion but no bug and it is building the +# parser, not running it, effectively similar to a compiler ICE. Upstream no plans to address +# https://github.com/westes/flex/issues/414 +CVE_CHECK_WHITELIST += "CVE-2019-6293" + inherit autotools gettext texinfo ptest M4 = "${bindir}/m4" diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0001-Backport-fix-for-PR-tree-optimization-97236-fix-bad-.patch b/meta/recipes-devtools/gcc/gcc-9.3/0001-Backport-fix-for-PR-tree-optimization-97236-fix-bad-.patch deleted file mode 100644 index dc1039dcc8..0000000000 --- a/meta/recipes-devtools/gcc/gcc-9.3/0001-Backport-fix-for-PR-tree-optimization-97236-fix-bad-.patch +++ /dev/null @@ -1,119 +0,0 @@ -Upstream-Status: Backport [https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=97b668f9a8c6ec565c278a60e7d1492a6932e409] -Signed-off-by: Jon Mason <jon.mason@arm.com> - -From 97b668f9a8c6ec565c278a60e7d1492a6932e409 Mon Sep 17 00:00:00 2001 -From: Matthias Klose <doko@ubuntu.com> -Date: Tue, 6 Oct 2020 13:41:37 +0200 -Subject: [PATCH] Backport fix for PR/tree-optimization/97236 - fix bad use of - VMAT_CONTIGUOUS - -This avoids using VMAT_CONTIGUOUS with single-element interleaving -when using V1mode vectors. Instead keep VMAT_ELEMENTWISE but -continue to avoid load-lanes and gathers. - -2020-10-01 Richard Biener <rguenther@suse.de> - - PR tree-optimization/97236 - * tree-vect-stmts.c (get_group_load_store_type): Keep - VMAT_ELEMENTWISE for single-element vectors. - - * gcc.dg/vect/pr97236.c: New testcase. - -(cherry picked from commit 1ab88985631dd2c5a5e3b5c0dce47cf8b6ed2f82) ---- - gcc/testsuite/gcc.dg/vect/pr97236.c | 43 +++++++++++++++++++++++++++++ - gcc/tree-vect-stmts.c | 20 ++++++-------- - 2 files changed, 52 insertions(+), 11 deletions(-) - create mode 100644 gcc/testsuite/gcc.dg/vect/pr97236.c - -diff --git a/gcc/testsuite/gcc.dg/vect/pr97236.c b/gcc/testsuite/gcc.dg/vect/pr97236.c -new file mode 100644 -index 000000000000..9d3dc20d953d ---- /dev/null -+++ b/gcc/testsuite/gcc.dg/vect/pr97236.c -@@ -0,0 +1,43 @@ -+typedef unsigned char __uint8_t; -+typedef __uint8_t uint8_t; -+typedef struct plane_t { -+ uint8_t *p_pixels; -+ int i_lines; -+ int i_pitch; -+} plane_t; -+ -+typedef struct { -+ plane_t p[5]; -+} picture_t; -+ -+#define N 4 -+ -+void __attribute__((noipa)) -+picture_Clone(picture_t *picture, picture_t *res) -+{ -+ for (int i = 0; i < N; i++) { -+ res->p[i].p_pixels = picture->p[i].p_pixels; -+ res->p[i].i_lines = picture->p[i].i_lines; -+ res->p[i].i_pitch = picture->p[i].i_pitch; -+ } -+} -+ -+int -+main() -+{ -+ picture_t aaa, bbb; -+ uint8_t pixels[10] = {1, 1, 1, 1, 1, 1, 1, 1}; -+ -+ for (unsigned i = 0; i < N; i++) -+ aaa.p[i].p_pixels = pixels; -+ -+ picture_Clone (&aaa, &bbb); -+ -+ uint8_t c = 0; -+ for (unsigned i = 0; i < N; i++) -+ c += bbb.p[i].p_pixels[0]; -+ -+ if (c != N) -+ __builtin_abort (); -+ return 0; -+} -diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c -index 507f81b0a0e8..ffbba3441de2 100644 ---- a/gcc/tree-vect-stmts.c -+++ b/gcc/tree-vect-stmts.c -@@ -2355,25 +2355,23 @@ get_group_load_store_type (stmt_vec_info stmt_info, tree vectype, bool slp, - /* First cope with the degenerate case of a single-element - vector. */ - if (known_eq (TYPE_VECTOR_SUBPARTS (vectype), 1U)) -- *memory_access_type = VMAT_CONTIGUOUS; -+ ; - - /* Otherwise try using LOAD/STORE_LANES. */ -- if (*memory_access_type == VMAT_ELEMENTWISE -- && (vls_type == VLS_LOAD -- ? vect_load_lanes_supported (vectype, group_size, masked_p) -- : vect_store_lanes_supported (vectype, group_size, -- masked_p))) -+ else if (vls_type == VLS_LOAD -+ ? vect_load_lanes_supported (vectype, group_size, masked_p) -+ : vect_store_lanes_supported (vectype, group_size, -+ masked_p)) - { - *memory_access_type = VMAT_LOAD_STORE_LANES; - overrun_p = would_overrun_p; - } - - /* If that fails, try using permuting loads. */ -- if (*memory_access_type == VMAT_ELEMENTWISE -- && (vls_type == VLS_LOAD -- ? vect_grouped_load_supported (vectype, single_element_p, -- group_size) -- : vect_grouped_store_supported (vectype, group_size))) -+ else if (vls_type == VLS_LOAD -+ ? vect_grouped_load_supported (vectype, single_element_p, -+ group_size) -+ : vect_grouped_store_supported (vectype, group_size)) - { - *memory_access_type = VMAT_CONTIGUOUS_PERMUTE; - overrun_p = would_overrun_p; --- -2.20.1 - diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0001-aarch64-New-Straight-Line-Speculation-SLS-mitigation.patch b/meta/recipes-devtools/gcc/gcc-9.3/0001-aarch64-New-Straight-Line-Speculation-SLS-mitigation.patch deleted file mode 100644 index a7e29f4bd7..0000000000 --- a/meta/recipes-devtools/gcc/gcc-9.3/0001-aarch64-New-Straight-Line-Speculation-SLS-mitigation.patch +++ /dev/null @@ -1,204 +0,0 @@ -CVE: CVE-2020-13844 -Upstream-Status: Backport -Signed-off-by: Ross Burton <ross.burton@arm.com> - -From 20da13e395bde597d8337167c712039c8f923c3b Mon Sep 17 00:00:00 2001 -From: Matthew Malcomson <matthew.malcomson@arm.com> -Date: Thu, 9 Jul 2020 09:11:58 +0100 -Subject: [PATCH 1/3] aarch64: New Straight Line Speculation (SLS) mitigation - flags - -Here we introduce the flags that will be used for straight line speculation. - -The new flag introduced is `-mharden-sls=`. -This flag can take arguments of `none`, `all`, or a comma seperated list -of one or more of `retbr` or `blr`. -`none` indicates no special mitigation of the straight line speculation -vulnerability. -`all` requests all mitigations currently implemented. -`retbr` requests that the RET and BR instructions have a speculation -barrier inserted after them. -`blr` requests that BLR instructions are replaced by a BL to a function -stub using a BR with a speculation barrier after it. - -Setting this on a per-function basis using attributes or the like is not -enabled, but may be in the future. - -(cherry picked from commit a9ba2a9b77bec7eacaf066801f22d1c366a2bc86) - -gcc/ChangeLog: - -2020-06-02 Matthew Malcomson <matthew.malcomson@arm.com> - - * config/aarch64/aarch64-protos.h (aarch64_harden_sls_retbr_p): - New. - (aarch64_harden_sls_blr_p): New. - * config/aarch64/aarch64.c (enum aarch64_sls_hardening_type): - New. - (aarch64_harden_sls_retbr_p): New. - (aarch64_harden_sls_blr_p): New. - (aarch64_validate_sls_mitigation): New. - (aarch64_override_options): Parse options for SLS mitigation. - * config/aarch64/aarch64.opt (-mharden-sls): New option. - * doc/invoke.texi: Document new option. ---- - gcc/config/aarch64/aarch64-protos.h | 3 ++ - gcc/config/aarch64/aarch64.c | 76 +++++++++++++++++++++++++++++ - gcc/config/aarch64/aarch64.opt | 4 ++ - gcc/doc/invoke.texi | 12 +++++ - 4 files changed, 95 insertions(+) - -diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h -index c083cad53..31493f412 100644 ---- a/gcc/config/aarch64/aarch64-protos.h -+++ b/gcc/config/aarch64/aarch64-protos.h -@@ -644,4 +644,7 @@ poly_uint64 aarch64_regmode_natural_size (machine_mode); - - bool aarch64_high_bits_all_ones_p (HOST_WIDE_INT); - -+extern bool aarch64_harden_sls_retbr_p (void); -+extern bool aarch64_harden_sls_blr_p (void); -+ - #endif /* GCC_AARCH64_PROTOS_H */ -diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c -index b452a53af..269ff6c92 100644 ---- a/gcc/config/aarch64/aarch64.c -+++ b/gcc/config/aarch64/aarch64.c -@@ -11734,6 +11734,79 @@ aarch64_validate_mcpu (const char *str, const struct processor **res, - return false; - } - -+/* Straight line speculation indicators. */ -+enum aarch64_sls_hardening_type -+{ -+ SLS_NONE = 0, -+ SLS_RETBR = 1, -+ SLS_BLR = 2, -+ SLS_ALL = 3, -+}; -+static enum aarch64_sls_hardening_type aarch64_sls_hardening; -+ -+/* Return whether we should mitigatate Straight Line Speculation for the RET -+ and BR instructions. */ -+bool -+aarch64_harden_sls_retbr_p (void) -+{ -+ return aarch64_sls_hardening & SLS_RETBR; -+} -+ -+/* Return whether we should mitigatate Straight Line Speculation for the BLR -+ instruction. */ -+bool -+aarch64_harden_sls_blr_p (void) -+{ -+ return aarch64_sls_hardening & SLS_BLR; -+} -+ -+/* As of yet we only allow setting these options globally, in the future we may -+ allow setting them per function. */ -+static void -+aarch64_validate_sls_mitigation (const char *const_str) -+{ -+ char *token_save = NULL; -+ char *str = NULL; -+ -+ if (strcmp (const_str, "none") == 0) -+ { -+ aarch64_sls_hardening = SLS_NONE; -+ return; -+ } -+ if (strcmp (const_str, "all") == 0) -+ { -+ aarch64_sls_hardening = SLS_ALL; -+ return; -+ } -+ -+ char *str_root = xstrdup (const_str); -+ str = strtok_r (str_root, ",", &token_save); -+ if (!str) -+ error ("invalid argument given to %<-mharden-sls=%>"); -+ -+ int temp = SLS_NONE; -+ while (str) -+ { -+ if (strcmp (str, "blr") == 0) -+ temp |= SLS_BLR; -+ else if (strcmp (str, "retbr") == 0) -+ temp |= SLS_RETBR; -+ else if (strcmp (str, "none") == 0 || strcmp (str, "all") == 0) -+ { -+ error ("%<%s%> must be by itself for %<-mharden-sls=%>", str); -+ break; -+ } -+ else -+ { -+ error ("invalid argument %<%s%> for %<-mharden-sls=%>", str); -+ break; -+ } -+ str = strtok_r (NULL, ",", &token_save); -+ } -+ aarch64_sls_hardening = (aarch64_sls_hardening_type) temp; -+ free (str_root); -+} -+ - /* Parses CONST_STR for branch protection features specified in - aarch64_branch_protect_types, and set any global variables required. Returns - the parsing result and assigns LAST_STR to the last processed token from -@@ -11972,6 +12045,9 @@ aarch64_override_options (void) - selected_arch = NULL; - selected_tune = NULL; - -+ if (aarch64_harden_sls_string) -+ aarch64_validate_sls_mitigation (aarch64_harden_sls_string); -+ - if (aarch64_branch_protection_string) - aarch64_validate_mbranch_protection (aarch64_branch_protection_string); - -diff --git a/gcc/config/aarch64/aarch64.opt b/gcc/config/aarch64/aarch64.opt -index 3c6d1cc90..d27ab6df8 100644 ---- a/gcc/config/aarch64/aarch64.opt -+++ b/gcc/config/aarch64/aarch64.opt -@@ -71,6 +71,10 @@ mgeneral-regs-only - Target Report RejectNegative Mask(GENERAL_REGS_ONLY) Save - Generate code which uses only the general registers. - -+mharden-sls= -+Target RejectNegative Joined Var(aarch64_harden_sls_string) -+Generate code to mitigate against straight line speculation. -+ - mfix-cortex-a53-835769 - Target Report Var(aarch64_fix_a53_err835769) Init(2) Save - Workaround for ARM Cortex-A53 Erratum number 835769. -diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi -index 2f7ffe456..5f04a7d2b 100644 ---- a/gcc/doc/invoke.texi -+++ b/gcc/doc/invoke.texi -@@ -638,6 +638,7 @@ Objective-C and Objective-C++ Dialects}. - -mpc-relative-literal-loads @gol - -msign-return-address=@var{scope} @gol - -mbranch-protection=@var{none}|@var{standard}|@var{pac-ret}[+@var{leaf}]|@var{bti} @gol -+-mharden-sls=@var{opts} @gol - -march=@var{name} -mcpu=@var{name} -mtune=@var{name} @gol - -moverride=@var{string} -mverbose-cost-dump @gol - -mstack-protector-guard=@var{guard} -mstack-protector-guard-reg=@var{sysreg} @gol -@@ -15955,6 +15956,17 @@ argument @samp{leaf} can be used to extend the signing to include leaf - functions. - @samp{bti} turns on branch target identification mechanism. - -+@item -mharden-sls=@var{opts} -+@opindex mharden-sls -+Enable compiler hardening against straight line speculation (SLS). -+@var{opts} is a comma-separated list of the following options: -+@table @samp -+@item retbr -+@item blr -+@end table -+In addition, @samp{-mharden-sls=all} enables all SLS hardening while -+@samp{-mharden-sls=none} disables all SLS hardening. -+ - @item -msve-vector-bits=@var{bits} - @opindex msve-vector-bits - Specify the number of bits in an SVE vector register. This option only has --- -2.25.1 - diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0002-aarch64-Introduce-SLS-mitigation-for-RET-and-BR-inst.patch b/meta/recipes-devtools/gcc/gcc-9.3/0002-aarch64-Introduce-SLS-mitigation-for-RET-and-BR-inst.patch deleted file mode 100644 index c972088d2b..0000000000 --- a/meta/recipes-devtools/gcc/gcc-9.3/0002-aarch64-Introduce-SLS-mitigation-for-RET-and-BR-inst.patch +++ /dev/null @@ -1,600 +0,0 @@ -CVE: CVE-2020-13844 -Upstream-Status: Backport -Signed-off-by: Ross Burton <ross.burton@arm.com> - -From dc586a749228ecfb71f72ec2ca10e6f7b6874af3 Mon Sep 17 00:00:00 2001 -From: Matthew Malcomson <matthew.malcomson@arm.com> -Date: Thu, 9 Jul 2020 09:11:59 +0100 -Subject: [PATCH 2/3] aarch64: Introduce SLS mitigation for RET and BR - instructions - -Instructions following RET or BR are not necessarily executed. In order -to avoid speculation past RET and BR we can simply append a speculation -barrier. - -Since these speculation barriers will not be architecturally executed, -they are not expected to add a high performance penalty. - -The speculation barrier is to be SB when targeting architectures which -have this enabled, and DSB SY + ISB otherwise. - -We add tests for each of the cases where such an instruction was seen. - -This is implemented by modifying each machine description pattern that -emits either a RET or a BR instruction. We choose not to use something -like `TARGET_ASM_FUNCTION_EPILOGUE` since it does not affect the -`indirect_jump`, `jump`, `sibcall_insn` and `sibcall_value_insn` -patterns and we find it preferable to implement the functionality in the -same way for every pattern. - -There is one particular case which is slightly tricky. The -implementation of TARGET_ASM_TRAMPOLINE_TEMPLATE uses a BR which needs -to be mitigated against. The trampoline template is used *once* per -compilation unit, and the TRAMPOLINE_SIZE is exposed to the user via the -builtin macro __LIBGCC_TRAMPOLINE_SIZE__. -In the future we may implement function specific attributes to turn on -and off hardening on a per-function basis. -The fixed nature of the trampoline described above implies it will be -safer to ensure this speculation barrier is always used. - -Testing: - Bootstrap and regtest done on aarch64-none-linux - Used a temporary hack(1) to use these options on every test in the - testsuite and a script to check that the output never emitted an - unmitigated RET or BR. - -1) Temporary hack was a change to the testsuite to always use -`-save-temps` and run a script on the assembly output of those -compilations which produced one to ensure every RET or BR is immediately -followed by a speculation barrier. - -(cherry picked from be178ecd5ac1fe1510d960ff95c66d0ff831afe1) - -gcc/ChangeLog: - - * config/aarch64/aarch64-protos.h (aarch64_sls_barrier): New. - * config/aarch64/aarch64.c (aarch64_output_casesi): Emit - speculation barrier after BR instruction if needs be. - (aarch64_trampoline_init): Handle ptr_mode value & adjust size - of code copied. - (aarch64_sls_barrier): New. - (aarch64_asm_trampoline_template): Add needed barriers. - * config/aarch64/aarch64.h (AARCH64_ISA_SB): New. - (TARGET_SB): New. - (TRAMPOLINE_SIZE): Account for barrier. - * config/aarch64/aarch64.md (indirect_jump, *casesi_dispatch, - simple_return, *do_return, *sibcall_insn, *sibcall_value_insn): - Emit barrier if needs be, also account for possible barrier using - "sls_length" attribute. - (sls_length): New attribute. - (length): Determine default using any non-default sls_length - value. - -gcc/testsuite/ChangeLog: - - * gcc.target/aarch64/sls-mitigation/sls-miti-retbr.c: New test. - * gcc.target/aarch64/sls-mitigation/sls-miti-retbr-pacret.c: - New test. - * gcc.target/aarch64/sls-mitigation/sls-mitigation.exp: New file. - * lib/target-supports.exp (check_effective_target_aarch64_asm_sb_ok): - New proc. ---- - gcc/config/aarch64/aarch64-protos.h | 1 + - gcc/config/aarch64/aarch64.c | 41 +++++- - gcc/config/aarch64/aarch64.h | 10 +- - gcc/config/aarch64/aarch64.md | 75 ++++++++--- - .../sls-mitigation/sls-miti-retbr-pacret.c | 15 +++ - .../aarch64/sls-mitigation/sls-miti-retbr.c | 119 ++++++++++++++++++ - .../aarch64/sls-mitigation/sls-mitigation.exp | 73 +++++++++++ - gcc/testsuite/lib/target-supports.exp | 3 +- - 8 files changed, 312 insertions(+), 25 deletions(-) - create mode 100644 gcc/testsuite/gcc.target/aarch64/sls-mitigation/sls-miti-retbr-pacret.c - create mode 100644 gcc/testsuite/gcc.target/aarch64/sls-mitigation/sls-miti-retbr.c - create mode 100644 gcc/testsuite/gcc.target/aarch64/sls-mitigation/sls-mitigation.exp - -diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h -index 31493f412..885eae893 100644 ---- a/gcc/config/aarch64/aarch64-protos.h -+++ b/gcc/config/aarch64/aarch64-protos.h -@@ -644,6 +644,7 @@ poly_uint64 aarch64_regmode_natural_size (machine_mode); - - bool aarch64_high_bits_all_ones_p (HOST_WIDE_INT); - -+const char *aarch64_sls_barrier (int); - extern bool aarch64_harden_sls_retbr_p (void); - extern bool aarch64_harden_sls_blr_p (void); - -diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c -index 269ff6c92..dff61105c 100644 ---- a/gcc/config/aarch64/aarch64.c -+++ b/gcc/config/aarch64/aarch64.c -@@ -8412,8 +8412,8 @@ aarch64_return_addr (int count, rtx frame ATTRIBUTE_UNUSED) - static void - aarch64_asm_trampoline_template (FILE *f) - { -- int offset1 = 16; -- int offset2 = 20; -+ int offset1 = 24; -+ int offset2 = 28; - - if (aarch64_bti_enabled ()) - { -@@ -8436,6 +8436,17 @@ aarch64_asm_trampoline_template (FILE *f) - } - asm_fprintf (f, "\tbr\t%s\n", reg_names [IP1_REGNUM]); - -+ /* We always emit a speculation barrier. -+ This is because the same trampoline template is used for every nested -+ function. Since nested functions are not particularly common or -+ performant we don't worry too much about the extra instructions to copy -+ around. -+ This is not yet a problem, since we have not yet implemented function -+ specific attributes to choose between hardening against straight line -+ speculation or not, but such function specific attributes are likely to -+ happen in the future. */ -+ asm_fprintf (f, "\tdsb\tsy\n\tisb\n"); -+ - /* The trampoline needs an extra padding instruction. In case if BTI is - enabled the padding instruction is replaced by the BTI instruction at - the beginning. */ -@@ -8450,10 +8461,14 @@ static void - aarch64_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) - { - rtx fnaddr, mem, a_tramp; -- const int tramp_code_sz = 16; -+ const int tramp_code_sz = 24; - - /* Don't need to copy the trailing D-words, we fill those in below. */ -- emit_block_move (m_tramp, assemble_trampoline_template (), -+ /* We create our own memory address in Pmode so that `emit_block_move` can -+ use parts of the backend which expect Pmode addresses. */ -+ rtx temp = convert_memory_address (Pmode, XEXP (m_tramp, 0)); -+ emit_block_move (gen_rtx_MEM (BLKmode, temp), -+ assemble_trampoline_template (), - GEN_INT (tramp_code_sz), BLOCK_OP_NORMAL); - mem = adjust_address (m_tramp, ptr_mode, tramp_code_sz); - fnaddr = XEXP (DECL_RTL (fndecl), 0); -@@ -8640,6 +8655,8 @@ aarch64_output_casesi (rtx *operands) - output_asm_insn (buf, operands); - output_asm_insn (patterns[index][1], operands); - output_asm_insn ("br\t%3", operands); -+ output_asm_insn (aarch64_sls_barrier (aarch64_harden_sls_retbr_p ()), -+ operands); - assemble_label (asm_out_file, label); - return ""; - } -@@ -18976,6 +18993,22 @@ aarch64_file_end_indicate_exec_stack () - #undef GNU_PROPERTY_AARCH64_FEATURE_1_BTI - #undef GNU_PROPERTY_AARCH64_FEATURE_1_AND - -+/* Helper function for straight line speculation. -+ Return what barrier should be emitted for straight line speculation -+ mitigation. -+ When not mitigating against straight line speculation this function returns -+ an empty string. -+ When mitigating against straight line speculation, use: -+ * SB when the v8.5-A SB extension is enabled. -+ * DSB+ISB otherwise. */ -+const char * -+aarch64_sls_barrier (int mitigation_required) -+{ -+ return mitigation_required -+ ? (TARGET_SB ? "sb" : "dsb\tsy\n\tisb") -+ : ""; -+} -+ - /* Target-specific selftests. */ - - #if CHECKING_P -diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h -index 772a97296..72ddc6fd9 100644 ---- a/gcc/config/aarch64/aarch64.h -+++ b/gcc/config/aarch64/aarch64.h -@@ -235,6 +235,7 @@ extern unsigned aarch64_architecture_version; - #define AARCH64_ISA_F16FML (aarch64_isa_flags & AARCH64_FL_F16FML) - #define AARCH64_ISA_RCPC8_4 (aarch64_isa_flags & AARCH64_FL_RCPC8_4) - #define AARCH64_ISA_V8_5 (aarch64_isa_flags & AARCH64_FL_V8_5) -+#define AARCH64_ISA_SB (aarch64_isa_flags & AARCH64_FL_SB) - - /* Crypto is an optional extension to AdvSIMD. */ - #define TARGET_CRYPTO (TARGET_SIMD && AARCH64_ISA_CRYPTO) -@@ -285,6 +286,9 @@ extern unsigned aarch64_architecture_version; - #define TARGET_FIX_ERR_A53_835769_DEFAULT 1 - #endif - -+/* SB instruction is enabled through +sb. */ -+#define TARGET_SB (AARCH64_ISA_SB) -+ - /* Apply the workaround for Cortex-A53 erratum 835769. */ - #define TARGET_FIX_ERR_A53_835769 \ - ((aarch64_fix_a53_err835769 == 2) \ -@@ -931,8 +935,10 @@ typedef struct - - #define RETURN_ADDR_RTX aarch64_return_addr - --/* BTI c + 3 insns + 2 pointer-sized entries. */ --#define TRAMPOLINE_SIZE (TARGET_ILP32 ? 24 : 32) -+/* BTI c + 3 insns -+ + sls barrier of DSB + ISB. -+ + 2 pointer-sized entries. */ -+#define TRAMPOLINE_SIZE (24 + (TARGET_ILP32 ? 8 : 16)) - - /* Trampolines contain dwords, so must be dword aligned. */ - #define TRAMPOLINE_ALIGNMENT 64 -diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md -index cc5a887d4..494aee964 100644 ---- a/gcc/config/aarch64/aarch64.md -+++ b/gcc/config/aarch64/aarch64.md -@@ -331,10 +331,25 @@ - ;; Attribute that specifies whether the alternative uses MOVPRFX. - (define_attr "movprfx" "no,yes" (const_string "no")) - -+;; Attribute to specify that an alternative has the length of a single -+;; instruction plus a speculation barrier. -+(define_attr "sls_length" "none,retbr,casesi" (const_string "none")) -+ - (define_attr "length" "" - (cond [(eq_attr "movprfx" "yes") - (const_int 8) -- ] (const_int 4))) -+ -+ (eq_attr "sls_length" "retbr") -+ (cond [(match_test "!aarch64_harden_sls_retbr_p ()") (const_int 4) -+ (match_test "TARGET_SB") (const_int 8)] -+ (const_int 12)) -+ -+ (eq_attr "sls_length" "casesi") -+ (cond [(match_test "!aarch64_harden_sls_retbr_p ()") (const_int 16) -+ (match_test "TARGET_SB") (const_int 20)] -+ (const_int 24)) -+ ] -+ (const_int 4))) - - ;; Strictly for compatibility with AArch32 in pipeline models, since AArch64 has - ;; no predicated insns. -@@ -370,8 +385,12 @@ - (define_insn "indirect_jump" - [(set (pc) (match_operand:DI 0 "register_operand" "r"))] - "" -- "br\\t%0" -- [(set_attr "type" "branch")] -+ { -+ output_asm_insn ("br\\t%0", operands); -+ return aarch64_sls_barrier (aarch64_harden_sls_retbr_p ()); -+ } -+ [(set_attr "type" "branch") -+ (set_attr "sls_length" "retbr")] - ) - - (define_insn "jump" -@@ -657,7 +676,7 @@ - "* - return aarch64_output_casesi (operands); - " -- [(set_attr "length" "16") -+ [(set_attr "sls_length" "casesi") - (set_attr "type" "branch")] - ) - -@@ -736,14 +755,18 @@ - [(return)] - "" - { -+ const char *ret = NULL; - if (aarch64_return_address_signing_enabled () - && TARGET_ARMV8_3 - && !crtl->calls_eh_return) -- return "retaa"; -- -- return "ret"; -+ ret = "retaa"; -+ else -+ ret = "ret"; -+ output_asm_insn (ret, operands); -+ return aarch64_sls_barrier (aarch64_harden_sls_retbr_p ()); - } -- [(set_attr "type" "branch")] -+ [(set_attr "type" "branch") -+ (set_attr "sls_length" "retbr")] - ) - - (define_expand "return" -@@ -755,8 +778,12 @@ - (define_insn "simple_return" - [(simple_return)] - "aarch64_use_simple_return_insn_p ()" -- "ret" -- [(set_attr "type" "branch")] -+ { -+ output_asm_insn ("ret", operands); -+ return aarch64_sls_barrier (aarch64_harden_sls_retbr_p ()); -+ } -+ [(set_attr "type" "branch") -+ (set_attr "sls_length" "retbr")] - ) - - (define_insn "*cb<optab><mode>1" -@@ -947,10 +974,16 @@ - (match_operand 1 "" "")) - (return)] - "SIBLING_CALL_P (insn)" -- "@ -- br\\t%0 -- b\\t%c0" -- [(set_attr "type" "branch, branch")] -+ { -+ if (which_alternative == 0) -+ { -+ output_asm_insn ("br\\t%0", operands); -+ return aarch64_sls_barrier (aarch64_harden_sls_retbr_p ()); -+ } -+ return "b\\t%c0"; -+ } -+ [(set_attr "type" "branch, branch") -+ (set_attr "sls_length" "retbr,none")] - ) - - (define_insn "*sibcall_value_insn" -@@ -960,10 +993,16 @@ - (match_operand 2 "" ""))) - (return)] - "SIBLING_CALL_P (insn)" -- "@ -- br\\t%1 -- b\\t%c1" -- [(set_attr "type" "branch, branch")] -+ { -+ if (which_alternative == 0) -+ { -+ output_asm_insn ("br\\t%1", operands); -+ return aarch64_sls_barrier (aarch64_harden_sls_retbr_p ()); -+ } -+ return "b\\t%c1"; -+ } -+ [(set_attr "type" "branch, branch") -+ (set_attr "sls_length" "retbr,none")] - ) - - ;; Call subroutine returning any type. -diff --git a/gcc/testsuite/gcc.target/aarch64/sls-mitigation/sls-miti-retbr-pacret.c b/gcc/testsuite/gcc.target/aarch64/sls-mitigation/sls-miti-retbr-pacret.c -new file mode 100644 -index 000000000..7656123ee ---- /dev/null -+++ b/gcc/testsuite/gcc.target/aarch64/sls-mitigation/sls-miti-retbr-pacret.c -@@ -0,0 +1,15 @@ -+/* Avoid ILP32 since pacret is only available for LP64 */ -+/* { dg-do compile { target { ! ilp32 } } } */ -+/* { dg-additional-options "-mharden-sls=retbr -mbranch-protection=pac-ret -march=armv8.3-a" } */ -+ -+/* Testing the do_return pattern for retaa. */ -+long retbr_subcall(void); -+long retbr_do_return_retaa(void) -+{ -+ return retbr_subcall()+1; -+} -+ -+/* Ensure there are no BR or RET instructions which are not directly followed -+ by a speculation barrier. */ -+/* { dg-final { scan-assembler-not {\t(br|ret|retaa)\tx[0-9][0-9]?\n\t(?!dsb\tsy\n\tisb)} } } */ -+/* { dg-final { scan-assembler-not {ret\t} } } */ -diff --git a/gcc/testsuite/gcc.target/aarch64/sls-mitigation/sls-miti-retbr.c b/gcc/testsuite/gcc.target/aarch64/sls-mitigation/sls-miti-retbr.c -new file mode 100644 -index 000000000..573b30cdc ---- /dev/null -+++ b/gcc/testsuite/gcc.target/aarch64/sls-mitigation/sls-miti-retbr.c -@@ -0,0 +1,119 @@ -+/* We ensure that -Wpedantic is off since it complains about the trampolines -+ we explicitly want to test. */ -+/* { dg-additional-options "-mharden-sls=retbr -Wno-pedantic " } */ -+/* -+ Ensure that the SLS hardening of RET and BR leaves no unprotected RET/BR -+ instructions. -+ */ -+typedef int (foo) (int, int); -+typedef void (bar) (int, int); -+struct sls_testclass { -+ foo *x; -+ bar *y; -+ int left; -+ int right; -+}; -+ -+int -+retbr_sibcall_value_insn (struct sls_testclass x) -+{ -+ return x.x(x.left, x.right); -+} -+ -+void -+retbr_sibcall_insn (struct sls_testclass x) -+{ -+ x.y(x.left, x.right); -+} -+ -+/* Aim to test two different returns. -+ One that introduces a tail call in the middle of the function, and one that -+ has a normal return. */ -+int -+retbr_multiple_returns (struct sls_testclass x) -+{ -+ int temp; -+ if (x.left % 10) -+ return x.x(x.left, 100); -+ else if (x.right % 20) -+ { -+ return x.x(x.left * x.right, 100); -+ } -+ temp = x.left % x.right; -+ temp *= 100; -+ temp /= 2; -+ return temp % 3; -+} -+ -+void -+retbr_multiple_returns_void (struct sls_testclass x) -+{ -+ if (x.left % 10) -+ { -+ x.y(x.left, 100); -+ } -+ else if (x.right % 20) -+ { -+ x.y(x.left * x.right, 100); -+ } -+ return; -+} -+ -+/* Testing the casesi jump via register. */ -+__attribute__ ((optimize ("Os"))) -+int -+retbr_casesi_dispatch (struct sls_testclass x) -+{ -+ switch (x.left) -+ { -+ case -5: -+ return -2; -+ case -3: -+ return -1; -+ case 0: -+ return 0; -+ case 3: -+ return 1; -+ case 5: -+ break; -+ default: -+ __builtin_unreachable (); -+ } -+ return x.right; -+} -+ -+/* Testing the BR in trampolines is mitigated against. */ -+void f1 (void *); -+void f3 (void *, void (*)(void *)); -+void f2 (void *); -+ -+int -+retbr_trampolines (void *a, int b) -+{ -+ if (!b) -+ { -+ f1 (a); -+ return 1; -+ } -+ if (b) -+ { -+ void retbr_tramp_internal (void *c) -+ { -+ if (c == a) -+ f2 (c); -+ } -+ f3 (a, retbr_tramp_internal); -+ } -+ return 0; -+} -+ -+/* Testing the indirect_jump pattern. */ -+void -+retbr_indirect_jump (int *buf) -+{ -+ __builtin_longjmp(buf, 1); -+} -+ -+/* Ensure there are no BR or RET instructions which are not directly followed -+ by a speculation barrier. */ -+/* { dg-final { scan-assembler-not {\t(br|ret|retaa)\tx[0-9][0-9]?\n\t(?!dsb\tsy\n\tisb|sb)} } } */ -diff --git a/gcc/testsuite/gcc.target/aarch64/sls-mitigation/sls-mitigation.exp b/gcc/testsuite/gcc.target/aarch64/sls-mitigation/sls-mitigation.exp -new file mode 100644 -index 000000000..812250379 ---- /dev/null -+++ b/gcc/testsuite/gcc.target/aarch64/sls-mitigation/sls-mitigation.exp -@@ -0,0 +1,73 @@ -+# Regression driver for SLS mitigation on AArch64. -+# Copyright (C) 2020 Free Software Foundation, Inc. -+# Contributed by ARM Ltd. -+# -+# This file is part of GCC. -+# -+# GCC is free software; you can redistribute it and/or modify it -+# under the terms of the GNU General Public License as published by -+# the Free Software Foundation; either version 3, or (at your option) -+# any later version. -+# -+# GCC is distributed in the hope that it will be useful, but -+# WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+# General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with GCC; see the file COPYING3. If not see -+# <http://www.gnu.org/licenses/>. */ -+ -+# Exit immediately if this isn't an AArch64 target. -+if {![istarget aarch64*-*-*] } then { -+ return -+} -+ -+# Load support procs. -+load_lib gcc-dg.exp -+load_lib torture-options.exp -+ -+# If a testcase doesn't have special options, use these. -+global DEFAULT_CFLAGS -+if ![info exists DEFAULT_CFLAGS] then { -+ set DEFAULT_CFLAGS " " -+} -+ -+# Initialize `dg'. -+dg-init -+torture-init -+ -+# Use different architectures as well as the normal optimisation options. -+# (i.e. use both SB and DSB+ISB barriers). -+ -+set save-dg-do-what-default ${dg-do-what-default} -+# Main loop. -+# Run with torture tests (i.e. a bunch of different optimisation levels) just -+# to increase test coverage. -+set dg-do-what-default assemble -+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cCS\]]] \ -+ "-save-temps" $DEFAULT_CFLAGS -+ -+# Run the same tests but this time with SB extension. -+# Since not all supported assemblers will support that extension we decide -+# whether to assemble or just compile based on whether the extension is -+# supported for the available assembler. -+ -+set templist {} -+foreach x $DG_TORTURE_OPTIONS { -+ lappend templist "$x -march=armv8.3-a+sb " -+ lappend templist "$x -march=armv8-a+sb " -+} -+set-torture-options $templist -+if { [check_effective_target_aarch64_asm_sb_ok] } { -+ set dg-do-what-default assemble -+} else { -+ set dg-do-what-default compile -+} -+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cCS\]]] \ -+ "-save-temps" $DEFAULT_CFLAGS -+set dg-do-what-default ${save-dg-do-what-default} -+ -+# All done. -+torture-finish -+dg-finish -diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp -index ea9a50ccb..79482f9b6 100644 ---- a/gcc/testsuite/lib/target-supports.exp -+++ b/gcc/testsuite/lib/target-supports.exp -@@ -8579,7 +8579,8 @@ proc check_effective_target_aarch64_tiny { } { - # Create functions to check that the AArch64 assembler supports the - # various architecture extensions via the .arch_extension pseudo-op. - --foreach { aarch64_ext } { "fp" "simd" "crypto" "crc" "lse" "dotprod" "sve"} { -+foreach { aarch64_ext } { "fp" "simd" "crypto" "crc" "lse" "dotprod" "sve" -+ "sb"} { - eval [string map [list FUNC $aarch64_ext] { - proc check_effective_target_aarch64_asm_FUNC_ok { } { - if { [istarget aarch64*-*-*] } { --- -2.25.1 - diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0003-aarch64-Mitigate-SLS-for-BLR-instruction.patch b/meta/recipes-devtools/gcc/gcc-9.3/0003-aarch64-Mitigate-SLS-for-BLR-instruction.patch deleted file mode 100644 index 6dffef0a34..0000000000 --- a/meta/recipes-devtools/gcc/gcc-9.3/0003-aarch64-Mitigate-SLS-for-BLR-instruction.patch +++ /dev/null @@ -1,659 +0,0 @@ -CVE: CVE-2020-13844 -Upstream-Status: Backport -Signed-off-by: Ross Burton <ross.burton@arm.com> - -From 2155170525f93093b90a1a065e7ed71a925566e9 Mon Sep 17 00:00:00 2001 -From: Matthew Malcomson <matthew.malcomson@arm.com> -Date: Thu, 9 Jul 2020 09:11:59 +0100 -Subject: [PATCH 3/3] aarch64: Mitigate SLS for BLR instruction - -This patch introduces the mitigation for Straight Line Speculation past -the BLR instruction. - -This mitigation replaces BLR instructions with a BL to a stub which uses -a BR to jump to the original value. These function stubs are then -appended with a speculation barrier to ensure no straight line -speculation happens after these jumps. - -When optimising for speed we use a set of stubs for each function since -this should help the branch predictor make more accurate predictions -about where a stub should branch. - -When optimising for size we use one set of stubs for all functions. -This set of stubs can have human readable names, and we are using -`__call_indirect_x<N>` for register x<N>. - -When BTI branch protection is enabled the BLR instruction can jump to a -`BTI c` instruction using any register, while the BR instruction can -only jump to a `BTI c` instruction using the x16 or x17 registers. -Hence, in order to ensure this transformation is safe we mov the value -of the original register into x16 and use x16 for the BR. - -As an example when optimising for size: -a - BLR x0 -instruction would get transformed to something like - BL __call_indirect_x0 -where __call_indirect_x0 labels a thunk that contains -__call_indirect_x0: - MOV X16, X0 - BR X16 - <speculation barrier> - -The first version of this patch used local symbols specific to a -compilation unit to try and avoid relocations. -This was mistaken since functions coming from the same compilation unit -can still be in different sections, and the assembler will insert -relocations at jumps between sections. - -On any relocation the linker is permitted to emit a veneer to handle -jumps between symbols that are very far apart. The registers x16 and -x17 may be clobbered by these veneers. -Hence the function stubs cannot rely on the values of x16 and x17 being -the same as just before the function stub is called. - -Similar can be said for the hot/cold partitioning of single functions, -so function-local stubs have the same restriction. - -This updated version of the patch never emits function stubs for x16 and -x17, and instead forces other registers to be used. - -Given the above, there is now no benefit to local symbols (since they -are not enough to avoid dealing with linker intricacies). This patch -now uses global symbols with hidden visibility each stored in their own -COMDAT section. This means stubs can be shared between compilation -units while still avoiding the PLT indirection. - -This patch also removes the `__call_indirect_x30` stub (and -function-local equivalent) which would simply jump back to the original -location. - -The function-local stubs are emitted to the assembly output file in one -chunk, which means we need not add the speculation barrier directly -after each one. -This is because we know for certain that the instructions directly after -the BR in all but the last function stub will be from another one of -these stubs and hence will not contain a speculation gadget. -Instead we add a speculation barrier at the end of the sequence of -stubs. - -The global stubs are emitted in COMDAT/.linkonce sections by -themselves so that the linker can remove duplicates from multiple object -files. This means they are not emitted in one chunk, and each one must -include the speculation barrier. - -Another difference is that since the global stubs are shared across -compilation units we do not know that all functions will be targeting an -architecture supporting the SB instruction. -Rather than provide multiple stubs for each architecture, we provide a -stub that will work for all architectures -- using the DSB+ISB barrier. - -This mitigation does not apply for BLR instructions in the following -places: -- Some accesses to thread-local variables use a code sequence with a BLR - instruction. This code sequence is part of the binary interface between - compiler and linker. If this BLR instruction needs to be mitigated, it'd - probably be best to do so in the linker. It seems that the code sequence - for thread-local variable access is unlikely to lead to a Spectre Revalation - Gadget. -- PLT stubs are produced by the linker and each contain a BLR instruction. - It seems that at most only after the last PLT stub a Spectre Revalation - Gadget might appear. - -Testing: - Bootstrap and regtest on AArch64 - (with BOOT_CFLAGS="-mharden-sls=retbr,blr") - Used a temporary hack(1) in gcc-dg.exp to use these options on every - test in the testsuite, a slight modification to emit the speculation - barrier after every function stub, and a script to check that the - output never emitted a BLR, or unmitigated BR or RET instruction. - Similar on an aarch64-none-elf cross-compiler. - -1) Temporary hack emitted a speculation barrier at the end of every stub -function, and used a script to ensure that: - a) Every RET or BR is immediately followed by a speculation barrier. - b) No BLR instruction is emitted by compiler. - -(cherry picked from 96b7f495f9269d5448822e4fc28882edb35a58d7) - -gcc/ChangeLog: - - * config/aarch64/aarch64-protos.h (aarch64_indirect_call_asm): - New declaration. - * config/aarch64/aarch64.c (aarch64_regno_regclass): Handle new - stub registers class. - (aarch64_class_max_nregs): Likewise. - (aarch64_register_move_cost): Likewise. - (aarch64_sls_shared_thunks): Global array to store stub labels. - (aarch64_sls_emit_function_stub): New. - (aarch64_create_blr_label): New. - (aarch64_sls_emit_blr_function_thunks): New. - (aarch64_sls_emit_shared_blr_thunks): New. - (aarch64_asm_file_end): New. - (aarch64_indirect_call_asm): New. - (TARGET_ASM_FILE_END): Use aarch64_asm_file_end. - (TARGET_ASM_FUNCTION_EPILOGUE): Use - aarch64_sls_emit_blr_function_thunks. - * config/aarch64/aarch64.h (STB_REGNUM_P): New. - (enum reg_class): Add STUB_REGS class. - (machine_function): Introduce `call_via` array for - function-local stub labels. - * config/aarch64/aarch64.md (*call_insn, *call_value_insn): Use - aarch64_indirect_call_asm to emit code when hardening BLR - instructions. - * config/aarch64/constraints.md (Ucr): New constraint - representing registers for indirect calls. Is GENERAL_REGS - usually, and STUB_REGS when hardening BLR instruction against - SLS. - * config/aarch64/predicates.md (aarch64_general_reg): STUB_REGS class - is also a general register. - -gcc/testsuite/ChangeLog: - - * gcc.target/aarch64/sls-mitigation/sls-miti-blr-bti.c: New test. - * gcc.target/aarch64/sls-mitigation/sls-miti-blr.c: New test. ---- - gcc/config/aarch64/aarch64-protos.h | 1 + - gcc/config/aarch64/aarch64.c | 225 +++++++++++++++++- - gcc/config/aarch64/aarch64.h | 15 ++ - gcc/config/aarch64/aarch64.md | 11 +- - gcc/config/aarch64/constraints.md | 9 + - gcc/config/aarch64/predicates.md | 3 +- - .../aarch64/sls-mitigation/sls-miti-blr-bti.c | 40 ++++ - .../aarch64/sls-mitigation/sls-miti-blr.c | 33 +++ - 8 files changed, 328 insertions(+), 9 deletions(-) - create mode 100644 gcc/testsuite/gcc.target/aarch64/sls-mitigation/sls-miti-blr-bti.c - create mode 100644 gcc/testsuite/gcc.target/aarch64/sls-mitigation/sls-miti-blr.c - -diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h -index 885eae893..2676e43ae 100644 ---- a/gcc/config/aarch64/aarch64-protos.h -+++ b/gcc/config/aarch64/aarch64-protos.h -@@ -645,6 +645,7 @@ poly_uint64 aarch64_regmode_natural_size (machine_mode); - bool aarch64_high_bits_all_ones_p (HOST_WIDE_INT); - - const char *aarch64_sls_barrier (int); -+const char *aarch64_indirect_call_asm (rtx); - extern bool aarch64_harden_sls_retbr_p (void); - extern bool aarch64_harden_sls_blr_p (void); - -diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c -index dff61105c..bc6c02c3a 100644 ---- a/gcc/config/aarch64/aarch64.c -+++ b/gcc/config/aarch64/aarch64.c -@@ -8190,6 +8190,9 @@ aarch64_label_mentioned_p (rtx x) - enum reg_class - aarch64_regno_regclass (unsigned regno) - { -+ if (STUB_REGNUM_P (regno)) -+ return STUB_REGS; -+ - if (GP_REGNUM_P (regno)) - return GENERAL_REGS; - -@@ -8499,6 +8502,7 @@ aarch64_class_max_nregs (reg_class_t regclass, machine_mode mode) - unsigned int nregs; - switch (regclass) - { -+ case STUB_REGS: - case TAILCALL_ADDR_REGS: - case POINTER_REGS: - case GENERAL_REGS: -@@ -10693,10 +10697,12 @@ aarch64_register_move_cost (machine_mode mode, - = aarch64_tune_params.regmove_cost; - - /* Caller save and pointer regs are equivalent to GENERAL_REGS. */ -- if (to == TAILCALL_ADDR_REGS || to == POINTER_REGS) -+ if (to == TAILCALL_ADDR_REGS || to == POINTER_REGS -+ || to == STUB_REGS) - to = GENERAL_REGS; - -- if (from == TAILCALL_ADDR_REGS || from == POINTER_REGS) -+ if (from == TAILCALL_ADDR_REGS || from == POINTER_REGS -+ || from == STUB_REGS) - from = GENERAL_REGS; - - /* Moving between GPR and stack cost is the same as GP2GP. */ -@@ -19009,6 +19015,215 @@ aarch64_sls_barrier (int mitigation_required) - : ""; - } - -+static GTY (()) tree aarch64_sls_shared_thunks[30]; -+static GTY (()) bool aarch64_sls_shared_thunks_needed = false; -+const char *indirect_symbol_names[30] = { -+ "__call_indirect_x0", -+ "__call_indirect_x1", -+ "__call_indirect_x2", -+ "__call_indirect_x3", -+ "__call_indirect_x4", -+ "__call_indirect_x5", -+ "__call_indirect_x6", -+ "__call_indirect_x7", -+ "__call_indirect_x8", -+ "__call_indirect_x9", -+ "__call_indirect_x10", -+ "__call_indirect_x11", -+ "__call_indirect_x12", -+ "__call_indirect_x13", -+ "__call_indirect_x14", -+ "__call_indirect_x15", -+ "", /* "__call_indirect_x16", */ -+ "", /* "__call_indirect_x17", */ -+ "__call_indirect_x18", -+ "__call_indirect_x19", -+ "__call_indirect_x20", -+ "__call_indirect_x21", -+ "__call_indirect_x22", -+ "__call_indirect_x23", -+ "__call_indirect_x24", -+ "__call_indirect_x25", -+ "__call_indirect_x26", -+ "__call_indirect_x27", -+ "__call_indirect_x28", -+ "__call_indirect_x29", -+}; -+ -+/* Function to create a BLR thunk. This thunk is used to mitigate straight -+ line speculation. Instead of a simple BLR that can be speculated past, -+ we emit a BL to this thunk, and this thunk contains a BR to the relevant -+ register. These thunks have the relevant speculation barries put after -+ their indirect branch so that speculation is blocked. -+ -+ We use such a thunk so the speculation barriers are kept off the -+ architecturally executed path in order to reduce the performance overhead. -+ -+ When optimizing for size we use stubs shared by the linked object. -+ When optimizing for performance we emit stubs for each function in the hope -+ that the branch predictor can better train on jumps specific for a given -+ function. */ -+rtx -+aarch64_sls_create_blr_label (int regnum) -+{ -+ gcc_assert (STUB_REGNUM_P (regnum)); -+ if (optimize_function_for_size_p (cfun)) -+ { -+ /* For the thunks shared between different functions in this compilation -+ unit we use a named symbol -- this is just for users to more easily -+ understand the generated assembly. */ -+ aarch64_sls_shared_thunks_needed = true; -+ const char *thunk_name = indirect_symbol_names[regnum]; -+ if (aarch64_sls_shared_thunks[regnum] == NULL) -+ { -+ /* Build a decl representing this function stub and record it for -+ later. We build a decl here so we can use the GCC machinery for -+ handling sections automatically (through `get_named_section` and -+ `make_decl_one_only`). That saves us a lot of trouble handling -+ the specifics of different output file formats. */ -+ tree decl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL, -+ get_identifier (thunk_name), -+ build_function_type_list (void_type_node, -+ NULL_TREE)); -+ DECL_RESULT (decl) = build_decl (BUILTINS_LOCATION, RESULT_DECL, -+ NULL_TREE, void_type_node); -+ TREE_PUBLIC (decl) = 1; -+ TREE_STATIC (decl) = 1; -+ DECL_IGNORED_P (decl) = 1; -+ DECL_ARTIFICIAL (decl) = 1; -+ make_decl_one_only (decl, DECL_ASSEMBLER_NAME (decl)); -+ resolve_unique_section (decl, 0, false); -+ aarch64_sls_shared_thunks[regnum] = decl; -+ } -+ -+ return gen_rtx_SYMBOL_REF (Pmode, thunk_name); -+ } -+ -+ if (cfun->machine->call_via[regnum] == NULL) -+ cfun->machine->call_via[regnum] -+ = gen_rtx_LABEL_REF (Pmode, gen_label_rtx ()); -+ return cfun->machine->call_via[regnum]; -+} -+ -+/* Helper function for aarch64_sls_emit_blr_function_thunks and -+ aarch64_sls_emit_shared_blr_thunks below. */ -+static void -+aarch64_sls_emit_function_stub (FILE *out_file, int regnum) -+{ -+ /* Save in x16 and branch to that function so this transformation does -+ not prevent jumping to `BTI c` instructions. */ -+ asm_fprintf (out_file, "\tmov\tx16, x%d\n", regnum); -+ asm_fprintf (out_file, "\tbr\tx16\n"); -+} -+ -+/* Emit all BLR stubs for this particular function. -+ Here we emit all the BLR stubs needed for the current function. Since we -+ emit these stubs in a consecutive block we know there will be no speculation -+ gadgets between each stub, and hence we only emit a speculation barrier at -+ the end of the stub sequences. -+ -+ This is called in the TARGET_ASM_FUNCTION_EPILOGUE hook. */ -+void -+aarch64_sls_emit_blr_function_thunks (FILE *out_file) -+{ -+ if (! aarch64_harden_sls_blr_p ()) -+ return; -+ -+ bool any_functions_emitted = false; -+ /* We must save and restore the current function section since this assembly -+ is emitted at the end of the function. This means it can be emitted *just -+ after* the cold section of a function. That cold part would be emitted in -+ a different section. That switch would trigger a `.cfi_endproc` directive -+ to be emitted in the original section and a `.cfi_startproc` directive to -+ be emitted in the new section. Switching to the original section without -+ restoring would mean that the `.cfi_endproc` emitted as a function ends -+ would happen in a different section -- leaving an unmatched -+ `.cfi_startproc` in the cold text section and an unmatched `.cfi_endproc` -+ in the standard text section. */ -+ section *save_text_section = in_section; -+ switch_to_section (function_section (current_function_decl)); -+ for (int regnum = 0; regnum < 30; ++regnum) -+ { -+ rtx specu_label = cfun->machine->call_via[regnum]; -+ if (specu_label == NULL) -+ continue; -+ -+ targetm.asm_out.print_operand (out_file, specu_label, 0); -+ asm_fprintf (out_file, ":\n"); -+ aarch64_sls_emit_function_stub (out_file, regnum); -+ any_functions_emitted = true; -+ } -+ if (any_functions_emitted) -+ /* Can use the SB if needs be here, since this stub will only be used -+ by the current function, and hence for the current target. */ -+ asm_fprintf (out_file, "\t%s\n", aarch64_sls_barrier (true)); -+ switch_to_section (save_text_section); -+} -+ -+/* Emit shared BLR stubs for the current compilation unit. -+ Over the course of compiling this unit we may have converted some BLR -+ instructions to a BL to a shared stub function. This is where we emit those -+ stub functions. -+ This function is for the stubs shared between different functions in this -+ compilation unit. We share when optimizing for size instead of speed. -+ -+ This function is called through the TARGET_ASM_FILE_END hook. */ -+void -+aarch64_sls_emit_shared_blr_thunks (FILE *out_file) -+{ -+ if (! aarch64_sls_shared_thunks_needed) -+ return; -+ -+ for (int regnum = 0; regnum < 30; ++regnum) -+ { -+ tree decl = aarch64_sls_shared_thunks[regnum]; -+ if (!decl) -+ continue; -+ -+ const char *name = indirect_symbol_names[regnum]; -+ switch_to_section (get_named_section (decl, NULL, 0)); -+ ASM_OUTPUT_ALIGN (out_file, 2); -+ targetm.asm_out.globalize_label (out_file, name); -+ /* Only emits if the compiler is configured for an assembler that can -+ handle visibility directives. */ -+ targetm.asm_out.assemble_visibility (decl, VISIBILITY_HIDDEN); -+ ASM_OUTPUT_TYPE_DIRECTIVE (out_file, name, "function"); -+ ASM_OUTPUT_LABEL (out_file, name); -+ aarch64_sls_emit_function_stub (out_file, regnum); -+ /* Use the most conservative target to ensure it can always be used by any -+ function in the translation unit. */ -+ asm_fprintf (out_file, "\tdsb\tsy\n\tisb\n"); -+ ASM_DECLARE_FUNCTION_SIZE (out_file, name, decl); -+ } -+} -+ -+/* Implement TARGET_ASM_FILE_END. */ -+void -+aarch64_asm_file_end () -+{ -+ aarch64_sls_emit_shared_blr_thunks (asm_out_file); -+ /* Since this function will be called for the ASM_FILE_END hook, we ensure -+ that what would be called otherwise (e.g. `file_end_indicate_exec_stack` -+ for FreeBSD) still gets called. */ -+#ifdef TARGET_ASM_FILE_END -+ TARGET_ASM_FILE_END (); -+#endif -+} -+ -+const char * -+aarch64_indirect_call_asm (rtx addr) -+{ -+ gcc_assert (REG_P (addr)); -+ if (aarch64_harden_sls_blr_p ()) -+ { -+ rtx stub_label = aarch64_sls_create_blr_label (REGNO (addr)); -+ output_asm_insn ("bl\t%0", &stub_label); -+ } -+ else -+ output_asm_insn ("blr\t%0", &addr); -+ return ""; -+} -+ - /* Target-specific selftests. */ - - #if CHECKING_P -@@ -19529,6 +19744,12 @@ aarch64_libgcc_floating_mode_supported_p - #define TARGET_RUN_TARGET_SELFTESTS selftest::aarch64_run_selftests - #endif /* #if CHECKING_P */ - -+#undef TARGET_ASM_FILE_END -+#define TARGET_ASM_FILE_END aarch64_asm_file_end -+ -+#undef TARGET_ASM_FUNCTION_EPILOGUE -+#define TARGET_ASM_FUNCTION_EPILOGUE aarch64_sls_emit_blr_function_thunks -+ - struct gcc_target targetm = TARGET_INITIALIZER; - - #include "gt-aarch64.h" -diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h -index 72ddc6fd9..60682a100 100644 ---- a/gcc/config/aarch64/aarch64.h -+++ b/gcc/config/aarch64/aarch64.h -@@ -540,6 +540,16 @@ extern unsigned aarch64_architecture_version; - #define GP_REGNUM_P(REGNO) \ - (((unsigned) (REGNO - R0_REGNUM)) <= (R30_REGNUM - R0_REGNUM)) - -+/* Registers known to be preserved over a BL instruction. This consists of the -+ GENERAL_REGS without x16, x17, and x30. The x30 register is changed by the -+ BL instruction itself, while the x16 and x17 registers may be used by -+ veneers which can be inserted by the linker. */ -+#define STUB_REGNUM_P(REGNO) \ -+ (GP_REGNUM_P (REGNO) \ -+ && (REGNO) != R16_REGNUM \ -+ && (REGNO) != R17_REGNUM \ -+ && (REGNO) != R30_REGNUM) \ -+ - #define FP_REGNUM_P(REGNO) \ - (((unsigned) (REGNO - V0_REGNUM)) <= (V31_REGNUM - V0_REGNUM)) - -@@ -561,6 +571,7 @@ enum reg_class - { - NO_REGS, - TAILCALL_ADDR_REGS, -+ STUB_REGS, - GENERAL_REGS, - STACK_REG, - POINTER_REGS, -@@ -580,6 +591,7 @@ enum reg_class - { \ - "NO_REGS", \ - "TAILCALL_ADDR_REGS", \ -+ "STUB_REGS", \ - "GENERAL_REGS", \ - "STACK_REG", \ - "POINTER_REGS", \ -@@ -596,6 +608,7 @@ enum reg_class - { \ - { 0x00000000, 0x00000000, 0x00000000 }, /* NO_REGS */ \ - { 0x00030000, 0x00000000, 0x00000000 }, /* TAILCALL_ADDR_REGS */\ -+ { 0x3ffcffff, 0x00000000, 0x00000000 }, /* STUB_REGS */ \ - { 0x7fffffff, 0x00000000, 0x00000003 }, /* GENERAL_REGS */ \ - { 0x80000000, 0x00000000, 0x00000000 }, /* STACK_REG */ \ - { 0xffffffff, 0x00000000, 0x00000003 }, /* POINTER_REGS */ \ -@@ -735,6 +748,8 @@ typedef struct GTY (()) machine_function - struct aarch64_frame frame; - /* One entry for each hard register. */ - bool reg_is_wrapped_separately[LAST_SAVED_REGNUM]; -+ /* One entry for each general purpose register. */ -+ rtx call_via[SP_REGNUM]; - bool label_is_assembled; - } machine_function; - #endif -diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md -index 494aee964..ed8cf8ece 100644 ---- a/gcc/config/aarch64/aarch64.md -+++ b/gcc/config/aarch64/aarch64.md -@@ -908,15 +908,14 @@ - ) - - (define_insn "*call_insn" -- [(call (mem:DI (match_operand:DI 0 "aarch64_call_insn_operand" "r, Usf")) -+ [(call (mem:DI (match_operand:DI 0 "aarch64_call_insn_operand" "Ucr, Usf")) - (match_operand 1 "" "")) - (clobber (reg:DI LR_REGNUM))] - "" - "@ -- blr\\t%0 -+ * return aarch64_indirect_call_asm (operands[0]); - bl\\t%c0" -- [(set_attr "type" "call, call")] --) -+ [(set_attr "type" "call, call")]) - - (define_expand "call_value" - [(parallel [(set (match_operand 0 "" "") -@@ -934,12 +933,12 @@ - - (define_insn "*call_value_insn" - [(set (match_operand 0 "" "") -- (call (mem:DI (match_operand:DI 1 "aarch64_call_insn_operand" "r, Usf")) -+ (call (mem:DI (match_operand:DI 1 "aarch64_call_insn_operand" "Ucr, Usf")) - (match_operand 2 "" ""))) - (clobber (reg:DI LR_REGNUM))] - "" - "@ -- blr\\t%1 -+ * return aarch64_indirect_call_asm (operands[1]); - bl\\t%c1" - [(set_attr "type" "call, call")] - ) -diff --git a/gcc/config/aarch64/constraints.md b/gcc/config/aarch64/constraints.md -index 21f9549e6..7756dbe83 100644 ---- a/gcc/config/aarch64/constraints.md -+++ b/gcc/config/aarch64/constraints.md -@@ -24,6 +24,15 @@ - (define_register_constraint "Ucs" "TAILCALL_ADDR_REGS" - "@internal Registers suitable for an indirect tail call") - -+(define_register_constraint "Ucr" -+ "aarch64_harden_sls_blr_p () ? STUB_REGS : GENERAL_REGS" -+ "@internal Registers to be used for an indirect call. -+ This is usually the general registers, but when we are hardening against -+ Straight Line Speculation we disallow x16, x17, and x30 so we can use -+ indirection stubs. These indirection stubs cannot use the above registers -+ since they will be reached by a BL that may have to go through a linker -+ veneer.") -+ - (define_register_constraint "w" "FP_REGS" - "Floating point and SIMD vector registers.") - -diff --git a/gcc/config/aarch64/predicates.md b/gcc/config/aarch64/predicates.md -index 8e1b78421..4250aecb3 100644 ---- a/gcc/config/aarch64/predicates.md -+++ b/gcc/config/aarch64/predicates.md -@@ -32,7 +32,8 @@ - - (define_predicate "aarch64_general_reg" - (and (match_operand 0 "register_operand") -- (match_test "REGNO_REG_CLASS (REGNO (op)) == GENERAL_REGS"))) -+ (match_test "REGNO_REG_CLASS (REGNO (op)) == STUB_REGS -+ || REGNO_REG_CLASS (REGNO (op)) == GENERAL_REGS"))) - - ;; Return true if OP a (const_int 0) operand. - (define_predicate "const0_operand" -diff --git a/gcc/testsuite/gcc.target/aarch64/sls-mitigation/sls-miti-blr-bti.c b/gcc/testsuite/gcc.target/aarch64/sls-mitigation/sls-miti-blr-bti.c -new file mode 100644 -index 000000000..b1fb754c7 ---- /dev/null -+++ b/gcc/testsuite/gcc.target/aarch64/sls-mitigation/sls-miti-blr-bti.c -@@ -0,0 +1,40 @@ -+/* { dg-do compile } */ -+/* { dg-additional-options "-mharden-sls=blr -mbranch-protection=bti" } */ -+/* -+ Ensure that the SLS hardening of BLR leaves no BLR instructions. -+ Here we also check that there are no BR instructions with anything except an -+ x16 or x17 register. This is because a `BTI c` instruction can be branched -+ to using a BLR instruction using any register, but can only be branched to -+ with a BR using an x16 or x17 register. -+ */ -+typedef int (foo) (int, int); -+typedef void (bar) (int, int); -+struct sls_testclass { -+ foo *x; -+ bar *y; -+ int left; -+ int right; -+}; -+ -+/* We test both RTL patterns for a call which returns a value and a call which -+ does not. */ -+int blr_call_value (struct sls_testclass x) -+{ -+ int retval = x.x(x.left, x.right); -+ if (retval % 10) -+ return 100; -+ return 9; -+} -+ -+int blr_call (struct sls_testclass x) -+{ -+ x.y(x.left, x.right); -+ if (x.left % 10) -+ return 100; -+ return 9; -+} -+ -+/* { dg-final { scan-assembler-not {\tblr\t} } } */ -+/* { dg-final { scan-assembler-not {\tbr\tx(?!16|17)} } } */ -+/* { dg-final { scan-assembler {\tbr\tx(16|17)} } } */ -+ -diff --git a/gcc/testsuite/gcc.target/aarch64/sls-mitigation/sls-miti-blr.c b/gcc/testsuite/gcc.target/aarch64/sls-mitigation/sls-miti-blr.c -new file mode 100644 -index 000000000..88baffffe ---- /dev/null -+++ b/gcc/testsuite/gcc.target/aarch64/sls-mitigation/sls-miti-blr.c -@@ -0,0 +1,33 @@ -+/* { dg-additional-options "-mharden-sls=blr -save-temps" } */ -+/* Ensure that the SLS hardening of BLR leaves no BLR instructions. -+ We only test that all BLR instructions have been removed, not that the -+ resulting code makes sense. */ -+typedef int (foo) (int, int); -+typedef void (bar) (int, int); -+struct sls_testclass { -+ foo *x; -+ bar *y; -+ int left; -+ int right; -+}; -+ -+/* We test both RTL patterns for a call which returns a value and a call which -+ does not. */ -+int blr_call_value (struct sls_testclass x) -+{ -+ int retval = x.x(x.left, x.right); -+ if (retval % 10) -+ return 100; -+ return 9; -+} -+ -+int blr_call (struct sls_testclass x) -+{ -+ x.y(x.left, x.right); -+ if (x.left % 10) -+ return 100; -+ return 9; -+} -+ -+/* { dg-final { scan-assembler-not {\tblr\t} } } */ -+/* { dg-final { scan-assembler {\tbr\tx[0-9][0-9]?} } } */ --- -2.25.1 - diff --git a/meta/recipes-devtools/gcc/gcc-9.3.inc b/meta/recipes-devtools/gcc/gcc-9.5.inc index 1c8e3df51d..9bb41bbe24 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3.inc +++ b/meta/recipes-devtools/gcc/gcc-9.5.inc @@ -2,13 +2,13 @@ require gcc-common.inc # Third digit in PV should be incremented after a minor release -PV = "9.3.0" +PV = "9.5.0" # BINV should be incremented to a revision after a minor gcc release -BINV = "9.3.0" +BINV = "9.5.0" -FILESEXTRAPATHS =. "${FILE_DIRNAME}/gcc-9.3:${FILE_DIRNAME}/gcc-9.3/backport:" +FILESEXTRAPATHS =. "${FILE_DIRNAME}/gcc-9.5:${FILE_DIRNAME}/gcc-9.5/backport:" DEPENDS =+ "mpfr gmp libmpc zlib flex-native" NATIVEDEPS = "mpfr-native gmp-native libmpc-native zlib-native flex-native" @@ -69,16 +69,14 @@ SRC_URI = "\ file://0037-CVE-2019-14250-Check-zero-value-in-simple_object_elf.patch \ file://0038-gentypes-genmodes-Do-not-use-__LINE__-for-maintainin.patch \ file://0039-process_alt_operands-Don-t-match-user-defined-regs-o.patch \ - file://0001-aarch64-New-Straight-Line-Speculation-SLS-mitigation.patch \ - file://0002-aarch64-Introduce-SLS-mitigation-for-RET-and-BR-inst.patch \ - file://0003-aarch64-Mitigate-SLS-for-BLR-instruction.patch \ - file://0001-Backport-fix-for-PR-tree-optimization-97236-fix-bad-.patch \ + file://0002-libstdc-Fix-inconsistent-noexcept-specific-for-valar.patch \ + file://CVE-2023-4039.patch \ " S = "${TMPDIR}/work-shared/gcc-${PV}-${PR}/gcc-${PV}" -SRC_URI[sha256sum] = "71e197867611f6054aa1119b13a0c0abac12834765fe2d81f35ac57f84f742d1" +SRC_URI[sha256sum] = "27769f64ef1d4cd5e2be8682c0c93f9887983e6cfd1a927ce5a0a2915a95cf8f" # For dev release snapshotting #S = "${TMPDIR}/work-shared/gcc-${PV}-${PR}/official-gcc-${RELEASE}" -#B = "${WORKDIR}/gcc-${PV}/build.${HOST_SYS}.${TARGET_SYS}" +B = "${WORKDIR}/gcc-${PV}/build.${HOST_SYS}.${TARGET_SYS}" # Language Overrides FORTRAN = "" @@ -123,3 +121,6 @@ EXTRA_OECONF_PATHS = "\ --with-sysroot=/not/exist \ --with-build-sysroot=${STAGING_DIR_TARGET} \ " + +# Is a binutils 2.26 issue, not gcc +CVE_CHECK_WHITELIST += "CVE-2021-37322" diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0001-gcc-4.3.1-ARCH_FLAGS_FOR_TARGET.patch b/meta/recipes-devtools/gcc/gcc-9.5/0001-gcc-4.3.1-ARCH_FLAGS_FOR_TARGET.patch index 0d9222df17..0d9222df17 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0001-gcc-4.3.1-ARCH_FLAGS_FOR_TARGET.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0001-gcc-4.3.1-ARCH_FLAGS_FOR_TARGET.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0002-gcc-poison-system-directories.patch b/meta/recipes-devtools/gcc/gcc-9.5/0002-gcc-poison-system-directories.patch index f427ee67c1..f427ee67c1 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0002-gcc-poison-system-directories.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0002-gcc-poison-system-directories.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.5/0002-libstdc-Fix-inconsistent-noexcept-specific-for-valar.patch b/meta/recipes-devtools/gcc/gcc-9.5/0002-libstdc-Fix-inconsistent-noexcept-specific-for-valar.patch new file mode 100644 index 0000000000..506064bfc2 --- /dev/null +++ b/meta/recipes-devtools/gcc/gcc-9.5/0002-libstdc-Fix-inconsistent-noexcept-specific-for-valar.patch @@ -0,0 +1,44 @@ +From 60d966708d7cf105dccf128d2b7a38b0b2580a1a Mon Sep 17 00:00:00 2001 +From: Jonathan Wakely <jwakely@redhat.com> +Date: Fri, 5 Nov 2021 21:42:20 +0000 +Subject: [PATCH] libstdc++: Fix inconsistent noexcept-specific for valarray + begin/end + +These declarations should be noexcept after I added it to the +definitions in <valarray>. + +libstdc++-v3/ChangeLog: + + * include/bits/range_access.h (begin(valarray), end(valarray)): + Add noexcept. + +(cherry picked from commit 2b2d97fc545635a0f6aa9c9ee3b017394bc494bf) + +Upstream-Status: Backport [https://github.com/hkaelber/gcc/commit/2b2d97fc545635a0f6aa9c9ee3b017394bc494bf] +Signed-off-by: Virendra Thakur <virendrak@kpit.com> + +--- + libstdc++-v3/include/bits/range_access.h | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/libstdc++-v3/include/bits/range_access.h b/libstdc++-v3/include/bits/range_access.h +index 3d99ea92027..4736e75fda1 100644 +--- a/libstdc++-v3/include/bits/range_access.h ++++ b/libstdc++-v3/include/bits/range_access.h +@@ -101,10 +101,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION + + template<typename _Tp> class valarray; + // These overloads must be declared for cbegin and cend to use them. +- template<typename _Tp> _Tp* begin(valarray<_Tp>&); +- template<typename _Tp> const _Tp* begin(const valarray<_Tp>&); +- template<typename _Tp> _Tp* end(valarray<_Tp>&); +- template<typename _Tp> const _Tp* end(const valarray<_Tp>&); ++ template<typename _Tp> _Tp* begin(valarray<_Tp>&) noexcept; ++ template<typename _Tp> const _Tp* begin(const valarray<_Tp>&) noexcept; ++ template<typename _Tp> _Tp* end(valarray<_Tp>&) noexcept; ++ template<typename _Tp> const _Tp* end(const valarray<_Tp>&) noexcept; + + /** + * @brief Return an iterator pointing to the first element of +-- +2.25.1
\ No newline at end of file diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0003-gcc-4.3.3-SYSROOT_CFLAGS_FOR_TARGET.patch b/meta/recipes-devtools/gcc/gcc-9.5/0003-gcc-4.3.3-SYSROOT_CFLAGS_FOR_TARGET.patch index 23ec5bce03..23ec5bce03 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0003-gcc-4.3.3-SYSROOT_CFLAGS_FOR_TARGET.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0003-gcc-4.3.3-SYSROOT_CFLAGS_FOR_TARGET.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0004-64-bit-multilib-hack.patch b/meta/recipes-devtools/gcc/gcc-9.5/0004-64-bit-multilib-hack.patch index 17ec8986c1..17ec8986c1 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0004-64-bit-multilib-hack.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0004-64-bit-multilib-hack.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0005-optional-libstdc.patch b/meta/recipes-devtools/gcc/gcc-9.5/0005-optional-libstdc.patch index 3c28aeac63..3c28aeac63 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0005-optional-libstdc.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0005-optional-libstdc.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0006-COLLECT_GCC_OPTIONS.patch b/meta/recipes-devtools/gcc/gcc-9.5/0006-COLLECT_GCC_OPTIONS.patch index 906f3a7317..906f3a7317 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0006-COLLECT_GCC_OPTIONS.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0006-COLLECT_GCC_OPTIONS.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0007-Use-the-defaults.h-in-B-instead-of-S-and-t-oe-in-B.patch b/meta/recipes-devtools/gcc/gcc-9.5/0007-Use-the-defaults.h-in-B-instead-of-S-and-t-oe-in-B.patch index 68a876cb95..68a876cb95 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0007-Use-the-defaults.h-in-B-instead-of-S-and-t-oe-in-B.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0007-Use-the-defaults.h-in-B-instead-of-S-and-t-oe-in-B.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0008-fortran-cross-compile-hack.patch b/meta/recipes-devtools/gcc/gcc-9.5/0008-fortran-cross-compile-hack.patch index 6acd2b0cf9..6acd2b0cf9 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0008-fortran-cross-compile-hack.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0008-fortran-cross-compile-hack.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0009-cpp-honor-sysroot.patch b/meta/recipes-devtools/gcc/gcc-9.5/0009-cpp-honor-sysroot.patch index 5a9e527606..5a9e527606 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0009-cpp-honor-sysroot.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0009-cpp-honor-sysroot.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0010-MIPS64-Default-to-N64-ABI.patch b/meta/recipes-devtools/gcc/gcc-9.5/0010-MIPS64-Default-to-N64-ABI.patch index a8103b951e..a8103b951e 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0010-MIPS64-Default-to-N64-ABI.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0010-MIPS64-Default-to-N64-ABI.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0011-Define-GLIBC_DYNAMIC_LINKER-and-UCLIBC_DYNAMIC_LINKE.patch b/meta/recipes-devtools/gcc/gcc-9.5/0011-Define-GLIBC_DYNAMIC_LINKER-and-UCLIBC_DYNAMIC_LINKE.patch index d9d563d0f7..d9d563d0f7 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0011-Define-GLIBC_DYNAMIC_LINKER-and-UCLIBC_DYNAMIC_LINKE.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0011-Define-GLIBC_DYNAMIC_LINKER-and-UCLIBC_DYNAMIC_LINKE.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0012-gcc-Fix-argument-list-too-long-error.patch b/meta/recipes-devtools/gcc/gcc-9.5/0012-gcc-Fix-argument-list-too-long-error.patch index f0b79ee145..f0b79ee145 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0012-gcc-Fix-argument-list-too-long-error.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0012-gcc-Fix-argument-list-too-long-error.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0013-Disable-sdt.patch b/meta/recipes-devtools/gcc/gcc-9.5/0013-Disable-sdt.patch index 455858354f..455858354f 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0013-Disable-sdt.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0013-Disable-sdt.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0014-libtool.patch b/meta/recipes-devtools/gcc/gcc-9.5/0014-libtool.patch index 2953859238..2953859238 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0014-libtool.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0014-libtool.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0015-gcc-armv4-pass-fix-v4bx-to-linker-to-support-EABI.patch b/meta/recipes-devtools/gcc/gcc-9.5/0015-gcc-armv4-pass-fix-v4bx-to-linker-to-support-EABI.patch index d4445244e2..d4445244e2 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0015-gcc-armv4-pass-fix-v4bx-to-linker-to-support-EABI.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0015-gcc-armv4-pass-fix-v4bx-to-linker-to-support-EABI.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0016-Use-the-multilib-config-files-from-B-instead-of-usin.patch b/meta/recipes-devtools/gcc/gcc-9.5/0016-Use-the-multilib-config-files-from-B-instead-of-usin.patch index 6f0833ccda..6f0833ccda 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0016-Use-the-multilib-config-files-from-B-instead-of-usin.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0016-Use-the-multilib-config-files-from-B-instead-of-usin.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0017-Avoid-using-libdir-from-.la-which-usually-points-to-.patch b/meta/recipes-devtools/gcc/gcc-9.5/0017-Avoid-using-libdir-from-.la-which-usually-points-to-.patch index 96da013bf2..96da013bf2 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0017-Avoid-using-libdir-from-.la-which-usually-points-to-.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0017-Avoid-using-libdir-from-.la-which-usually-points-to-.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0018-export-CPP.patch b/meta/recipes-devtools/gcc/gcc-9.5/0018-export-CPP.patch index 2385099c25..2385099c25 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0018-export-CPP.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0018-export-CPP.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0019-Ensure-target-gcc-headers-can-be-included.patch b/meta/recipes-devtools/gcc/gcc-9.5/0019-Ensure-target-gcc-headers-can-be-included.patch index e0129d1f96..e0129d1f96 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0019-Ensure-target-gcc-headers-can-be-included.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0019-Ensure-target-gcc-headers-can-be-included.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0020-gcc-4.8-won-t-build-with-disable-dependency-tracking.patch b/meta/recipes-devtools/gcc/gcc-9.5/0020-gcc-4.8-won-t-build-with-disable-dependency-tracking.patch index 1d2182140f..1d2182140f 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0020-gcc-4.8-won-t-build-with-disable-dependency-tracking.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0020-gcc-4.8-won-t-build-with-disable-dependency-tracking.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0021-Don-t-search-host-directory-during-relink-if-inst_pr.patch b/meta/recipes-devtools/gcc/gcc-9.5/0021-Don-t-search-host-directory-during-relink-if-inst_pr.patch index e363c7d445..e363c7d445 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0021-Don-t-search-host-directory-during-relink-if-inst_pr.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0021-Don-t-search-host-directory-during-relink-if-inst_pr.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0022-Use-SYSTEMLIBS_DIR-replacement-instead-of-hardcoding.patch b/meta/recipes-devtools/gcc/gcc-9.5/0022-Use-SYSTEMLIBS_DIR-replacement-instead-of-hardcoding.patch index 846c0de5e8..846c0de5e8 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0022-Use-SYSTEMLIBS_DIR-replacement-instead-of-hardcoding.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0022-Use-SYSTEMLIBS_DIR-replacement-instead-of-hardcoding.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0023-aarch64-Add-support-for-musl-ldso.patch b/meta/recipes-devtools/gcc/gcc-9.5/0023-aarch64-Add-support-for-musl-ldso.patch index 102d6fc742..102d6fc742 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0023-aarch64-Add-support-for-musl-ldso.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0023-aarch64-Add-support-for-musl-ldso.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0024-libcc1-fix-libcc1-s-install-path-and-rpath.patch b/meta/recipes-devtools/gcc/gcc-9.5/0024-libcc1-fix-libcc1-s-install-path-and-rpath.patch index 443e0a2ca6..443e0a2ca6 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0024-libcc1-fix-libcc1-s-install-path-and-rpath.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0024-libcc1-fix-libcc1-s-install-path-and-rpath.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0025-handle-sysroot-support-for-nativesdk-gcc.patch b/meta/recipes-devtools/gcc/gcc-9.5/0025-handle-sysroot-support-for-nativesdk-gcc.patch index 59ac97eaed..59ac97eaed 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0025-handle-sysroot-support-for-nativesdk-gcc.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0025-handle-sysroot-support-for-nativesdk-gcc.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0026-Search-target-sysroot-gcc-version-specific-dirs-with.patch b/meta/recipes-devtools/gcc/gcc-9.5/0026-Search-target-sysroot-gcc-version-specific-dirs-with.patch index abfa7516da..abfa7516da 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0026-Search-target-sysroot-gcc-version-specific-dirs-with.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0026-Search-target-sysroot-gcc-version-specific-dirs-with.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0027-Fix-various-_FOR_BUILD-and-related-variables.patch b/meta/recipes-devtools/gcc/gcc-9.5/0027-Fix-various-_FOR_BUILD-and-related-variables.patch index ae8acc7f13..ae8acc7f13 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0027-Fix-various-_FOR_BUILD-and-related-variables.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0027-Fix-various-_FOR_BUILD-and-related-variables.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0028-nios2-Define-MUSL_DYNAMIC_LINKER.patch b/meta/recipes-devtools/gcc/gcc-9.5/0028-nios2-Define-MUSL_DYNAMIC_LINKER.patch index 52a5d97aef..52a5d97aef 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0028-nios2-Define-MUSL_DYNAMIC_LINKER.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0028-nios2-Define-MUSL_DYNAMIC_LINKER.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0029-Add-ssp_nonshared-to-link-commandline-for-musl-targe.patch b/meta/recipes-devtools/gcc/gcc-9.5/0029-Add-ssp_nonshared-to-link-commandline-for-musl-targe.patch index bfa7e19dd0..bfa7e19dd0 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0029-Add-ssp_nonshared-to-link-commandline-for-musl-targe.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0029-Add-ssp_nonshared-to-link-commandline-for-musl-targe.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0030-ldbl128-config.patch b/meta/recipes-devtools/gcc/gcc-9.5/0030-ldbl128-config.patch index f8e8c07f62..f8e8c07f62 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0030-ldbl128-config.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0030-ldbl128-config.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0031-Link-libgcc-using-LDFLAGS-not-just-SHLIB_LDFLAGS.patch b/meta/recipes-devtools/gcc/gcc-9.5/0031-Link-libgcc-using-LDFLAGS-not-just-SHLIB_LDFLAGS.patch index 60a29fc94d..60a29fc94d 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0031-Link-libgcc-using-LDFLAGS-not-just-SHLIB_LDFLAGS.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0031-Link-libgcc-using-LDFLAGS-not-just-SHLIB_LDFLAGS.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0032-libgcc_s-Use-alias-for-__cpu_indicator_init-instead-.patch b/meta/recipes-devtools/gcc/gcc-9.5/0032-libgcc_s-Use-alias-for-__cpu_indicator_init-instead-.patch index 6f048dab82..6f048dab82 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0032-libgcc_s-Use-alias-for-__cpu_indicator_init-instead-.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0032-libgcc_s-Use-alias-for-__cpu_indicator_init-instead-.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0033-sync-gcc-stddef.h-with-musl.patch b/meta/recipes-devtools/gcc/gcc-9.5/0033-sync-gcc-stddef.h-with-musl.patch index f080b0596f..f080b0596f 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0033-sync-gcc-stddef.h-with-musl.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0033-sync-gcc-stddef.h-with-musl.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0034-fix-segmentation-fault-in-precompiled-header-generat.patch b/meta/recipes-devtools/gcc/gcc-9.5/0034-fix-segmentation-fault-in-precompiled-header-generat.patch index 3b7ccb3e3d..3b7ccb3e3d 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0034-fix-segmentation-fault-in-precompiled-header-generat.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0034-fix-segmentation-fault-in-precompiled-header-generat.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0035-Fix-for-testsuite-failure.patch b/meta/recipes-devtools/gcc/gcc-9.5/0035-Fix-for-testsuite-failure.patch index 5e199fbcfd..5e199fbcfd 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0035-Fix-for-testsuite-failure.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0035-Fix-for-testsuite-failure.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0036-Re-introduce-spe-commandline-options.patch b/meta/recipes-devtools/gcc/gcc-9.5/0036-Re-introduce-spe-commandline-options.patch index 825e070aa3..825e070aa3 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0036-Re-introduce-spe-commandline-options.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0036-Re-introduce-spe-commandline-options.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0037-CVE-2019-14250-Check-zero-value-in-simple_object_elf.patch b/meta/recipes-devtools/gcc/gcc-9.5/0037-CVE-2019-14250-Check-zero-value-in-simple_object_elf.patch index f268a4eb58..f268a4eb58 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0037-CVE-2019-14250-Check-zero-value-in-simple_object_elf.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0037-CVE-2019-14250-Check-zero-value-in-simple_object_elf.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0038-gentypes-genmodes-Do-not-use-__LINE__-for-maintainin.patch b/meta/recipes-devtools/gcc/gcc-9.5/0038-gentypes-genmodes-Do-not-use-__LINE__-for-maintainin.patch index a79fc03d15..a79fc03d15 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0038-gentypes-genmodes-Do-not-use-__LINE__-for-maintainin.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0038-gentypes-genmodes-Do-not-use-__LINE__-for-maintainin.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.3/0039-process_alt_operands-Don-t-match-user-defined-regs-o.patch b/meta/recipes-devtools/gcc/gcc-9.5/0039-process_alt_operands-Don-t-match-user-defined-regs-o.patch index b69114d1e5..b69114d1e5 100644 --- a/meta/recipes-devtools/gcc/gcc-9.3/0039-process_alt_operands-Don-t-match-user-defined-regs-o.patch +++ b/meta/recipes-devtools/gcc/gcc-9.5/0039-process_alt_operands-Don-t-match-user-defined-regs-o.patch diff --git a/meta/recipes-devtools/gcc/gcc-9.5/CVE-2023-4039.patch b/meta/recipes-devtools/gcc/gcc-9.5/CVE-2023-4039.patch new file mode 100644 index 0000000000..56d229066f --- /dev/null +++ b/meta/recipes-devtools/gcc/gcc-9.5/CVE-2023-4039.patch @@ -0,0 +1,1506 @@ +From: Richard Sandiford <richard.sandiford@arm.com> +Subject: [PATCH 00/19] aarch64: Fix -fstack-protector issue +Date: Tue, 12 Sep 2023 16:25:10 +0100 + +This series of patches fixes deficiencies in GCC's -fstack-protector +implementation for AArch64 when using dynamically allocated stack space. +This is CVE-2023-4039. See: + +https://developer.arm.com/Arm%20Security%20Center/GCC%20Stack%20Protector%20Vulnerability%20AArch64 +https://github.com/metaredteam/external-disclosures/security/advisories/GHSA-x7ch-h5rf-w2mf + +for more details. + +The fix is to put the saved registers above the locals area when +-fstack-protector is used. + +The series also fixes a stack-clash problem that I found while working +on the CVE. In unpatched sources, the stack-clash problem would only +trigger for unrealistic numbers of arguments (8K 64-bit arguments, or an +equivalent). But it would be a more significant issue with the new +-fstack-protector frame layout. It's therefore important that both +problems are fixed together. + +Some reorganisation of the code seemed necessary to fix the problems in a +cleanish way. The series is therefore quite long, but only a handful of +patches should have any effect on code generation. + +See the individual patches for a detailed description. + +Tested on aarch64-linux-gnu. Pushed to trunk and to all active branches. +I've also pushed backports to GCC 7+ to vendors/ARM/heads/CVE-2023-4039. + +CVE: CVE-2023-4039 +Upstream-Status: Submitted +Signed-off-by: Ross Burton <ross.burton@arm.com> + + +From 78ebdb7b12d5e258b9811bab715734454268fd0c Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Fri, 16 Jun 2023 17:00:51 +0100 +Subject: [PATCH 01/10] aarch64: Explicitly handle frames with no saved + registers + +If a frame has no saved registers, it can be allocated in one go. +There is no need to treat the areas below and above the saved +registers as separate. + +And if we allocate the frame in one go, it should be allocated +as the initial_adjust rather than the final_adjust. This allows the +frame size to grow to guard_size - guard_used_by_caller before a stack +probe is needed. (A frame with no register saves is necessarily a +leaf frame.) + +This is a no-op as thing stand, since a leaf function will have +no outgoing arguments, and so all the frame will be above where +the saved registers normally go. + +gcc/ + * config/aarch64/aarch64.c (aarch64_layout_frame): Explicitly + allocate the frame in one go if there are no saved registers. +--- + gcc/config/aarch64/aarch64.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index a35dceab9fc..e9dad682738 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -4771,9 +4771,11 @@ aarch64_layout_frame (void) + max_push_offset = 256; + + HOST_WIDE_INT const_size, const_fp_offset; +- if (cfun->machine->frame.frame_size.is_constant (&const_size) +- && const_size < max_push_offset +- && known_eq (crtl->outgoing_args_size, 0)) ++ if (cfun->machine->frame.saved_regs_size == 0) ++ cfun->machine->frame.initial_adjust = cfun->machine->frame.frame_size; ++ else if (cfun->machine->frame.frame_size.is_constant (&const_size) ++ && const_size < max_push_offset ++ && known_eq (crtl->outgoing_args_size, 0)) + { + /* Simple, small frame with no outgoing arguments: + stp reg1, reg2, [sp, -frame_size]! +-- +2.34.1 + + +From 347487fffa0266d43bf18f1f91878410881f596e Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Fri, 16 Jun 2023 16:55:12 +0100 +Subject: [PATCH 02/10] aarch64: Add bytes_below_hard_fp to frame info + +The frame layout code currently hard-codes the assumption that +the number of bytes below the saved registers is equal to the +size of the outgoing arguments. This patch abstracts that +value into a new field of aarch64_frame. + +gcc/ + * config/aarch64/aarch64.h (aarch64_frame::bytes_below_hard_fp): New + field. + * config/aarch64/aarch64.c (aarch64_layout_frame): Initialize it, + and use it instead of crtl->outgoing_args_size. + (aarch64_get_separate_components): Use bytes_below_hard_fp instead + of outgoing_args_size. + (aarch64_process_components): Likewise. +--- + gcc/config/aarch64/aarch64.c | 50 +++++++++++++++++++----------------- + gcc/config/aarch64/aarch64.h | 6 ++++- + 2 files changed, 32 insertions(+), 24 deletions(-) + +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index e9dad682738..25cf10cc4b9 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -4684,6 +4684,8 @@ aarch64_layout_frame (void) + last_fp_reg = regno; + } + ++ cfun->machine->frame.bytes_below_hard_fp = crtl->outgoing_args_size; ++ + if (cfun->machine->frame.emit_frame_chain) + { + /* FP and LR are placed in the linkage record. */ +@@ -4751,11 +4753,11 @@ aarch64_layout_frame (void) + STACK_BOUNDARY / BITS_PER_UNIT); + + /* Both these values are already aligned. */ +- gcc_assert (multiple_p (crtl->outgoing_args_size, ++ gcc_assert (multiple_p (cfun->machine->frame.bytes_below_hard_fp, + STACK_BOUNDARY / BITS_PER_UNIT)); + cfun->machine->frame.frame_size + = (cfun->machine->frame.hard_fp_offset +- + crtl->outgoing_args_size); ++ + cfun->machine->frame.bytes_below_hard_fp); + + cfun->machine->frame.locals_offset = cfun->machine->frame.saved_varargs_size; + +@@ -4775,23 +4777,23 @@ aarch64_layout_frame (void) + cfun->machine->frame.initial_adjust = cfun->machine->frame.frame_size; + else if (cfun->machine->frame.frame_size.is_constant (&const_size) + && const_size < max_push_offset +- && known_eq (crtl->outgoing_args_size, 0)) ++ && known_eq (cfun->machine->frame.bytes_below_hard_fp, 0)) + { +- /* Simple, small frame with no outgoing arguments: ++ /* Simple, small frame with no data below the saved registers. + stp reg1, reg2, [sp, -frame_size]! + stp reg3, reg4, [sp, 16] */ + cfun->machine->frame.callee_adjust = const_size; + } +- else if (known_lt (crtl->outgoing_args_size ++ else if (known_lt (cfun->machine->frame.bytes_below_hard_fp + + cfun->machine->frame.saved_regs_size, 512) + && !(cfun->calls_alloca + && known_lt (cfun->machine->frame.hard_fp_offset, + max_push_offset))) + { +- /* Frame with small outgoing arguments: ++ /* Frame with small area below the saved registers: + sub sp, sp, frame_size +- stp reg1, reg2, [sp, outgoing_args_size] +- stp reg3, reg4, [sp, outgoing_args_size + 16] */ ++ stp reg1, reg2, [sp, bytes_below_hard_fp] ++ stp reg3, reg4, [sp, bytes_below_hard_fp + 16] */ + cfun->machine->frame.initial_adjust = cfun->machine->frame.frame_size; + cfun->machine->frame.callee_offset + = cfun->machine->frame.frame_size - cfun->machine->frame.hard_fp_offset; +@@ -4799,22 +4801,23 @@ aarch64_layout_frame (void) + else if (cfun->machine->frame.hard_fp_offset.is_constant (&const_fp_offset) + && const_fp_offset < max_push_offset) + { +- /* Frame with large outgoing arguments but a small local area: ++ /* Frame with large area below the saved registers, but with a ++ small area above: + stp reg1, reg2, [sp, -hard_fp_offset]! + stp reg3, reg4, [sp, 16] +- sub sp, sp, outgoing_args_size */ ++ sub sp, sp, bytes_below_hard_fp */ + cfun->machine->frame.callee_adjust = const_fp_offset; + cfun->machine->frame.final_adjust + = cfun->machine->frame.frame_size - cfun->machine->frame.callee_adjust; + } + else + { +- /* Frame with large local area and outgoing arguments using frame pointer: ++ /* General case: + sub sp, sp, hard_fp_offset + stp x29, x30, [sp, 0] + add x29, sp, 0 + stp reg3, reg4, [sp, 16] +- sub sp, sp, outgoing_args_size */ ++ sub sp, sp, bytes_below_hard_fp */ + cfun->machine->frame.initial_adjust = cfun->machine->frame.hard_fp_offset; + cfun->machine->frame.final_adjust + = cfun->machine->frame.frame_size - cfun->machine->frame.initial_adjust; +@@ -5243,9 +5246,11 @@ aarch64_get_separate_components (void) + if (aarch64_register_saved_on_entry (regno)) + { + poly_int64 offset = cfun->machine->frame.reg_offset[regno]; ++ ++ /* Get the offset relative to the register we'll use. */ + if (!frame_pointer_needed) +- offset += cfun->machine->frame.frame_size +- - cfun->machine->frame.hard_fp_offset; ++ offset += cfun->machine->frame.bytes_below_hard_fp; ++ + /* Check that we can access the stack slot of the register with one + direct load with no adjustments needed. */ + if (offset_12bit_unsigned_scaled_p (DImode, offset)) +@@ -5367,8 +5372,8 @@ aarch64_process_components (sbitmap components, bool prologue_p) + rtx reg = gen_rtx_REG (mode, regno); + poly_int64 offset = cfun->machine->frame.reg_offset[regno]; + if (!frame_pointer_needed) +- offset += cfun->machine->frame.frame_size +- - cfun->machine->frame.hard_fp_offset; ++ offset += cfun->machine->frame.bytes_below_hard_fp; ++ + rtx addr = plus_constant (Pmode, ptr_reg, offset); + rtx mem = gen_frame_mem (mode, addr); + +@@ -5410,8 +5415,7 @@ aarch64_process_components (sbitmap components, bool prologue_p) + /* REGNO2 can be saved/restored in a pair with REGNO. */ + rtx reg2 = gen_rtx_REG (mode, regno2); + if (!frame_pointer_needed) +- offset2 += cfun->machine->frame.frame_size +- - cfun->machine->frame.hard_fp_offset; ++ offset2 += cfun->machine->frame.bytes_below_hard_fp; + rtx addr2 = plus_constant (Pmode, ptr_reg, offset2); + rtx mem2 = gen_frame_mem (mode, addr2); + rtx set2 = prologue_p ? gen_rtx_SET (mem2, reg2) +@@ -5478,10 +5482,10 @@ aarch64_stack_clash_protection_alloca_probe_range (void) + registers. If POLY_SIZE is not large enough to require a probe this function + will only adjust the stack. When allocating the stack space + FRAME_RELATED_P is then used to indicate if the allocation is frame related. +- FINAL_ADJUSTMENT_P indicates whether we are allocating the outgoing +- arguments. If we are then we ensure that any allocation larger than the ABI +- defined buffer needs a probe so that the invariant of having a 1KB buffer is +- maintained. ++ FINAL_ADJUSTMENT_P indicates whether we are allocating the area below ++ the saved registers. If we are then we ensure that any allocation ++ larger than the ABI defined buffer needs a probe so that the ++ invariant of having a 1KB buffer is maintained. + + We emit barriers after each stack adjustment to prevent optimizations from + breaking the invariant that we never drop the stack more than a page. This +@@ -5671,7 +5675,7 @@ aarch64_allocate_and_probe_stack_space (rtx temp1, rtx temp2, + /* Handle any residuals. Residuals of at least MIN_PROBE_THRESHOLD have to + be probed. This maintains the requirement that each page is probed at + least once. For initial probing we probe only if the allocation is +- more than GUARD_SIZE - buffer, and for the outgoing arguments we probe ++ more than GUARD_SIZE - buffer, and below the saved registers we probe + if the amount is larger than buffer. GUARD_SIZE - buffer + buffer == + GUARD_SIZE. This works that for any allocation that is large enough to + trigger a probe here, we'll have at least one, and if they're not large +diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h +index af0bc3f1881..95831637ba7 100644 +--- a/gcc/config/aarch64/aarch64.h ++++ b/gcc/config/aarch64/aarch64.h +@@ -712,9 +712,13 @@ struct GTY (()) aarch64_frame + HOST_WIDE_INT saved_varargs_size; + + /* The size of the saved callee-save int/FP registers. */ +- + HOST_WIDE_INT saved_regs_size; + ++ /* The number of bytes between the bottom of the static frame (the bottom ++ of the outgoing arguments) and the hard frame pointer. This value is ++ always a multiple of STACK_BOUNDARY. */ ++ poly_int64 bytes_below_hard_fp; ++ + /* Offset from the base of the frame (incomming SP) to the + top of the locals area. This value is always a multiple of + STACK_BOUNDARY. */ +-- +2.34.1 + + +From 4604c4cd0a6c4c26d6594ec9a0383b4d9197d9df Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Tue, 27 Jun 2023 11:25:40 +0100 +Subject: [PATCH 03/10] aarch64: Rename locals_offset to bytes_above_locals +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +locals_offset was described as: + + /* Offset from the base of the frame (incomming SP) to the + top of the locals area. This value is always a multiple of + STACK_BOUNDARY. */ + +This is implicitly an “upside down” view of the frame: the incoming +SP is at offset 0, and anything N bytes below the incoming SP is at +offset N (rather than -N). + +However, reg_offset instead uses a “right way up” view; that is, +it views offsets in address terms. Something above X is at a +positive offset from X and something below X is at a negative +offset from X. + +Also, even on FRAME_GROWS_DOWNWARD targets like AArch64, +target-independent code views offsets in address terms too: +locals are allocated at negative offsets to virtual_stack_vars. + +It seems confusing to have *_offset fields of the same structure +using different polarities like this. This patch tries to avoid +that by renaming locals_offset to bytes_above_locals. + +gcc/ + * config/aarch64/aarch64.h (aarch64_frame::locals_offset): Rename to... + (aarch64_frame::bytes_above_locals): ...this. + * config/aarch64/aarch64.c (aarch64_layout_frame) + (aarch64_initial_elimination_offset): Update accordingly. +--- + gcc/config/aarch64/aarch64.c | 9 +++++---- + gcc/config/aarch64/aarch64.h | 6 +++--- + 2 files changed, 8 insertions(+), 7 deletions(-) + +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index 25cf10cc4b9..dcaf491af42 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -4759,7 +4759,8 @@ aarch64_layout_frame (void) + = (cfun->machine->frame.hard_fp_offset + + cfun->machine->frame.bytes_below_hard_fp); + +- cfun->machine->frame.locals_offset = cfun->machine->frame.saved_varargs_size; ++ cfun->machine->frame.bytes_above_locals ++ = cfun->machine->frame.saved_varargs_size; + + cfun->machine->frame.initial_adjust = 0; + cfun->machine->frame.final_adjust = 0; +@@ -8566,14 +8567,14 @@ aarch64_initial_elimination_offset (unsigned from, unsigned to) + + if (from == FRAME_POINTER_REGNUM) + return cfun->machine->frame.hard_fp_offset +- - cfun->machine->frame.locals_offset; ++ - cfun->machine->frame.bytes_above_locals; + } + + if (to == STACK_POINTER_REGNUM) + { + if (from == FRAME_POINTER_REGNUM) +- return cfun->machine->frame.frame_size +- - cfun->machine->frame.locals_offset; ++ return cfun->machine->frame.frame_size ++ - cfun->machine->frame.bytes_above_locals; + } + + return cfun->machine->frame.frame_size; +diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h +index 95831637ba7..a079a88b4f4 100644 +--- a/gcc/config/aarch64/aarch64.h ++++ b/gcc/config/aarch64/aarch64.h +@@ -719,10 +719,10 @@ struct GTY (()) aarch64_frame + always a multiple of STACK_BOUNDARY. */ + poly_int64 bytes_below_hard_fp; + +- /* Offset from the base of the frame (incomming SP) to the +- top of the locals area. This value is always a multiple of ++ /* The number of bytes between the top of the locals area and the top ++ of the frame (the incomming SP). This value is always a multiple of + STACK_BOUNDARY. */ +- poly_int64 locals_offset; ++ poly_int64 bytes_above_locals; + + /* Offset from the base of the frame (incomming SP) to the + hard_frame_pointer. This value is always a multiple of +-- +2.34.1 + + +From 16016465ff28a75f5e0540cbaeb4eb102fdc3230 Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Tue, 27 Jun 2023 11:28:11 +0100 +Subject: [PATCH 04/10] aarch64: Rename hard_fp_offset to bytes_above_hard_fp +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Similarly to the previous locals_offset patch, hard_fp_offset +was described as: + + /* Offset from the base of the frame (incomming SP) to the + hard_frame_pointer. This value is always a multiple of + STACK_BOUNDARY. */ + poly_int64 hard_fp_offset; + +which again took an “upside-down” view: higher offsets meant lower +addresses. This patch renames the field to bytes_above_hard_fp instead. + +gcc/ + * config/aarch64/aarch64.h (aarch64_frame::hard_fp_offset): Rename + to... + (aarch64_frame::bytes_above_hard_fp): ...this. + * config/aarch64/aarch64.c (aarch64_layout_frame) + (aarch64_expand_prologue): Update accordingly. + (aarch64_initial_elimination_offset): Likewise. +--- + gcc/config/aarch64/aarch64.c | 21 +++++++++++---------- + gcc/config/aarch64/aarch64.h | 6 +++--- + 2 files changed, 14 insertions(+), 13 deletions(-) + +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index dcaf491af42..2681e0c2bb9 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -4747,7 +4747,7 @@ aarch64_layout_frame (void) + HOST_WIDE_INT varargs_and_saved_regs_size + = offset + cfun->machine->frame.saved_varargs_size; + +- cfun->machine->frame.hard_fp_offset ++ cfun->machine->frame.bytes_above_hard_fp + = aligned_upper_bound (varargs_and_saved_regs_size + + get_frame_size (), + STACK_BOUNDARY / BITS_PER_UNIT); +@@ -4756,7 +4756,7 @@ aarch64_layout_frame (void) + gcc_assert (multiple_p (cfun->machine->frame.bytes_below_hard_fp, + STACK_BOUNDARY / BITS_PER_UNIT)); + cfun->machine->frame.frame_size +- = (cfun->machine->frame.hard_fp_offset ++ = (cfun->machine->frame.bytes_above_hard_fp + + cfun->machine->frame.bytes_below_hard_fp); + + cfun->machine->frame.bytes_above_locals +@@ -4788,7 +4788,7 @@ aarch64_layout_frame (void) + else if (known_lt (cfun->machine->frame.bytes_below_hard_fp + + cfun->machine->frame.saved_regs_size, 512) + && !(cfun->calls_alloca +- && known_lt (cfun->machine->frame.hard_fp_offset, ++ && known_lt (cfun->machine->frame.bytes_above_hard_fp, + max_push_offset))) + { + /* Frame with small area below the saved registers: +@@ -4797,14 +4797,14 @@ aarch64_layout_frame (void) + stp reg3, reg4, [sp, bytes_below_hard_fp + 16] */ + cfun->machine->frame.initial_adjust = cfun->machine->frame.frame_size; + cfun->machine->frame.callee_offset +- = cfun->machine->frame.frame_size - cfun->machine->frame.hard_fp_offset; ++ = cfun->machine->frame.frame_size - cfun->machine->frame.bytes_above_hard_fp; + } +- else if (cfun->machine->frame.hard_fp_offset.is_constant (&const_fp_offset) ++ else if (cfun->machine->frame.bytes_above_hard_fp.is_constant (&const_fp_offset) + && const_fp_offset < max_push_offset) + { + /* Frame with large area below the saved registers, but with a + small area above: +- stp reg1, reg2, [sp, -hard_fp_offset]! ++ stp reg1, reg2, [sp, -bytes_above_hard_fp]! + stp reg3, reg4, [sp, 16] + sub sp, sp, bytes_below_hard_fp */ + cfun->machine->frame.callee_adjust = const_fp_offset; +@@ -4814,12 +4814,13 @@ aarch64_layout_frame (void) + else + { + /* General case: +- sub sp, sp, hard_fp_offset ++ sub sp, sp, bytes_above_hard_fp + stp x29, x30, [sp, 0] + add x29, sp, 0 + stp reg3, reg4, [sp, 16] + sub sp, sp, bytes_below_hard_fp */ +- cfun->machine->frame.initial_adjust = cfun->machine->frame.hard_fp_offset; ++ cfun->machine->frame.initial_adjust ++ = cfun->machine->frame.bytes_above_hard_fp; + cfun->machine->frame.final_adjust + = cfun->machine->frame.frame_size - cfun->machine->frame.initial_adjust; + } +@@ -8563,10 +8564,10 @@ aarch64_initial_elimination_offset (unsigned from, unsigned to) + if (to == HARD_FRAME_POINTER_REGNUM) + { + if (from == ARG_POINTER_REGNUM) +- return cfun->machine->frame.hard_fp_offset; ++ return cfun->machine->frame.bytes_above_hard_fp; + + if (from == FRAME_POINTER_REGNUM) +- return cfun->machine->frame.hard_fp_offset ++ return cfun->machine->frame.bytes_above_hard_fp + - cfun->machine->frame.bytes_above_locals; + } + +diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h +index a079a88b4f4..eab6da84a02 100644 +--- a/gcc/config/aarch64/aarch64.h ++++ b/gcc/config/aarch64/aarch64.h +@@ -724,10 +724,10 @@ struct GTY (()) aarch64_frame + STACK_BOUNDARY. */ + poly_int64 bytes_above_locals; + +- /* Offset from the base of the frame (incomming SP) to the +- hard_frame_pointer. This value is always a multiple of ++ /* The number of bytes between the hard_frame_pointer and the top of ++ the frame (the incomming SP). This value is always a multiple of + STACK_BOUNDARY. */ +- poly_int64 hard_fp_offset; ++ poly_int64 bytes_above_hard_fp; + + /* The size of the frame. This value is the offset from base of the + frame (incomming SP) to the stack_pointer. This value is always +-- +2.34.1 + + +From eb2271eb6bb68ec3c9aa9ae4746ea1ee5f18874a Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Thu, 22 Jun 2023 22:26:30 +0100 +Subject: [PATCH 05/10] aarch64: Tweak frame_size comment +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch fixes another case in which a value was described with +an “upside-down” view. + +gcc/ + * config/aarch64/aarch64.h (aarch64_frame::frame_size): Tweak comment. +--- + gcc/config/aarch64/aarch64.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h +index eab6da84a02..7c4b65ec55b 100644 +--- a/gcc/config/aarch64/aarch64.h ++++ b/gcc/config/aarch64/aarch64.h +@@ -729,8 +729,8 @@ struct GTY (()) aarch64_frame + STACK_BOUNDARY. */ + poly_int64 bytes_above_hard_fp; + +- /* The size of the frame. This value is the offset from base of the +- frame (incomming SP) to the stack_pointer. This value is always ++ /* The size of the frame, i.e. the number of bytes between the bottom ++ of the outgoing arguments and the incoming SP. This value is always + a multiple of STACK_BOUNDARY. */ + poly_int64 frame_size; + +-- +2.34.1 + + +From cfed3b87e9351edff1568ade4ef666edc9887639 Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Tue, 15 Aug 2023 19:05:30 +0100 +Subject: [PATCH 06/10] Backport check-function-bodies support + +--- + gcc/testsuite/lib/scanasm.exp | 191 ++++++++++++++++++++++++++++++++++ + 1 file changed, 191 insertions(+) + +diff --git a/gcc/testsuite/lib/scanasm.exp b/gcc/testsuite/lib/scanasm.exp +index 35ccbc86fc0..c9af27bf47a 100644 +--- a/gcc/testsuite/lib/scanasm.exp ++++ b/gcc/testsuite/lib/scanasm.exp +@@ -546,3 +546,194 @@ proc scan-lto-assembler { args } { + verbose "output_file: $output_file" + dg-scan "scan-lto-assembler" 1 $testcase $output_file $args + } ++ ++# Read assembly file FILENAME and store a mapping from function names ++# to function bodies in array RESULT. FILENAME has already been uploaded ++# locally where necessary and is known to exist. ++ ++proc parse_function_bodies { filename result } { ++ upvar $result up_result ++ ++ # Regexp for the start of a function definition (name in \1). ++ set label {^([a-zA-Z_]\S+):$} ++ ++ # Regexp for the end of a function definition. ++ set terminator {^\s*\.size} ++ ++ # Regexp for lines that aren't interesting. ++ set fluff {^\s*(?:\.|//|@|$)} ++ ++ set fd [open $filename r] ++ set in_function 0 ++ while { [gets $fd line] >= 0 } { ++ if { [regexp $label $line dummy function_name] } { ++ set in_function 1 ++ set function_body "" ++ } elseif { $in_function } { ++ if { [regexp $terminator $line] } { ++ set up_result($function_name) $function_body ++ set in_function 0 ++ } elseif { ![regexp $fluff $line] } { ++ append function_body $line "\n" ++ } ++ } ++ } ++ close $fd ++} ++ ++# FUNCTIONS is an array that maps function names to function bodies. ++# Return true if it contains a definition of function NAME and if ++# that definition matches BODY_REGEXP. ++ ++proc check_function_body { functions name body_regexp } { ++ upvar $functions up_functions ++ ++ if { ![info exists up_functions($name)] } { ++ return 0 ++ } ++ set fn_res [regexp "^$body_regexp\$" $up_functions($name)] ++ if { !$fn_res } { ++ verbose -log "body: $body_regexp" ++ verbose -log "against: $up_functions($name)" ++ } ++ return $fn_res ++} ++ ++# Check the implementations of functions against expected output. Used as: ++# ++# { dg-do { check-function-bodies PREFIX TERMINATOR[ OPTION[ SELECTOR]] } } ++# ++# See sourcebuild.texi for details. ++ ++proc check-function-bodies { args } { ++ if { [llength $args] < 2 } { ++ error "too few arguments to check-function-bodies" ++ } ++ if { [llength $args] > 4 } { ++ error "too many arguments to check-function-bodies" ++ } ++ ++ if { [llength $args] >= 3 } { ++ set required_flags [lindex $args 2] ++ ++ upvar 2 dg-extra-tool-flags extra_tool_flags ++ set flags $extra_tool_flags ++ ++ global torture_current_flags ++ if { [info exists torture_current_flags] } { ++ append flags " " $torture_current_flags ++ } ++ foreach required_flag $required_flags { ++ switch -- $required_flag { ++ target - ++ xfail { ++ error "misplaced $required_flag in check-function-bodies" ++ } ++ } ++ } ++ foreach required_flag $required_flags { ++ if { ![regexp " $required_flag " $flags] } { ++ return ++ } ++ } ++ } ++ ++ set xfail_all 0 ++ if { [llength $args] >= 4 } { ++ switch [dg-process-target [lindex $args 3]] { ++ "S" { } ++ "N" { return } ++ "F" { set xfail_all 1 } ++ "P" { } ++ } ++ } ++ ++ set testcase [testname-for-summary] ++ # The name might include a list of options; extract the file name. ++ set filename [lindex $testcase 0] ++ ++ global srcdir ++ set input_filename "$srcdir/$filename" ++ set output_filename "[file rootname [file tail $filename]].s" ++ ++ set prefix [lindex $args 0] ++ set prefix_len [string length $prefix] ++ set terminator [lindex $args 1] ++ if { [string equal $terminator ""] } { ++ set terminator "*/" ++ } ++ set terminator_len [string length $terminator] ++ ++ set have_bodies 0 ++ if { [is_remote host] } { ++ remote_upload host "$filename" ++ } ++ if { [file exists $output_filename] } { ++ parse_function_bodies $output_filename functions ++ set have_bodies 1 ++ } else { ++ verbose -log "$testcase: output file does not exist" ++ } ++ ++ set count 0 ++ set function_regexp "" ++ set label {^(\S+):$} ++ ++ set lineno 1 ++ set fd [open $input_filename r] ++ set in_function 0 ++ while { [gets $fd line] >= 0 } { ++ if { [string equal -length $prefix_len $line $prefix] } { ++ set line [string trim [string range $line $prefix_len end]] ++ if { !$in_function } { ++ if { [regexp "^(.*?\\S)\\s+{(.*)}\$" $line dummy \ ++ line selector] } { ++ set selector [dg-process-target $selector] ++ } else { ++ set selector "P" ++ } ++ if { ![regexp $label $line dummy function_name] } { ++ close $fd ++ error "check-function-bodies: line $lineno does not have a function label" ++ } ++ set in_function 1 ++ set function_regexp "" ++ } elseif { [string equal $line "("] } { ++ append function_regexp "(?:" ++ } elseif { [string equal $line "|"] } { ++ append function_regexp "|" ++ } elseif { [string equal $line ")"] } { ++ append function_regexp ")" ++ } elseif { [string equal $line "..."] } { ++ append function_regexp ".*" ++ } else { ++ append function_regexp "\t" $line "\n" ++ } ++ } elseif { [string equal -length $terminator_len $line $terminator] } { ++ if { ![string equal $selector "N"] } { ++ if { $xfail_all || [string equal $selector "F"] } { ++ setup_xfail "*-*-*" ++ } ++ set testname "$testcase check-function-bodies $function_name" ++ if { !$have_bodies } { ++ unresolved $testname ++ } elseif { [check_function_body functions $function_name \ ++ $function_regexp] } { ++ pass $testname ++ } else { ++ fail $testname ++ } ++ } ++ set in_function 0 ++ incr count ++ } ++ incr lineno ++ } ++ close $fd ++ if { $in_function } { ++ error "check-function-bodies: missing \"$terminator\"" ++ } ++ if { $count == 0 } { ++ error "check-function-bodies: no matches found" ++ } ++} +-- +2.34.1 + + +From 4dd8925d95d3d6d89779b494b5f4cfadcf9fa96e Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Tue, 27 Jun 2023 15:11:44 +0100 +Subject: [PATCH 07/10] aarch64: Tweak stack clash boundary condition + +The AArch64 ABI says that, when stack clash protection is used, +there can be a maximum of 1KiB of unprobed space at sp on entry +to a function. Therefore, we need to probe when allocating +>= guard_size - 1KiB of data (>= rather than >). This is what +GCC does. + +If an allocation is exactly guard_size bytes, it is enough to allocate +those bytes and probe once at offset 1024. It isn't possible to use a +single probe at any other offset: higher would conmplicate later code, +by leaving more unprobed space than usual, while lower would risk +leaving an entire page unprobed. For simplicity, the code probes all +allocations at offset 1024. + +Some register saves also act as probes. If we need to allocate +more space below the last such register save probe, we need to +probe the allocation if it is > 1KiB. Again, this allocation is +then sometimes (but not always) probed at offset 1024. This sort of +allocation is currently only used for outgoing arguments, which are +rarely this big. + +However, the code also probed if this final outgoing-arguments +allocation was == 1KiB, rather than just > 1KiB. This isn't +necessary, since the register save then probes at offset 1024 +as required. Continuing to probe allocations of exactly 1KiB +would complicate later patches. + +gcc/ + * config/aarch64/aarch64.c (aarch64_allocate_and_probe_stack_space): + Don't probe final allocations that are exactly 1KiB in size (after + unprobed space above the final allocation has been deducted). + +gcc/testsuite/ + * gcc.target/aarch64/stack-check-prologue-17.c: New test. +--- + gcc/config/aarch64/aarch64.c | 6 +- + .../aarch64/stack-check-prologue-17.c | 55 +++++++++++++++++++ + 2 files changed, 60 insertions(+), 1 deletion(-) + create mode 100644 gcc/testsuite/gcc.target/aarch64/stack-check-prologue-17.c + +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index 2681e0c2bb9..4c9e11cd7cf 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -5506,6 +5506,8 @@ aarch64_allocate_and_probe_stack_space (rtx temp1, rtx temp2, + HOST_WIDE_INT guard_size + = 1 << PARAM_VALUE (PARAM_STACK_CLASH_PROTECTION_GUARD_SIZE); + HOST_WIDE_INT guard_used_by_caller = STACK_CLASH_CALLER_GUARD; ++ HOST_WIDE_INT byte_sp_alignment = STACK_BOUNDARY / BITS_PER_UNIT; ++ gcc_assert (multiple_p (poly_size, byte_sp_alignment)); + /* When doing the final adjustment for the outgoing argument size we can't + assume that LR was saved at position 0. So subtract it's offset from the + ABI safe buffer so that we don't accidentally allow an adjustment that +@@ -5513,7 +5515,9 @@ aarch64_allocate_and_probe_stack_space (rtx temp1, rtx temp2, + probing. */ + HOST_WIDE_INT min_probe_threshold + = final_adjustment_p +- ? guard_used_by_caller - cfun->machine->frame.reg_offset[LR_REGNUM] ++ ? (guard_used_by_caller ++ + byte_sp_alignment ++ - cfun->machine->frame.reg_offset[LR_REGNUM]) + : guard_size - guard_used_by_caller; + + poly_int64 frame_size = cfun->machine->frame.frame_size; +diff --git a/gcc/testsuite/gcc.target/aarch64/stack-check-prologue-17.c b/gcc/testsuite/gcc.target/aarch64/stack-check-prologue-17.c +new file mode 100644 +index 00000000000..0d8a25d73a2 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/stack-check-prologue-17.c +@@ -0,0 +1,55 @@ ++/* { dg-options "-O2 -fstack-clash-protection -fomit-frame-pointer --param stack-clash-protection-guard-size=12" } */ ++/* { dg-final { check-function-bodies "**" "" } } */ ++ ++void f(int, ...); ++void g(); ++ ++/* ++** test1: ++** ... ++** str x30, \[sp\] ++** sub sp, sp, #1024 ++** cbnz w0, .* ++** bl g ++** ... ++*/ ++int test1(int z) { ++ __uint128_t x = 0; ++ int y[0x400]; ++ if (z) ++ { ++ f(0, 0, 0, 0, 0, 0, 0, &y, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x); ++ } ++ g(); ++ return 1; ++} ++ ++/* ++** test2: ++** ... ++** str x30, \[sp\] ++** sub sp, sp, #1040 ++** str xzr, \[sp\] ++** cbnz w0, .* ++** bl g ++** ... ++*/ ++int test2(int z) { ++ __uint128_t x = 0; ++ int y[0x400]; ++ if (z) ++ { ++ f(0, 0, 0, 0, 0, 0, 0, &y, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x); ++ } ++ g(); ++ return 1; ++} +-- +2.34.1 + + +From 12517baf6c88447e3bda3a459ac4c29d61f84e6c Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Tue, 27 Jun 2023 15:12:55 +0100 +Subject: [PATCH 08/10] aarch64: Put LR save probe in first 16 bytes + +-fstack-clash-protection uses the save of LR as a probe for the next +allocation. The next allocation could be: + +* another part of the static frame, e.g. when allocating SVE save slots + or outgoing arguments + +* an alloca in the same function + +* an allocation made by a callee function + +However, when -fomit-frame-pointer is used, the LR save slot is placed +above the other GPR save slots. It could therefore be up to 80 bytes +above the base of the GPR save area (which is also the hard fp address). + +aarch64_allocate_and_probe_stack_space took this into account when +deciding how much subsequent space could be allocated without needing +a probe. However, it interacted badly with: + + /* If doing a small final adjustment, we always probe at offset 0. + This is done to avoid issues when LR is not at position 0 or when + the final adjustment is smaller than the probing offset. */ + else if (final_adjustment_p && rounded_size == 0) + residual_probe_offset = 0; + +which forces any allocation that is smaller than the guard page size +to be probed at offset 0 rather than the usual offset 1024. It was +therefore possible to construct cases in which we had: + +* a probe using LR at SP + 80 bytes (or some other value >= 16) +* an allocation of the guard page size - 16 bytes +* a probe at SP + 0 + +which allocates guard page size + 64 consecutive unprobed bytes. + +This patch requires the LR probe to be in the first 16 bytes of the +save area when stack clash protection is active. Doing it +unconditionally would cause code-quality regressions. + +gcc/ + * config/aarch64/aarch64.c (aarch64_layout_frame): Ensure that + the LR save slot is in the first 16 bytes of the register save area. + (aarch64_allocate_and_probe_stack_space): Remove workaround for + when LR was not in the first 16 bytes. + +gcc/testsuite/ + * gcc.target/aarch64/stack-check-prologue-18.c: New test. +--- + gcc/config/aarch64/aarch64.c | 50 +++++---- + .../aarch64/stack-check-prologue-18.c | 100 ++++++++++++++++++ + 2 files changed, 127 insertions(+), 23 deletions(-) + create mode 100644 gcc/testsuite/gcc.target/aarch64/stack-check-prologue-18.c + +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index 4c9e11cd7cf..1e8467fdd03 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -4686,15 +4686,31 @@ aarch64_layout_frame (void) + + cfun->machine->frame.bytes_below_hard_fp = crtl->outgoing_args_size; + ++#define ALLOCATE_GPR_SLOT(REGNO) \ ++ do \ ++ { \ ++ cfun->machine->frame.reg_offset[REGNO] = offset; \ ++ if (cfun->machine->frame.wb_candidate1 == INVALID_REGNUM) \ ++ cfun->machine->frame.wb_candidate1 = (REGNO); \ ++ else if (cfun->machine->frame.wb_candidate2 == INVALID_REGNUM) \ ++ cfun->machine->frame.wb_candidate2 = (REGNO); \ ++ offset += UNITS_PER_WORD; \ ++ } \ ++ while (0) ++ + if (cfun->machine->frame.emit_frame_chain) + { + /* FP and LR are placed in the linkage record. */ +- cfun->machine->frame.reg_offset[R29_REGNUM] = 0; +- cfun->machine->frame.wb_candidate1 = R29_REGNUM; +- cfun->machine->frame.reg_offset[R30_REGNUM] = UNITS_PER_WORD; +- cfun->machine->frame.wb_candidate2 = R30_REGNUM; +- offset = 2 * UNITS_PER_WORD; ++ ALLOCATE_GPR_SLOT (R29_REGNUM); ++ ALLOCATE_GPR_SLOT (R30_REGNUM); + } ++ else if (flag_stack_clash_protection ++ && cfun->machine->frame.reg_offset[R30_REGNUM] == SLOT_REQUIRED) ++ /* Put the LR save slot first, since it makes a good choice of probe ++ for stack clash purposes. The idea is that the link register usually ++ has to be saved before a call anyway, and so we lose little by ++ stopping it from being individually shrink-wrapped. */ ++ ALLOCATE_GPR_SLOT (R30_REGNUM); + + /* With stack-clash, LR must be saved in non-leaf functions. */ + gcc_assert (crtl->is_leaf +@@ -4704,14 +4720,9 @@ aarch64_layout_frame (void) + /* Now assign stack slots for them. */ + for (regno = R0_REGNUM; regno <= R30_REGNUM; regno++) + if (cfun->machine->frame.reg_offset[regno] == SLOT_REQUIRED) +- { +- cfun->machine->frame.reg_offset[regno] = offset; +- if (cfun->machine->frame.wb_candidate1 == INVALID_REGNUM) +- cfun->machine->frame.wb_candidate1 = regno; +- else if (cfun->machine->frame.wb_candidate2 == INVALID_REGNUM) +- cfun->machine->frame.wb_candidate2 = regno; +- offset += UNITS_PER_WORD; +- } ++ ALLOCATE_GPR_SLOT (regno); ++ ++#undef ALLOCATE_GPR_SLOT + + HOST_WIDE_INT max_int_offset = offset; + offset = ROUND_UP (offset, STACK_BOUNDARY / BITS_PER_UNIT); +@@ -5508,16 +5519,9 @@ aarch64_allocate_and_probe_stack_space (rtx temp1, rtx temp2, + HOST_WIDE_INT guard_used_by_caller = STACK_CLASH_CALLER_GUARD; + HOST_WIDE_INT byte_sp_alignment = STACK_BOUNDARY / BITS_PER_UNIT; + gcc_assert (multiple_p (poly_size, byte_sp_alignment)); +- /* When doing the final adjustment for the outgoing argument size we can't +- assume that LR was saved at position 0. So subtract it's offset from the +- ABI safe buffer so that we don't accidentally allow an adjustment that +- would result in an allocation larger than the ABI buffer without +- probing. */ + HOST_WIDE_INT min_probe_threshold + = final_adjustment_p +- ? (guard_used_by_caller +- + byte_sp_alignment +- - cfun->machine->frame.reg_offset[LR_REGNUM]) ++ ? guard_used_by_caller + byte_sp_alignment + : guard_size - guard_used_by_caller; + + poly_int64 frame_size = cfun->machine->frame.frame_size; +@@ -5697,8 +5701,8 @@ aarch64_allocate_and_probe_stack_space (rtx temp1, rtx temp2, + if (final_adjustment_p && rounded_size != 0) + min_probe_threshold = 0; + /* If doing a small final adjustment, we always probe at offset 0. +- This is done to avoid issues when LR is not at position 0 or when +- the final adjustment is smaller than the probing offset. */ ++ This is done to avoid issues when the final adjustment is smaller ++ than the probing offset. */ + else if (final_adjustment_p && rounded_size == 0) + residual_probe_offset = 0; + +diff --git a/gcc/testsuite/gcc.target/aarch64/stack-check-prologue-18.c b/gcc/testsuite/gcc.target/aarch64/stack-check-prologue-18.c +new file mode 100644 +index 00000000000..82447d20fff +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/stack-check-prologue-18.c +@@ -0,0 +1,100 @@ ++/* { dg-options "-O2 -fstack-clash-protection -fomit-frame-pointer --param stack-clash-protection-guard-size=12" } */ ++/* { dg-final { check-function-bodies "**" "" } } */ ++ ++void f(int, ...); ++void g(); ++ ++/* ++** test1: ++** ... ++** str x30, \[sp\] ++** sub sp, sp, #4064 ++** str xzr, \[sp\] ++** cbnz w0, .* ++** bl g ++** ... ++** str x26, \[sp, #?4128\] ++** ... ++*/ ++int test1(int z) { ++ __uint128_t x = 0; ++ int y[0x400]; ++ if (z) ++ { ++ asm volatile ("" ::: ++ "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26"); ++ f(0, 0, 0, 0, 0, 0, 0, &y, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x); ++ } ++ g(); ++ return 1; ++} ++ ++/* ++** test2: ++** ... ++** str x30, \[sp\] ++** sub sp, sp, #1040 ++** str xzr, \[sp\] ++** cbnz w0, .* ++** bl g ++** ... ++*/ ++int test2(int z) { ++ __uint128_t x = 0; ++ int y[0x400]; ++ if (z) ++ { ++ asm volatile ("" ::: ++ "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26"); ++ f(0, 0, 0, 0, 0, 0, 0, &y, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x); ++ } ++ g(); ++ return 1; ++} ++ ++/* ++** test3: ++** ... ++** str x30, \[sp\] ++** sub sp, sp, #1024 ++** cbnz w0, .* ++** bl g ++** ... ++*/ ++int test3(int z) { ++ __uint128_t x = 0; ++ int y[0x400]; ++ if (z) ++ { ++ asm volatile ("" ::: ++ "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26"); ++ f(0, 0, 0, 0, 0, 0, 0, &y, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x); ++ } ++ g(); ++ return 1; ++} +-- +2.34.1 + + +From f2684e63652bb251d22c79e40081c646df1f36b6 Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Tue, 8 Aug 2023 01:57:26 +0100 +Subject: [PATCH 09/10] aarch64: Simplify probe of final frame allocation + +Previous patches ensured that the final frame allocation only needs +a probe when the size is strictly greater than 1KiB. It's therefore +safe to use the normal 1024 probe offset in all cases. + +The main motivation for doing this is to simplify the code and +remove the number of special cases. + +gcc/ + * config/aarch64/aarch64.c (aarch64_allocate_and_probe_stack_space): + Always probe the residual allocation at offset 1024, asserting + that that is in range. + +gcc/testsuite/ + * gcc.target/aarch64/stack-check-prologue-17.c: Expect the probe + to be at offset 1024 rather than offset 0. + * gcc.target/aarch64/stack-check-prologue-18.c: Likewise. +--- + gcc/config/aarch64/aarch64.c | 12 ++++-------- + .../gcc.target/aarch64/stack-check-prologue-17.c | 2 +- + .../gcc.target/aarch64/stack-check-prologue-18.c | 7 +++++-- + 3 files changed, 10 insertions(+), 11 deletions(-) + +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index 1e8467fdd03..705f719a2ea 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -5695,16 +5695,12 @@ aarch64_allocate_and_probe_stack_space (rtx temp1, rtx temp2, + are still safe. */ + if (residual) + { +- HOST_WIDE_INT residual_probe_offset = guard_used_by_caller; ++ gcc_assert (guard_used_by_caller + byte_sp_alignment <= size); ++ + /* If we're doing final adjustments, and we've done any full page + allocations then any residual needs to be probed. */ + if (final_adjustment_p && rounded_size != 0) + min_probe_threshold = 0; +- /* If doing a small final adjustment, we always probe at offset 0. +- This is done to avoid issues when the final adjustment is smaller +- than the probing offset. */ +- else if (final_adjustment_p && rounded_size == 0) +- residual_probe_offset = 0; + + aarch64_sub_sp (temp1, temp2, residual, frame_related_p); + if (residual >= min_probe_threshold) +@@ -5715,8 +5711,8 @@ aarch64_allocate_and_probe_stack_space (rtx temp1, rtx temp2, + HOST_WIDE_INT_PRINT_DEC " bytes, probing will be required." + "\n", residual); + +- emit_stack_probe (plus_constant (Pmode, stack_pointer_rtx, +- residual_probe_offset)); ++ emit_stack_probe (plus_constant (Pmode, stack_pointer_rtx, ++ guard_used_by_caller)); + emit_insn (gen_blockage ()); + } + } +diff --git a/gcc/testsuite/gcc.target/aarch64/stack-check-prologue-17.c b/gcc/testsuite/gcc.target/aarch64/stack-check-prologue-17.c +index 0d8a25d73a2..f0ec1389771 100644 +--- a/gcc/testsuite/gcc.target/aarch64/stack-check-prologue-17.c ++++ b/gcc/testsuite/gcc.target/aarch64/stack-check-prologue-17.c +@@ -33,7 +33,7 @@ int test1(int z) { + ** ... + ** str x30, \[sp\] + ** sub sp, sp, #1040 +-** str xzr, \[sp\] ++** str xzr, \[sp, #?1024\] + ** cbnz w0, .* + ** bl g + ** ... +diff --git a/gcc/testsuite/gcc.target/aarch64/stack-check-prologue-18.c b/gcc/testsuite/gcc.target/aarch64/stack-check-prologue-18.c +index 82447d20fff..71d33ba34e9 100644 +--- a/gcc/testsuite/gcc.target/aarch64/stack-check-prologue-18.c ++++ b/gcc/testsuite/gcc.target/aarch64/stack-check-prologue-18.c +@@ -8,8 +8,9 @@ void g(); + ** test1: + ** ... + ** str x30, \[sp\] ++** ... + ** sub sp, sp, #4064 +-** str xzr, \[sp\] ++** str xzr, \[sp, #?1024\] + ** cbnz w0, .* + ** bl g + ** ... +@@ -49,8 +50,9 @@ int test1(int z) { + ** test2: + ** ... + ** str x30, \[sp\] ++** ... + ** sub sp, sp, #1040 +-** str xzr, \[sp\] ++** str xzr, \[sp, #?1024\] + ** cbnz w0, .* + ** bl g + ** ... +@@ -77,6 +79,7 @@ int test2(int z) { + ** test3: + ** ... + ** str x30, \[sp\] ++** ... + ** sub sp, sp, #1024 + ** cbnz w0, .* + ** bl g +-- +2.34.1 + + +From bf3eeaa0182a92987570d9c787bd45079eebf528 Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Thu, 15 Jun 2023 19:16:52 +0100 +Subject: [PATCH 10/10] aarch64: Make stack smash canary protect saved + registers + +AArch64 normally puts the saved registers near the bottom of the frame, +immediately above any dynamic allocations. But this means that a +stack-smash attack on those dynamic allocations could overwrite the +saved registers without needing to reach as far as the stack smash +canary. + +The same thing could also happen for variable-sized arguments that are +passed by value, since those are allocated before a call and popped on +return. + +This patch avoids that by putting the locals (and thus the canary) below +the saved registers when stack smash protection is active. + +The patch fixes CVE-2023-4039. + +gcc/ + * config/aarch64/aarch64.c (aarch64_save_regs_above_locals_p): + New function. + (aarch64_layout_frame): Use it to decide whether locals should + go above or below the saved registers. + (aarch64_expand_prologue): Update stack layout comment. + Emit a stack tie after the final adjustment. + +gcc/testsuite/ + * gcc.target/aarch64/stack-protector-8.c: New test. + * gcc.target/aarch64/stack-protector-9.c: Likewise. +--- + gcc/config/aarch64/aarch64.c | 46 +++++++++++++-- + .../gcc.target/aarch64/stack-protector-8.c | 58 +++++++++++++++++++ + .../gcc.target/aarch64/stack-protector-9.c | 33 +++++++++++ + 3 files changed, 133 insertions(+), 4 deletions(-) + create mode 100644 gcc/testsuite/gcc.target/aarch64/stack-protector-8.c + create mode 100644 gcc/testsuite/gcc.target/aarch64/stack-protector-9.c + +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index 705f719a2ea..3d094214fac 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -4622,6 +4622,20 @@ aarch64_needs_frame_chain (void) + return aarch64_use_frame_pointer; + } + ++/* Return true if the current function should save registers above ++ the locals area, rather than below it. */ ++ ++static bool ++aarch64_save_regs_above_locals_p () ++{ ++ /* When using stack smash protection, make sure that the canary slot ++ comes between the locals and the saved registers. Otherwise, ++ it would be possible for a carefully sized smash attack to change ++ the saved registers (particularly LR and FP) without reaching the ++ canary. */ ++ return crtl->stack_protect_guard; ++} ++ + /* Mark the registers that need to be saved by the callee and calculate + the size of the callee-saved registers area and frame record (both FP + and LR may be omitted). */ +@@ -4686,6 +4700,16 @@ aarch64_layout_frame (void) + + cfun->machine->frame.bytes_below_hard_fp = crtl->outgoing_args_size; + ++ bool regs_at_top_p = aarch64_save_regs_above_locals_p (); ++ ++ if (regs_at_top_p) ++ { ++ cfun->machine->frame.bytes_below_hard_fp += get_frame_size (); ++ cfun->machine->frame.bytes_below_hard_fp ++ = aligned_upper_bound (cfun->machine->frame.bytes_below_hard_fp, ++ STACK_BOUNDARY / BITS_PER_UNIT); ++ } ++ + #define ALLOCATE_GPR_SLOT(REGNO) \ + do \ + { \ +@@ -4758,9 +4782,11 @@ aarch64_layout_frame (void) + HOST_WIDE_INT varargs_and_saved_regs_size + = offset + cfun->machine->frame.saved_varargs_size; + ++ cfun->machine->frame.bytes_above_hard_fp = varargs_and_saved_regs_size; ++ if (!regs_at_top_p) ++ cfun->machine->frame.bytes_above_hard_fp += get_frame_size (); + cfun->machine->frame.bytes_above_hard_fp +- = aligned_upper_bound (varargs_and_saved_regs_size +- + get_frame_size (), ++ = aligned_upper_bound (cfun->machine->frame.bytes_above_hard_fp, + STACK_BOUNDARY / BITS_PER_UNIT); + + /* Both these values are already aligned. */ +@@ -4772,6 +4798,9 @@ aarch64_layout_frame (void) + + cfun->machine->frame.bytes_above_locals + = cfun->machine->frame.saved_varargs_size; ++ if (regs_at_top_p) ++ cfun->machine->frame.bytes_above_locals ++ += cfun->machine->frame.saved_regs_size; + + cfun->machine->frame.initial_adjust = 0; + cfun->machine->frame.final_adjust = 0; +@@ -5764,10 +5793,10 @@ aarch64_add_cfa_expression (rtx_insn *insn, unsigned int reg, + | for register varargs | + | | + +-------------------------------+ +- | local variables | <-- frame_pointer_rtx ++ | local variables (1) | <-- frame_pointer_rtx + | | + +-------------------------------+ +- | padding | \ ++ | padding (1) | \ + +-------------------------------+ | + | callee-saved registers | | frame.saved_regs_size + +-------------------------------+ | +@@ -5775,6 +5804,10 @@ aarch64_add_cfa_expression (rtx_insn *insn, unsigned int reg, + +-------------------------------+ | + | FP' | / <- hard_frame_pointer_rtx (aligned) + +-------------------------------+ ++ | local variables (2) | ++ +-------------------------------+ ++ | padding (2) | ++ +-------------------------------+ + | dynamic allocation | + +-------------------------------+ + | padding | +@@ -5784,6 +5817,9 @@ aarch64_add_cfa_expression (rtx_insn *insn, unsigned int reg, + +-------------------------------+ + | | <-- stack_pointer_rtx (aligned) + ++ The regions marked (1) and (2) are mutually exclusive. (2) is used ++ when aarch64_save_regs_above_locals_p is true. ++ + Dynamic stack allocations via alloca() decrease stack_pointer_rtx + but leave frame_pointer_rtx and hard_frame_pointer_rtx + unchanged. +@@ -5937,6 +5973,8 @@ aarch64_expand_prologue (void) + that is assumed by the called. */ + aarch64_allocate_and_probe_stack_space (tmp1_rtx, tmp0_rtx, final_adjust, + !frame_pointer_needed, true); ++ if (emit_frame_chain && maybe_ne (final_adjust, 0)) ++ emit_insn (gen_stack_tie (stack_pointer_rtx, hard_frame_pointer_rtx)); + } + + /* Return TRUE if we can use a simple_return insn. +diff --git a/gcc/testsuite/gcc.target/aarch64/stack-protector-8.c b/gcc/testsuite/gcc.target/aarch64/stack-protector-8.c +new file mode 100644 +index 00000000000..c5e7deef6c1 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/stack-protector-8.c +@@ -0,0 +1,58 @@ ++/* { dg-options " -O -fstack-protector-strong -mstack-protector-guard=sysreg -mstack-protector-guard-reg=tpidr2_el0 -mstack-protector-guard-offset=16" } */ ++/* { dg-final { check-function-bodies "**" "" } } */ ++ ++void g(void *); ++ ++/* ++** test1: ++** sub sp, sp, #288 ++** stp x29, x30, \[sp, #?272\] ++** add x29, sp, #?272 ++** mrs (x[0-9]+), tpidr2_el0 ++** ldr (x[0-9]+), \[\1, #?16\] ++** str \2, \[sp, #?264\] ++** mov \2, *0 ++** add x0, sp, #?8 ++** bl g ++** ... ++** mrs .* ++** ... ++** bne .* ++** ... ++** ldp x29, x30, \[sp, #?272\] ++** add sp, sp, #?288 ++** ret ++** bl __stack_chk_fail ++*/ ++int test1() { ++ int y[0x40]; ++ g(y); ++ return 1; ++} ++ ++/* ++** test2: ++** stp x29, x30, \[sp, #?-16\]! ++** mov x29, sp ++** sub sp, sp, #1040 ++** mrs (x[0-9]+), tpidr2_el0 ++** ldr (x[0-9]+), \[\1, #?16\] ++** str \2, \[sp, #?1032\] ++** mov \2, *0 ++** add x0, sp, #?8 ++** bl g ++** ... ++** mrs .* ++** ... ++** bne .* ++** ... ++** add sp, sp, #?1040 ++** ldp x29, x30, \[sp\], #?16 ++** ret ++** bl __stack_chk_fail ++*/ ++int test2() { ++ int y[0x100]; ++ g(y); ++ return 1; ++} +diff --git a/gcc/testsuite/gcc.target/aarch64/stack-protector-9.c b/gcc/testsuite/gcc.target/aarch64/stack-protector-9.c +new file mode 100644 +index 00000000000..58f322aa480 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/stack-protector-9.c +@@ -0,0 +1,33 @@ ++/* { dg-options "-O2 -mcpu=neoverse-v1 -fstack-protector-all" } */ ++/* { dg-final { check-function-bodies "**" "" } } */ ++ ++/* ++** main: ++** ... ++** stp x29, x30, \[sp, #?-[0-9]+\]! ++** ... ++** sub sp, sp, #[0-9]+ ++** ... ++** str x[0-9]+, \[x29, #?-8\] ++** ... ++*/ ++int f(const char *); ++void g(void *); ++int main(int argc, char* argv[]) ++{ ++ int a; ++ int b; ++ char c[2+f(argv[1])]; ++ int d[0x100]; ++ char y; ++ ++ y=42; a=4; b=10; ++ c[0] = 'h'; c[1] = '\0'; ++ ++ c[f(argv[2])] = '\0'; ++ ++ __builtin_printf("%d %d\n%s\n", a, b, c); ++ g(d); ++ ++ return 0; ++} +-- +2.34.1 + diff --git a/meta/recipes-devtools/gcc/gcc-common.inc b/meta/recipes-devtools/gcc/gcc-common.inc index 629fa26dfe..69a3536965 100644 --- a/meta/recipes-devtools/gcc/gcc-common.inc +++ b/meta/recipes-devtools/gcc/gcc-common.inc @@ -100,7 +100,7 @@ BINV = "${PV}" #S = "${WORKDIR}/gcc-${PV}" S = "${TMPDIR}/work-shared/gcc-${PV}-${PR}/gcc-${PV}" -B = "${WORKDIR}/gcc-${PV}/build.${HOST_SYS}.${TARGET_SYS}" +B ?= "${WORKDIR}/gcc-${PV}/build.${HOST_SYS}.${TARGET_SYS}" target_includedir ?= "${includedir}" target_libdir ?= "${libdir}" diff --git a/meta/recipes-devtools/gcc/gcc-cross-canadian_9.3.bb b/meta/recipes-devtools/gcc/gcc-cross-canadian_9.5.bb index bf53c5cd78..bf53c5cd78 100644 --- a/meta/recipes-devtools/gcc/gcc-cross-canadian_9.3.bb +++ b/meta/recipes-devtools/gcc/gcc-cross-canadian_9.5.bb diff --git a/meta/recipes-devtools/gcc/gcc-cross_9.3.bb b/meta/recipes-devtools/gcc/gcc-cross_9.5.bb index b43cca0c52..b43cca0c52 100644 --- a/meta/recipes-devtools/gcc/gcc-cross_9.3.bb +++ b/meta/recipes-devtools/gcc/gcc-cross_9.5.bb diff --git a/meta/recipes-devtools/gcc/gcc-crosssdk_9.3.bb b/meta/recipes-devtools/gcc/gcc-crosssdk_9.5.bb index 40a6c4feff..40a6c4feff 100644 --- a/meta/recipes-devtools/gcc/gcc-crosssdk_9.3.bb +++ b/meta/recipes-devtools/gcc/gcc-crosssdk_9.5.bb diff --git a/meta/recipes-devtools/gcc/gcc-runtime_9.3.bb b/meta/recipes-devtools/gcc/gcc-runtime_9.5.bb index dd430b57eb..dd430b57eb 100644 --- a/meta/recipes-devtools/gcc/gcc-runtime_9.3.bb +++ b/meta/recipes-devtools/gcc/gcc-runtime_9.5.bb diff --git a/meta/recipes-devtools/gcc/gcc-sanitizers_9.3.bb b/meta/recipes-devtools/gcc/gcc-sanitizers_9.5.bb index f3c7058114..f3c7058114 100644 --- a/meta/recipes-devtools/gcc/gcc-sanitizers_9.3.bb +++ b/meta/recipes-devtools/gcc/gcc-sanitizers_9.5.bb diff --git a/meta/recipes-devtools/gcc/gcc-shared-source.inc b/meta/recipes-devtools/gcc/gcc-shared-source.inc index aac4b49313..4baf7874d2 100644 --- a/meta/recipes-devtools/gcc/gcc-shared-source.inc +++ b/meta/recipes-devtools/gcc/gcc-shared-source.inc @@ -9,3 +9,6 @@ SRC_URI = "" do_configure[depends] += "gcc-source-${PV}:do_preconfigure" do_populate_lic[depends] += "gcc-source-${PV}:do_unpack" + +# patch is available via gcc-source recipe +CVE_CHECK_WHITELIST += "CVE-2023-4039" diff --git a/meta/recipes-devtools/gcc/gcc-source.inc b/meta/recipes-devtools/gcc/gcc-source.inc index 03bab97815..224b7778ef 100644 --- a/meta/recipes-devtools/gcc/gcc-source.inc +++ b/meta/recipes-devtools/gcc/gcc-source.inc @@ -18,6 +18,7 @@ INHIBIT_DEFAULT_DEPS = "1" DEPENDS = "" PACKAGES = "" +B = "${WORKDIR}/build" # This needs to be Python to avoid lots of shell variables becoming dependencies. python do_preconfigure () { diff --git a/meta/recipes-devtools/gcc/gcc-source_9.3.bb b/meta/recipes-devtools/gcc/gcc-source_9.5.bb index b890fa33ea..b890fa33ea 100644 --- a/meta/recipes-devtools/gcc/gcc-source_9.3.bb +++ b/meta/recipes-devtools/gcc/gcc-source_9.5.bb diff --git a/meta/recipes-devtools/gcc/gcc_9.3.bb b/meta/recipes-devtools/gcc/gcc_9.5.bb index 7d93590588..7d93590588 100644 --- a/meta/recipes-devtools/gcc/gcc_9.3.bb +++ b/meta/recipes-devtools/gcc/gcc_9.5.bb diff --git a/meta/recipes-devtools/gcc/libgcc-initial_9.3.bb b/meta/recipes-devtools/gcc/libgcc-initial_9.5.bb index 0c698c26ec..0c698c26ec 100644 --- a/meta/recipes-devtools/gcc/libgcc-initial_9.3.bb +++ b/meta/recipes-devtools/gcc/libgcc-initial_9.5.bb diff --git a/meta/recipes-devtools/gcc/libgcc_9.3.bb b/meta/recipes-devtools/gcc/libgcc_9.5.bb index ea210a1130..ea210a1130 100644 --- a/meta/recipes-devtools/gcc/libgcc_9.3.bb +++ b/meta/recipes-devtools/gcc/libgcc_9.5.bb diff --git a/meta/recipes-devtools/gcc/libgfortran_9.3.bb b/meta/recipes-devtools/gcc/libgfortran_9.5.bb index 71dd8b4bdc..71dd8b4bdc 100644 --- a/meta/recipes-devtools/gcc/libgfortran_9.3.bb +++ b/meta/recipes-devtools/gcc/libgfortran_9.5.bb diff --git a/meta/recipes-devtools/gdb/gdb-9.1.inc b/meta/recipes-devtools/gdb/gdb-9.1.inc index d019e6b384..212c554cf1 100644 --- a/meta/recipes-devtools/gdb/gdb-9.1.inc +++ b/meta/recipes-devtools/gdb/gdb-9.1.inc @@ -16,6 +16,7 @@ SRC_URI = "${GNU_MIRROR}/gdb/gdb-${PV}.tar.xz \ file://0009-resolve-restrict-keyword-conflict.patch \ file://0010-Fix-invalid-sigprocmask-call.patch \ file://0011-gdbserver-ctrl-c-handling.patch \ + file://0012-CVE-2023-39128.patch \ " SRC_URI[md5sum] = "f7e9f6236c425097d9e5f18a6ac40655" SRC_URI[sha256sum] = "699e0ec832fdd2f21c8266171ea5bf44024bd05164fdf064e4d10cc4cf0d1737" diff --git a/meta/recipes-devtools/gdb/gdb/0012-CVE-2023-39128.patch b/meta/recipes-devtools/gdb/gdb/0012-CVE-2023-39128.patch new file mode 100644 index 0000000000..6445455bde --- /dev/null +++ b/meta/recipes-devtools/gdb/gdb/0012-CVE-2023-39128.patch @@ -0,0 +1,75 @@ +From 033bc52bb6190393c8eed80925fa78cc35b40c6d Mon Sep 17 00:00:00 2001 +From: Tom Tromey <tromey@adacore.com> +Date: Wed, 16 Aug 2023 11:29:19 -0600 +Subject: [PATCH] Avoid buffer overflow in ada_decode + +A bug report pointed out a buffer overflow in ada_decode, which Keith +helpfully analyzed. ada_decode had a logic error when the input was +all digits. While this isn't valid -- and would probably only appear +in fuzzer tests -- it still should be handled properly. + +This patch adds a missing bounds check. Tested with the self-tests in +an asan build. + +Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30639 +Reviewed-by: Keith Seitz <keiths@redhat.com> + +Upstream-Status: Backport from [https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=033bc52bb6190393c8eed80925fa78cc35b40c6d] +CVE: CVE-2023-39128 +Signed-off-by: Siddharth Doshi <sdoshi@mvista.com> +--- + gdb/ada-lang.c | 19 ++++++++++++++++++- + 1 file changed, 18 insertions(+), 1 deletion(-) + +diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c +index 0c2d4fc..40852b6 100644 +--- a/gdb/ada-lang.c ++++ b/gdb/ada-lang.c +@@ -56,6 +56,7 @@ + #include "cli/cli-utils.h" + #include "gdbsupport/function-view.h" + #include "gdbsupport/byte-vector.h" ++#include "gdbsupport/selftest.h" + #include <algorithm> + + /* Define whether or not the C operator '/' truncates towards zero for +@@ -1184,7 +1185,7 @@ ada_decode (const char *encoded) + i -= 1; + if (i > 1 && encoded[i] == '_' && encoded[i - 1] == '_') + len0 = i - 1; +- else if (encoded[i] == '$') ++ else if (i >= 0 && encoded[i] == '$') + len0 = i; + } + +@@ -1350,6 +1351,18 @@ Suppress: + + } + ++#ifdef GDB_SELF_TEST ++ ++static void ++ada_decode_tests () ++{ ++ /* This isn't valid, but used to cause a crash. PR gdb/30639. The ++ result does not really matter very much. */ ++ SELF_CHECK (ada_decode ("44") == "44"); ++} ++ ++#endif ++ + /* Table for keeping permanent unique copies of decoded names. Once + allocated, names in this table are never released. While this is a + storage leak, it should not be significant unless there are massive +@@ -14345,4 +14358,8 @@ DWARF attribute."), + gdb::observers::new_objfile.attach (ada_new_objfile_observer); + gdb::observers::free_objfile.attach (ada_free_objfile_observer); + gdb::observers::inferior_exit.attach (ada_inferior_exit); ++ ++#ifdef GDB_SELF_TEST ++ selftests::register_test ("ada-decode", ada_decode_tests); ++#endif + } +-- +2.24.4 + diff --git a/meta/recipes-devtools/git/files/CVE-2021-21300.patch b/meta/recipes-devtools/git/files/CVE-2021-21300.patch deleted file mode 100644 index 9206f711cf..0000000000 --- a/meta/recipes-devtools/git/files/CVE-2021-21300.patch +++ /dev/null @@ -1,305 +0,0 @@ -From 0e9cef2414f0df3fa5b9b56ff9072aa122bef29c Mon Sep 17 00:00:00 2001 -From: Minjae Kim <flowrgom@gmail.com> -Date: Sat, 27 Mar 2021 15:18:46 +0900 -Subject: [PATCH] checkout: fix bug that makes checkout follow symlinks in - leading path - -Before checking out a file, we have to confirm that all of its leading -components are real existing directories. And to reduce the number of -lstat() calls in this process, we cache the last leading path known to -contain only directories. However, when a path collision occurs (e.g. -when checking out case-sensitive files in case-insensitive file -systems), a cached path might have its file type changed on disk, -leaving the cache on an invalid state. Normally, this doesn't bring -any bad consequences as we usually check out files in index order, and -therefore, by the time the cached path becomes outdated, we no longer -need it anyway (because all files in that directory would have already -been written). - -But, there are some users of the checkout machinery that do not always -follow the index order. In particular: checkout-index writes the paths -in the same order that they appear on the CLI (or stdin); and the -delayed checkout feature -- used when a long-running filter process -replies with "status=delayed" -- postpones the checkout of some entries, -thus modifying the checkout order. - -When we have to check out an out-of-order entry and the lstat() cache is -invalid (due to a previous path collision), checkout_entry() may end up -using the invalid data and thrusting that the leading components are -real directories when, in reality, they are not. In the best case -scenario, where the directory was replaced by a regular file, the user -will get an error: "fatal: unable to create file 'foo/bar': Not a -directory". But if the directory was replaced by a symlink, checkout -could actually end up following the symlink and writing the file at a -wrong place, even outside the repository. Since delayed checkout is -affected by this bug, it could be used by an attacker to write -arbitrary files during the clone of a maliciously crafted repository. - -Some candidate solutions considered were to disable the lstat() cache -during unordered checkouts or sort the entries before passing them to -the checkout machinery. But both ideas include some performance penalty -and they don't future-proof the code against new unordered use cases. - -Instead, we now manually reset the lstat cache whenever we successfully -remove a directory. Note: We are not even checking whether the directory -was the same as the lstat cache points to because we might face a -scenario where the paths refer to the same location but differ due to -case folding, precomposed UTF-8 issues, or the presence of `..` -components in the path. Two regression tests, with case-collisions and -utf8-collisions, are also added for both checkout-index and delayed -checkout. - -Note: to make the previously mentioned clone attack unfeasible, it would -be sufficient to reset the lstat cache only after the remove_subtree() -call inside checkout_entry(). This is the place where we would remove a -directory whose path collides with the path of another entry that we are -currently trying to check out (possibly a symlink). However, in the -interest of a thorough fix that does not leave Git open to -similar-but-not-identical attack vectors, we decided to intercept -all `rmdir()` calls in one fell swoop. - -This addresses CVE-2021-21300. - -Co-authored-by: Johannes Schindelin <johannes.schindelin@gmx.de> -Signed-off-by: Matheus Tavares <matheus.bernardino@usp.br> - -Upstream-Status: Acepted [https://github.com/git/git/commit/684dd4c2b414bcf648505e74498a608f28de4592] -CVE: CVE-2021-21300 -Signed-off-by: Minjae Kim <flowergom@gmail.com> ---- - cache.h | 1 + - compat/mingw.c | 2 ++ - git-compat-util.h | 5 +++++ - symlinks.c | 25 +++++++++++++++++++++ - t/t0021-conversion.sh | 39 ++++++++++++++++++++++++++++++++ - t/t0021/rot13-filter.pl | 21 ++++++++++++++--- - t/t2006-checkout-index-basic.sh | 40 +++++++++++++++++++++++++++++++++ - 7 files changed, 130 insertions(+), 3 deletions(-) - -diff --git a/cache.h b/cache.h -index 04cabaa..dda373f 100644 ---- a/cache.h -+++ b/cache.h -@@ -1675,6 +1675,7 @@ int has_symlink_leading_path(const char *name, int len); - int threaded_has_symlink_leading_path(struct cache_def *, const char *, int); - int check_leading_path(const char *name, int len); - int has_dirs_only_path(const char *name, int len, int prefix_len); -+extern void invalidate_lstat_cache(void); - void schedule_dir_for_removal(const char *name, int len); - void remove_scheduled_dirs(void); - -diff --git a/compat/mingw.c b/compat/mingw.c -index bd24d91..cea9c72 100644 ---- a/compat/mingw.c -+++ b/compat/mingw.c -@@ -340,6 +340,8 @@ int mingw_rmdir(const char *pathname) - ask_yes_no_if_possible("Deletion of directory '%s' failed. " - "Should I try again?", pathname)) - ret = _wrmdir(wpathname); -+ if (!ret) -+ invalidate_lstat_cache(); - return ret; - } - -diff --git a/git-compat-util.h b/git-compat-util.h -index d0dd9c0..a1ecfd3 100644 ---- a/git-compat-util.h -+++ b/git-compat-util.h -@@ -365,6 +365,11 @@ static inline int noop_core_config(const char *var, const char *value, void *cb) - #define platform_core_config noop_core_config - #endif - -+int lstat_cache_aware_rmdir(const char *path); -+#if !defined(__MINGW32__) && !defined(_MSC_VER) -+#define rmdir lstat_cache_aware_rmdir -+#endif -+ - #ifndef has_dos_drive_prefix - static inline int git_has_dos_drive_prefix(const char *path) - { -diff --git a/symlinks.c b/symlinks.c -index 69d458a..ae3c665 100644 ---- a/symlinks.c -+++ b/symlinks.c -@@ -267,6 +267,13 @@ int has_dirs_only_path(const char *name, int len, int prefix_len) - */ - static int threaded_has_dirs_only_path(struct cache_def *cache, const char *name, int len, int prefix_len) - { -+ /* -+ * Note: this function is used by the checkout machinery, which also -+ * takes care to properly reset the cache when it performs an operation -+ * that would leave the cache outdated. If this function starts caching -+ * anything else besides FL_DIR, remember to also invalidate the cache -+ * when creating or deleting paths that might be in the cache. -+ */ - return lstat_cache(cache, name, len, - FL_DIR|FL_FULLPATH, prefix_len) & - FL_DIR; -@@ -321,3 +328,21 @@ void remove_scheduled_dirs(void) - { - do_remove_scheduled_dirs(0); - } -+ -+ -+void invalidate_lstat_cache(void) -+{ -+ reset_lstat_cache(&default_cache); -+} -+ -+#undef rmdir -+int lstat_cache_aware_rmdir(const char *path) -+{ -+ /* Any change in this function must be made also in `mingw_rmdir()` */ -+ int ret = rmdir(path); -+ -+ if (!ret) -+ invalidate_lstat_cache(); -+ -+ return ret; -+} -diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh -index c954c70..6a1d5f6 100755 ---- a/t/t0021-conversion.sh -+++ b/t/t0021-conversion.sh -@@ -820,4 +820,43 @@ test_expect_success PERL 'invalid file in delayed checkout' ' - grep "error: external filter .* signaled that .unfiltered. is now available although it has not been delayed earlier" git-stderr.log - ' - -+for mode in 'case' 'utf-8' -+do -+ case "$mode" in -+ case) dir='A' symlink='a' mode_prereq='CASE_INSENSITIVE_FS' ;; -+ utf-8) -+ dir=$(printf "\141\314\210") symlink=$(printf "\303\244") -+ mode_prereq='UTF8_NFD_TO_NFC' ;; -+ esac -+ -+ test_expect_success PERL,SYMLINKS,$mode_prereq \ -+ "delayed checkout with $mode-collision don't write to the wrong place" ' -+ test_config_global filter.delay.process \ -+ "\"$TEST_ROOT/rot13-filter.pl\" --always-delay delayed.log clean smudge delay" && -+ test_config_global filter.delay.required true && -+ git init $mode-collision && -+ ( -+ cd $mode-collision && -+ mkdir target-dir && -+ empty_oid=$(printf "" | git hash-object -w --stdin) && -+ symlink_oid=$(printf "%s" "$PWD/target-dir" | git hash-object -w --stdin) && -+ attr_oid=$(echo "$dir/z filter=delay" | git hash-object -w --stdin) && -+ cat >objs <<-EOF && -+ 100644 blob $empty_oid $dir/x -+ 100644 blob $empty_oid $dir/y -+ 100644 blob $empty_oid $dir/z -+ 120000 blob $symlink_oid $symlink -+ 100644 blob $attr_oid .gitattributes -+ EOF -+ git update-index --index-info <objs && -+ git commit -m "test commit" -+ ) && -+ git clone $mode-collision $mode-collision-cloned && -+ # Make sure z was really delayed -+ grep "IN: smudge $dir/z .* \\[DELAYED\\]" $mode-collision-cloned/delayed.log && -+ # Should not create $dir/z at $symlink/z -+ test_path_is_missing $mode-collision/target-dir/z -+ ' -+done -+ - test_done -diff --git a/t/t0021/rot13-filter.pl b/t/t0021/rot13-filter.pl -index 4701072..007f2d7 100644 ---- a/t/t0021/rot13-filter.pl -+++ b/t/t0021/rot13-filter.pl -@@ -2,9 +2,15 @@ - # Example implementation for the Git filter protocol version 2 - # See Documentation/gitattributes.txt, section "Filter Protocol" - # --# The first argument defines a debug log file that the script write to. --# All remaining arguments define a list of supported protocol --# capabilities ("clean", "smudge", etc). -+# Usage: rot13-filter.pl [--always-delay] <log path> <capabilities> -+# -+# Log path defines a debug log file that the script writes to. The -+# subsequent arguments define a list of supported protocol capabilities -+# ("clean", "smudge", etc). -+# -+# When --always-delay is given all pathnames with the "can-delay" flag -+# that don't appear on the list bellow are delayed with a count of 1 -+# (see more below). - # - # This implementation supports special test cases: - # (1) If data with the pathname "clean-write-fail.r" is processed with -@@ -53,6 +59,13 @@ sub gitperllib { - use Git::Packet; - - my $MAX_PACKET_CONTENT_SIZE = 65516; -+ -+my $always_delay = 0; -+if ( $ARGV[0] eq '--always-delay' ) { -+ $always_delay = 1; -+ shift @ARGV; -+} -+ - my $log_file = shift @ARGV; - my @capabilities = @ARGV; - -@@ -134,6 +147,8 @@ sub rot13 { - if ( $buffer eq "can-delay=1" ) { - if ( exists $DELAY{$pathname} and $DELAY{$pathname}{"requested"} == 0 ) { - $DELAY{$pathname}{"requested"} = 1; -+ } elsif ( !exists $DELAY{$pathname} and $always_delay ) { -+ $DELAY{$pathname} = { "requested" => 1, "count" => 1 }; - } - } else { - die "Unknown message '$buffer'"; -diff --git a/t/t2006-checkout-index-basic.sh b/t/t2006-checkout-index-basic.sh -index 57cbdfe..f223a02 100755 ---- a/t/t2006-checkout-index-basic.sh -+++ b/t/t2006-checkout-index-basic.sh -@@ -21,4 +21,44 @@ test_expect_success 'checkout-index -h in broken repository' ' - test_i18ngrep "[Uu]sage" broken/usage - ' - -+for mode in 'case' 'utf-8' -+do -+ case "$mode" in -+ case) dir='A' symlink='a' mode_prereq='CASE_INSENSITIVE_FS' ;; -+ utf-8) -+ dir=$(printf "\141\314\210") symlink=$(printf "\303\244") -+ mode_prereq='UTF8_NFD_TO_NFC' ;; -+ esac -+ -+ test_expect_success SYMLINKS,$mode_prereq \ -+ "checkout-index with $mode-collision don't write to the wrong place" ' -+ git init $mode-collision && -+ ( -+ cd $mode-collision && -+ mkdir target-dir && -+ empty_obj_hex=$(git hash-object -w --stdin </dev/null) && -+ symlink_hex=$(printf "%s" "$PWD/target-dir" | git hash-object -w --stdin) && -+ cat >objs <<-EOF && -+ 100644 blob ${empty_obj_hex} ${dir}/x -+ 100644 blob ${empty_obj_hex} ${dir}/y -+ 100644 blob ${empty_obj_hex} ${dir}/z -+ 120000 blob ${symlink_hex} ${symlink} -+ EOF -+ git update-index --index-info <objs && -+ # Note: the order is important here to exercise the -+ # case where the file at ${dir} has its type changed by -+ # the time Git tries to check out ${dir}/z. -+ # -+ # Also, we use core.precomposeUnicode=false because we -+ # want Git to treat the UTF-8 paths transparently on -+ # Mac OS, matching what is in the index. -+ # -+ git -c core.precomposeUnicode=false checkout-index -f \ -+ ${dir}/x ${dir}/y ${symlink} ${dir}/z && -+ # Should not create ${dir}/z at ${symlink}/z -+ test_path_is_missing target-dir/z -+ ) -+ ' -+done -+ - test_done --- -2.17.1 - diff --git a/meta/recipes-devtools/git/files/CVE-2021-40330.patch b/meta/recipes-devtools/git/files/CVE-2021-40330.patch new file mode 100644 index 0000000000..725f98f0b7 --- /dev/null +++ b/meta/recipes-devtools/git/files/CVE-2021-40330.patch @@ -0,0 +1,108 @@ +From e77ca0c7d577408878d2b3e8c7336e6119cb3931 Mon Sep 17 00:00:00 2001 +From: Minjae Kim <flowergom@gmail.com> +Date: Thu, 25 Nov 2021 06:36:26 +0000 +Subject: [PATCH] git_connect_git(): forbid newlines in host and path + +When we connect to a git:// server, we send an initial request that +looks something like: + + 002dgit-upload-pack repo.git\0host=example.com + +If the repo path contains a newline, then it's included literally, and +we get: + + 002egit-upload-pack repo + .git\0host=example.com + +This works fine if you really do have a newline in your repository name; +the server side uses the pktline framing to parse the string, not +newlines. However, there are many _other_ protocols in the wild that do +parse on newlines, such as HTTP. So a carefully constructed git:// URL +can actually turn into a valid HTTP request. For example: + + git://localhost:1234/%0d%0a%0d%0aGET%20/%20HTTP/1.1 %0d%0aHost:localhost%0d%0a%0d%0a + +becomes: + + 0050git-upload-pack / + GET / HTTP/1.1 + Host:localhost + + host=localhost:1234 + +on the wire. Again, this isn't a problem for a real Git server, but it +does mean that feeding a malicious URL to Git (e.g., through a +submodule) can cause it to make unexpected cross-protocol requests. +Since repository names with newlines are presumably quite rare (and +indeed, we already disallow them in git-over-http), let's just disallow +them over this protocol. + +Hostnames could likewise inject a newline, but this is unlikely a +problem in practice; we'd try resolving the hostname with a newline in +it, which wouldn't work. Still, it doesn't hurt to err on the side of +caution there, since we would not expect them to work in the first +place. + +The ssh and local code paths are unaffected by this patch. In both cases +we're trying to run upload-pack via a shell, and will quote the newline +so that it makes it intact. An attacker can point an ssh url at an +arbitrary port, of course, but unless there's an actual ssh server +there, we'd never get as far as sending our shell command anyway. We +_could_ similarly restrict newlines in those protocols out of caution, +but there seems little benefit to doing so. + +The new test here is run alongside the git-daemon tests, which cover the +same protocol, but it shouldn't actually contact the daemon at all. In +theory we could make the test more robust by setting up an actual +repository with a newline in it (so that our clone would succeed if our +new check didn't kick in). But a repo directory with newline in it is +likely not portable across all filesystems. Likewise, we could check +git-daemon's log that it was not contacted at all, but we do not +currently record the log (and anyway, it would make the test racy with +the daemon's log write). We'll just check the client-side stderr to make +sure we hit the expected code path. + +Reported-by: Harold Kim <h.kim@flatt.tech> +Signed-off-by: Jeff King <peff@peff.net> +Signed-off-by: Junio C Hamano <gitster@pobox.com> + +Upstream-Status: Backported [https://github.com/git/git/commit/a02ea577174ab8ed18f847cf1693f213e0b9c473] +CVE: CVE-2021-40330 +Signed-off-by: Minjae Kim <flowergom@gmail.com> +--- + connect.c | 2 ++ + t/t5570-git-daemon.sh | 5 +++++ + 2 files changed, 7 insertions(+) + +diff --git a/connect.c b/connect.c +index b6451ab..929de9a 100644 +--- a/connect.c ++++ b/connect.c +@@ -1064,6 +1064,8 @@ static struct child_process *git_connect_git(int fd[2], char *hostandport, + target_host = xstrdup(hostandport); + + transport_check_allowed("git"); ++ if (strchr(target_host, '\n') || strchr(path, '\n')) ++ die(_("newline is forbidden in git:// hosts and repo paths")); + + /* + * These underlying connection commands die() if they +diff --git a/t/t5570-git-daemon.sh b/t/t5570-git-daemon.sh +index 34487bb..79cd218 100755 +--- a/t/t5570-git-daemon.sh ++++ b/t/t5570-git-daemon.sh +@@ -103,6 +103,11 @@ test_expect_success 'fetch notices corrupt idx' ' + ) + ' + ++test_expect_success 'client refuses to ask for repo with newline' ' ++ test_must_fail git clone "$GIT_DAEMON_URL/repo$LF.git" dst 2>stderr && ++ test_i18ngrep newline.is.forbidden stderr ++' ++ + test_remote_error() + { + do_export=YesPlease +-- +2.17.1 + diff --git a/meta/recipes-devtools/git/files/CVE-2022-23521.patch b/meta/recipes-devtools/git/files/CVE-2022-23521.patch new file mode 100644 index 0000000000..974546013d --- /dev/null +++ b/meta/recipes-devtools/git/files/CVE-2022-23521.patch @@ -0,0 +1,367 @@ +From eb22e7dfa23da6bd9aed9bd1dad69e1e8e167d24 Mon Sep 17 00:00:00 2001 +From: Patrick Steinhardt <ps@pks.im> +Date: Thu, 1 Dec 2022 15:45:15 +0100 +Subject: [PATCH] CVE-2022-23521 + +attr: fix overflow when upserting attribute with overly long name + +The function `git_attr_internal()` is called to upsert attributes into +the global map. And while all callers pass a `size_t`, the function +itself accepts an `int` as the attribute name's length. This can lead to +an integer overflow in case the attribute name is longer than `INT_MAX`. + +Now this overflow seems harmless as the first thing we do is to call +`attr_name_valid()`, and that function only succeeds in case all chars +in the range of `namelen` match a certain small set of chars. We thus +can't do an out-of-bounds read as NUL is not part of that set and all +strings passed to this function are NUL-terminated. And furthermore, we +wouldn't ever read past the current attribute name anyway due to the +same reason. And if validation fails we will return early. + +On the other hand it feels fragile to rely on this behaviour, even more +so given that we pass `namelen` to `FLEX_ALLOC_MEM()`. So let's instead +just do the correct thing here and accept a `size_t` as line length. + +Upstream-Status: Backport [https://github.com/git/git/commit/eb22e7dfa23da6bd9aed9bd1dad69e1e8e167d24 &https://github.com/git/git/commit/8d0d48cf2157cfb914db1f53b3fe40785b86f3aa & https://github.com/git/git/commit/24557209500e6ed618f04a8795a111a0c491a29c & https://github.com/git/git/commit/34ace8bad02bb14ecc5b631f7e3daaa7a9bba7d9 & https://github.com/git/git/commit/447ac906e189535e77dcb1f4bbe3f1bc917d4c12 & https://github.com/git/git/commit/e1e12e97ac73ded85f7d000da1063a774b3cc14f & https://github.com/git/git/commit/a60a66e409c265b2944f18bf43581c146812586d & https://github.com/git/git/commit/d74b1fd54fdbc45966d12ea907dece11e072fb2b & https://github.com/git/git/commit/dfa6b32b5e599d97448337ed4fc18dd50c90758f & https://github.com/git/git/commit/3c50032ff5289cc45659f21949c8d09e52164579 + +CVE: CVE-2022-23521 + +Reviewed-by: Sylvain Beucler <beuc@debian.org> +Signed-off-by: Patrick Steinhardt <ps@pks.im> +Signed-off-by: Junio C Hamano <gitster@pobox.com> +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> +--- + attr.c | 97 +++++++++++++++++++++++++++---------------- + attr.h | 12 ++++++ + t/t0003-attributes.sh | 59 ++++++++++++++++++++++++++ + 3 files changed, 132 insertions(+), 36 deletions(-) + +diff --git a/attr.c b/attr.c +index 11f19b5..63484ab 100644 +--- a/attr.c ++++ b/attr.c +@@ -29,7 +29,7 @@ static const char git_attr__unknown[] = "(builtin)unknown"; + #endif + + struct git_attr { +- int attr_nr; /* unique attribute number */ ++ unsigned int attr_nr; /* unique attribute number */ + char name[FLEX_ARRAY]; /* attribute name */ + }; + +@@ -221,7 +221,7 @@ static void report_invalid_attr(const char *name, size_t len, + * dictionary. If no entry is found, create a new attribute and store it in + * the dictionary. + */ +-static const struct git_attr *git_attr_internal(const char *name, int namelen) ++static const struct git_attr *git_attr_internal(const char *name, size_t namelen) + { + struct git_attr *a; + +@@ -237,8 +237,8 @@ static const struct git_attr *git_attr_internal(const char *name, int namelen) + a->attr_nr = hashmap_get_size(&g_attr_hashmap.map); + + attr_hashmap_add(&g_attr_hashmap, a->name, namelen, a); +- assert(a->attr_nr == +- (hashmap_get_size(&g_attr_hashmap.map) - 1)); ++ if (a->attr_nr != hashmap_get_size(&g_attr_hashmap.map) - 1) ++ die(_("unable to add additional attribute")); + } + + hashmap_unlock(&g_attr_hashmap); +@@ -283,7 +283,7 @@ struct match_attr { + const struct git_attr *attr; + } u; + char is_macro; +- unsigned num_attr; ++ size_t num_attr; + struct attr_state state[FLEX_ARRAY]; + }; + +@@ -300,7 +300,7 @@ static const char *parse_attr(const char *src, int lineno, const char *cp, + struct attr_state *e) + { + const char *ep, *equals; +- int len; ++ size_t len; + + ep = cp + strcspn(cp, blank); + equals = strchr(cp, '='); +@@ -344,8 +344,7 @@ static const char *parse_attr(const char *src, int lineno, const char *cp, + static struct match_attr *parse_attr_line(const char *line, const char *src, + int lineno, int macro_ok) + { +- int namelen; +- int num_attr, i; ++ size_t namelen, num_attr, i; + const char *cp, *name, *states; + struct match_attr *res = NULL; + int is_macro; +@@ -356,6 +355,11 @@ static struct match_attr *parse_attr_line(const char *line, const char *src, + return NULL; + name = cp; + ++ if (strlen(line) >= ATTR_MAX_LINE_LENGTH) { ++ warning(_("ignoring overly long attributes line %d"), lineno); ++ return NULL; ++ } ++ + if (*cp == '"' && !unquote_c_style(&pattern, name, &states)) { + name = pattern.buf; + namelen = pattern.len; +@@ -392,10 +396,9 @@ static struct match_attr *parse_attr_line(const char *line, const char *src, + goto fail_return; + } + +- res = xcalloc(1, +- sizeof(*res) + +- sizeof(struct attr_state) * num_attr + +- (is_macro ? 0 : namelen + 1)); ++ res = xcalloc(1, st_add3(sizeof(*res), ++ st_mult(sizeof(struct attr_state), num_attr), ++ is_macro ? 0 : namelen + 1)); + if (is_macro) { + res->u.attr = git_attr_internal(name, namelen); + } else { +@@ -458,11 +461,12 @@ struct attr_stack { + + static void attr_stack_free(struct attr_stack *e) + { +- int i; ++ unsigned i; + free(e->origin); + for (i = 0; i < e->num_matches; i++) { + struct match_attr *a = e->attrs[i]; +- int j; ++ size_t j; ++ + for (j = 0; j < a->num_attr; j++) { + const char *setto = a->state[j].setto; + if (setto == ATTR__TRUE || +@@ -671,8 +675,8 @@ static void handle_attr_line(struct attr_stack *res, + a = parse_attr_line(line, src, lineno, macro_ok); + if (!a) + return; +- ALLOC_GROW(res->attrs, res->num_matches + 1, res->alloc); +- res->attrs[res->num_matches++] = a; ++ ALLOC_GROW_BY(res->attrs, res->num_matches, 1, res->alloc); ++ res->attrs[res->num_matches - 1] = a; + } + + static struct attr_stack *read_attr_from_array(const char **list) +@@ -711,21 +715,37 @@ void git_attr_set_direction(enum git_attr_direction new_direction) + + static struct attr_stack *read_attr_from_file(const char *path, int macro_ok) + { ++ struct strbuf buf = STRBUF_INIT; + FILE *fp = fopen_or_warn(path, "r"); + struct attr_stack *res; +- char buf[2048]; + int lineno = 0; ++ int fd; ++ struct stat st; + + if (!fp) + return NULL; +- res = xcalloc(1, sizeof(*res)); +- while (fgets(buf, sizeof(buf), fp)) { +- char *bufp = buf; +- if (!lineno) +- skip_utf8_bom(&bufp, strlen(bufp)); +- handle_attr_line(res, bufp, path, ++lineno, macro_ok); ++ ++ fd = fileno(fp); ++ if (fstat(fd, &st)) { ++ warning_errno(_("cannot fstat gitattributes file '%s'"), path); ++ fclose(fp); ++ return NULL; + } ++ if (st.st_size >= ATTR_MAX_FILE_SIZE) { ++ warning(_("ignoring overly large gitattributes file '%s'"), path); ++ fclose(fp); ++ return NULL; ++ } ++ ++ CALLOC_ARRAY(res, 1); ++ while (strbuf_getline(&buf, fp) != EOF) { ++ if (!lineno && starts_with(buf.buf, utf8_bom)) ++ strbuf_remove(&buf, 0, strlen(utf8_bom)); ++ handle_attr_line(res, buf.buf, path, ++lineno, macro_ok); ++ } ++ + fclose(fp); ++ strbuf_release(&buf); + return res; + } + +@@ -736,13 +756,18 @@ static struct attr_stack *read_attr_from_index(const struct index_state *istate, + struct attr_stack *res; + char *buf, *sp; + int lineno = 0; ++ size_t size; + + if (!istate) + return NULL; + +- buf = read_blob_data_from_index(istate, path, NULL); ++ buf = read_blob_data_from_index(istate, path, &size); + if (!buf) + return NULL; ++ if (size >= ATTR_MAX_FILE_SIZE) { ++ warning(_("ignoring overly large gitattributes blob '%s'"), path); ++ return NULL; ++ } + + res = xcalloc(1, sizeof(*res)); + for (sp = buf; *sp; ) { +@@ -1012,12 +1037,12 @@ static int macroexpand_one(struct all_attrs_item *all_attrs, int nr, int rem); + static int fill_one(const char *what, struct all_attrs_item *all_attrs, + const struct match_attr *a, int rem) + { +- int i; ++ size_t i; + +- for (i = a->num_attr - 1; rem > 0 && i >= 0; i--) { +- const struct git_attr *attr = a->state[i].attr; ++ for (i = a->num_attr; rem > 0 && i > 0; i--) { ++ const struct git_attr *attr = a->state[i - 1].attr; + const char **n = &(all_attrs[attr->attr_nr].value); +- const char *v = a->state[i].setto; ++ const char *v = a->state[i - 1].setto; + + if (*n == ATTR__UNKNOWN) { + debug_set(what, +@@ -1036,11 +1061,11 @@ static int fill(const char *path, int pathlen, int basename_offset, + struct all_attrs_item *all_attrs, int rem) + { + for (; rem > 0 && stack; stack = stack->prev) { +- int i; ++ unsigned i; + const char *base = stack->origin ? stack->origin : ""; + +- for (i = stack->num_matches - 1; 0 < rem && 0 <= i; i--) { +- const struct match_attr *a = stack->attrs[i]; ++ for (i = stack->num_matches; 0 < rem && 0 < i; i--) { ++ const struct match_attr *a = stack->attrs[i - 1]; + if (a->is_macro) + continue; + if (path_matches(path, pathlen, basename_offset, +@@ -1071,11 +1096,11 @@ static void determine_macros(struct all_attrs_item *all_attrs, + const struct attr_stack *stack) + { + for (; stack; stack = stack->prev) { +- int i; +- for (i = stack->num_matches - 1; i >= 0; i--) { +- const struct match_attr *ma = stack->attrs[i]; ++ unsigned i; ++ for (i = stack->num_matches; i > 0; i--) { ++ const struct match_attr *ma = stack->attrs[i - 1]; + if (ma->is_macro) { +- int n = ma->u.attr->attr_nr; ++ unsigned int n = ma->u.attr->attr_nr; + if (!all_attrs[n].macro) { + all_attrs[n].macro = ma; + } +@@ -1127,7 +1152,7 @@ void git_check_attr(const struct index_state *istate, + collect_some_attrs(istate, path, check); + + for (i = 0; i < check->nr; i++) { +- size_t n = check->items[i].attr->attr_nr; ++ unsigned int n = check->items[i].attr->attr_nr; + const char *value = check->all_attrs[n].value; + if (value == ATTR__UNKNOWN) + value = ATTR__UNSET; +diff --git a/attr.h b/attr.h +index b0378bf..f424285 100644 +--- a/attr.h ++++ b/attr.h +@@ -1,6 +1,18 @@ + #ifndef ATTR_H + #define ATTR_H + ++/** ++ * The maximum line length for a gitattributes file. If the line exceeds this ++ * length we will ignore it. ++ */ ++#define ATTR_MAX_LINE_LENGTH 2048 ++ ++ /** ++ * The maximum size of the giattributes file. If the file exceeds this size we ++ * will ignore it. ++ */ ++#define ATTR_MAX_FILE_SIZE (100 * 1024 * 1024) ++ + struct index_state; + + /* An attribute is a pointer to this opaque structure */ +diff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh +index 71e63d8..556245b 100755 +--- a/t/t0003-attributes.sh ++++ b/t/t0003-attributes.sh +@@ -342,4 +342,63 @@ test_expect_success 'query binary macro directly' ' + test_cmp expect actual + ' + ++test_expect_success 'large attributes line ignored in tree' ' ++ test_when_finished "rm .gitattributes" && ++ printf "path %02043d" 1 >.gitattributes && ++ git check-attr --all path >actual 2>err && ++ echo "warning: ignoring overly long attributes line 1" >expect && ++ test_cmp expect err && ++ test_must_be_empty actual ++' ++ ++test_expect_success 'large attributes line ignores trailing content in tree' ' ++ test_when_finished "rm .gitattributes" && ++ # older versions of Git broke lines at 2048 bytes; the 2045 bytes ++ # of 0-padding here is accounting for the three bytes of "a 1", which ++ # would knock "trailing" to the "next" line, where it would be ++ # erroneously parsed. ++ printf "a %02045dtrailing attribute\n" 1 >.gitattributes && ++ git check-attr --all trailing >actual 2>err && ++ echo "warning: ignoring overly long attributes line 1" >expect && ++ test_cmp expect err && ++ test_must_be_empty actual ++' ++ ++test_expect_success EXPENSIVE 'large attributes file ignored in tree' ' ++ test_when_finished "rm .gitattributes" && ++ dd if=/dev/zero of=.gitattributes bs=101M count=1 2>/dev/null && ++ git check-attr --all path >/dev/null 2>err && ++ echo "warning: ignoring overly large gitattributes file ${SQ}.gitattributes${SQ}" >expect && ++ test_cmp expect err ++' ++ ++test_expect_success 'large attributes line ignored in index' ' ++ test_when_finished "git update-index --remove .gitattributes" && ++ blob=$(printf "path %02043d" 1 | git hash-object -w --stdin) && ++ git update-index --add --cacheinfo 100644,$blob,.gitattributes && ++ git check-attr --cached --all path >actual 2>err && ++ echo "warning: ignoring overly long attributes line 1" >expect && ++ test_cmp expect err && ++ test_must_be_empty actual ++' ++ ++test_expect_success 'large attributes line ignores trailing content in index' ' ++ test_when_finished "git update-index --remove .gitattributes" && ++ blob=$(printf "a %02045dtrailing attribute\n" 1 | git hash-object -w --stdin) && ++ git update-index --add --cacheinfo 100644,$blob,.gitattributes && ++ git check-attr --cached --all trailing >actual 2>err && ++ echo "warning: ignoring overly long attributes line 1" >expect && ++ test_cmp expect err && ++ test_must_be_empty actual ++' ++ ++test_expect_success EXPENSIVE 'large attributes file ignored in index' ' ++ test_when_finished "git update-index --remove .gitattributes" && ++ blob=$(dd if=/dev/zero bs=101M count=1 2>/dev/null | git hash-object -w --stdin) && ++ git update-index --add --cacheinfo 100644,$blob,.gitattributes && ++ git check-attr --cached --all path >/dev/null 2>err && ++ echo "warning: ignoring overly large gitattributes blob ${SQ}.gitattributes${SQ}" >expect && ++ test_cmp expect err ++' ++ + test_done +-- +2.25.1 + diff --git a/meta/recipes-devtools/git/files/CVE-2022-41903-01.patch b/meta/recipes-devtools/git/files/CVE-2022-41903-01.patch new file mode 100644 index 0000000000..87091abd47 --- /dev/null +++ b/meta/recipes-devtools/git/files/CVE-2022-41903-01.patch @@ -0,0 +1,39 @@ +From a244dc5b0a629290881641467c7a545de7508ab2 Mon Sep 17 00:00:00 2001 +From: Carlo Marcelo Arenas Belón <carenas@gmail.com> +Date: Tue, 2 Nov 2021 15:46:06 +0000 +Subject: [PATCH 01/12] test-lib: add prerequisite for 64-bit platforms + +Allow tests that assume a 64-bit `size_t` to be skipped in 32-bit +platforms and regardless of the size of `long`. + +This imitates the `LONG_IS_64BIT` prerequisite. + +Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com> +Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> +Signed-off-by: Junio C Hamano <gitster@pobox.com> + +Upstream-Status: Backport [https://github.com/git/git/commit/a244dc5b0a629290881641467c7a545de7508ab2] +CVE: CVE-2022-41903 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + t/test-lib.sh | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/t/test-lib.sh b/t/test-lib.sh +index e06fa02..db5ec2f 100644 +--- a/t/test-lib.sh ++++ b/t/test-lib.sh +@@ -1613,6 +1613,10 @@ build_option () { + sed -ne "s/^$1: //p" + } + ++test_lazy_prereq SIZE_T_IS_64BIT ' ++ test 8 -eq "$(build_option sizeof-size_t)" ++' ++ + test_lazy_prereq LONG_IS_64BIT ' + test 8 -le "$(build_option sizeof-long)" + ' +-- +2.25.1 + diff --git a/meta/recipes-devtools/git/files/CVE-2022-41903-02.patch b/meta/recipes-devtools/git/files/CVE-2022-41903-02.patch new file mode 100644 index 0000000000..f35e55b585 --- /dev/null +++ b/meta/recipes-devtools/git/files/CVE-2022-41903-02.patch @@ -0,0 +1,187 @@ +From 81dc898df9b4b4035534a927f3234a3839b698bf Mon Sep 17 00:00:00 2001 +From: Patrick Steinhardt <ps@pks.im> +Date: Thu, 1 Dec 2022 15:46:25 +0100 +Subject: [PATCH 02/12] pretty: fix out-of-bounds write caused by integer overflow + +When using a padding specifier in the pretty format passed to git-log(1) +we need to calculate the string length in several places. These string +lengths are stored in `int`s though, which means that these can easily +overflow when the input lengths exceeds 2GB. This can ultimately lead to +an out-of-bounds write when these are used in a call to memcpy(3P): + + ==8340==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7f1ec62f97fe at pc 0x7f2127e5f427 bp 0x7ffd3bd63de0 sp 0x7ffd3bd63588 + WRITE of size 1 at 0x7f1ec62f97fe thread T0 + #0 0x7f2127e5f426 in __interceptor_memcpy /usr/src/debug/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:827 + #1 0x5628e96aa605 in format_and_pad_commit pretty.c:1762 + #2 0x5628e96aa7f4 in format_commit_item pretty.c:1801 + #3 0x5628e97cdb24 in strbuf_expand strbuf.c:429 + #4 0x5628e96ab060 in repo_format_commit_message pretty.c:1869 + #5 0x5628e96acd0f in pretty_print_commit pretty.c:2161 + #6 0x5628e95a44c8 in show_log log-tree.c:781 + #7 0x5628e95a76ba in log_tree_commit log-tree.c:1117 + #8 0x5628e922bed5 in cmd_log_walk_no_free builtin/log.c:508 + #9 0x5628e922c35b in cmd_log_walk builtin/log.c:549 + #10 0x5628e922f1a2 in cmd_log builtin/log.c:883 + #11 0x5628e9106993 in run_builtin git.c:466 + #12 0x5628e9107397 in handle_builtin git.c:721 + #13 0x5628e9107b07 in run_argv git.c:788 + #14 0x5628e91088a7 in cmd_main git.c:923 + #15 0x5628e939d682 in main common-main.c:57 + #16 0x7f2127c3c28f (/usr/lib/libc.so.6+0x2328f) + #17 0x7f2127c3c349 in __libc_start_main (/usr/lib/libc.so.6+0x23349) + #18 0x5628e91020e4 in _start ../sysdeps/x86_64/start.S:115 + + 0x7f1ec62f97fe is located 2 bytes to the left of 4831838265-byte region [0x7f1ec62f9800,0x7f1fe62f9839) + allocated by thread T0 here: + #0 0x7f2127ebe7ea in __interceptor_realloc /usr/src/debug/gcc/libsanitizer/asan/asan_malloc_linux.cpp:85 + #1 0x5628e98774d4 in xrealloc wrapper.c:136 + #2 0x5628e97cb01c in strbuf_grow strbuf.c:99 + #3 0x5628e97ccd42 in strbuf_addchars strbuf.c:327 + #4 0x5628e96aa55c in format_and_pad_commit pretty.c:1761 + #5 0x5628e96aa7f4 in format_commit_item pretty.c:1801 + #6 0x5628e97cdb24 in strbuf_expand strbuf.c:429 + #7 0x5628e96ab060 in repo_format_commit_message pretty.c:1869 + #8 0x5628e96acd0f in pretty_print_commit pretty.c:2161 + #9 0x5628e95a44c8 in show_log log-tree.c:781 + #10 0x5628e95a76ba in log_tree_commit log-tree.c:1117 + #11 0x5628e922bed5 in cmd_log_walk_no_free builtin/log.c:508 + #12 0x5628e922c35b in cmd_log_walk builtin/log.c:549 + #13 0x5628e922f1a2 in cmd_log builtin/log.c:883 + #14 0x5628e9106993 in run_builtin git.c:466 + #15 0x5628e9107397 in handle_builtin git.c:721 + #16 0x5628e9107b07 in run_argv git.c:788 + #17 0x5628e91088a7 in cmd_main git.c:923 + #18 0x5628e939d682 in main common-main.c:57 + #19 0x7f2127c3c28f (/usr/lib/libc.so.6+0x2328f) + #20 0x7f2127c3c349 in __libc_start_main (/usr/lib/libc.so.6+0x23349) + #21 0x5628e91020e4 in _start ../sysdeps/x86_64/start.S:115 + + SUMMARY: AddressSanitizer: heap-buffer-overflow /usr/src/debug/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:827 in __interceptor_memcpy + Shadow bytes around the buggy address: + 0x0fe458c572a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa + 0x0fe458c572b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa + 0x0fe458c572c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa + 0x0fe458c572d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa + 0x0fe458c572e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa + =>0x0fe458c572f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa[fa] + 0x0fe458c57300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0x0fe458c57310: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0x0fe458c57320: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0x0fe458c57330: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0x0fe458c57340: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + Shadow byte legend (one shadow byte represents 8 application bytes): + Addressable: 00 + Partially addressable: 01 02 03 04 05 06 07 + Heap left redzone: fa + Freed heap region: fd + Stack left redzone: f1 + Stack mid redzone: f2 + Stack right redzone: f3 + Stack after return: f5 + Stack use after scope: f8 + Global redzone: f9 + Global init order: f6 + Poisoned by user: f7 + Container overflow: fc + Array cookie: ac + Intra object redzone: bb + ASan internal: fe + Left alloca redzone: ca + Right alloca redzone: cb + ==8340==ABORTING + +The pretty format can also be used in `git archive` operations via the +`export-subst` attribute. So this is what in our opinion makes this a +critical issue in the context of Git forges which allow to download an +archive of user supplied Git repositories. + +Fix this vulnerability by using `size_t` instead of `int` to track the +string lengths. Add tests which detect this vulnerability when Git is +compiled with the address sanitizer. + +Reported-by: Joern Schneeweisz <jschneeweisz@gitlab.com> +Original-patch-by: Joern Schneeweisz <jschneeweisz@gitlab.com> +Modified-by: Taylor Blau <me@ttalorr.com> +Signed-off-by: Patrick Steinhardt <ps@pks.im> +Signed-off-by: Junio C Hamano <gitster@pobox.com> + +Upstream-Status: Backport [https://github.com/git/git/commit/81dc898df9b4b4035534a927f3234a3839b698bf] +CVE: CVE-2022-41903 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + pretty.c | 11 ++++++----- + t/t4205-log-pretty-formats.sh | 17 +++++++++++++++++ + 2 files changed, 23 insertions(+), 5 deletions(-) + +diff --git a/pretty.c b/pretty.c +index b32f036..637e344 100644 +--- a/pretty.c ++++ b/pretty.c +@@ -1427,7 +1427,9 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */ + struct format_commit_context *c) + { + struct strbuf local_sb = STRBUF_INIT; +- int total_consumed = 0, len, padding = c->padding; ++ size_t total_consumed = 0; ++ int len, padding = c->padding; ++ + if (padding < 0) { + const char *start = strrchr(sb->buf, '\n'); + int occupied; +@@ -1439,7 +1441,7 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */ + } + while (1) { + int modifier = *placeholder == 'C'; +- int consumed = format_commit_one(&local_sb, placeholder, c); ++ size_t consumed = format_commit_one(&local_sb, placeholder, c); + total_consumed += consumed; + + if (!modifier) +@@ -1505,7 +1507,7 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */ + } + strbuf_addbuf(sb, &local_sb); + } else { +- int sb_len = sb->len, offset = 0; ++ size_t sb_len = sb->len, offset = 0; + if (c->flush_type == flush_left) + offset = padding - len; + else if (c->flush_type == flush_both) +@@ -1528,8 +1530,7 @@ static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */ + const char *placeholder, + void *context) + { +- int consumed; +- size_t orig_len; ++ size_t consumed, orig_len; + enum { + NO_MAGIC, + ADD_LF_BEFORE_NON_EMPTY, +diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh +index f42a69f..a2acee1 100755 +--- a/t/t4205-log-pretty-formats.sh ++++ b/t/t4205-log-pretty-formats.sh +@@ -788,4 +788,21 @@ test_expect_success '%S in git log --format works with other placeholders (part + test_cmp expect actual + ' + ++test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'log --pretty with huge commit message' ' ++ # We only assert that this command does not crash. This needs to be ++ # executed with the address sanitizer to demonstrate failure. ++ git log -1 --pretty="format:%>(2147483646)%x41%41%>(2147483646)%x41" >/dev/null ++' ++ ++test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'set up huge commit' ' ++ test-tool genzeros 2147483649 | tr "\000" "1" >expect && ++ huge_commit=$(git commit-tree -F expect HEAD^{tree}) ++' ++ ++test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'log --pretty with huge commit message' ' ++ git log -1 --format="%B%<(1)%x30" $huge_commit >actual && ++ echo 0 >>expect && ++ test_cmp expect actual ++' ++ + test_done +-- +2.25.1 + diff --git a/meta/recipes-devtools/git/files/CVE-2022-41903-03.patch b/meta/recipes-devtools/git/files/CVE-2022-41903-03.patch new file mode 100644 index 0000000000..d83d77eaf7 --- /dev/null +++ b/meta/recipes-devtools/git/files/CVE-2022-41903-03.patch @@ -0,0 +1,146 @@ +From b49f309aa16febeddb65e82526640a91bbba3be3 Mon Sep 17 00:00:00 2001 +From: Patrick Steinhardt <ps@pks.im> +Date: Thu, 1 Dec 2022 15:46:30 +0100 +Subject: [PATCH 03/12] pretty: fix out-of-bounds read when left-flushing with stealing + +With the `%>>(<N>)` pretty formatter, you can ask git-log(1) et al to +steal spaces. To do so we need to look ahead of the next token to see +whether there are spaces there. This loop takes into account ANSI +sequences that end with an `m`, and if it finds any it will skip them +until it finds the first space. While doing so it does not take into +account the buffer's limits though and easily does an out-of-bounds +read. + +Add a test that hits this behaviour. While we don't have an easy way to +verify this, the test causes the following failure when run with +`SANITIZE=address`: + + ==37941==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x603000000baf at pc 0x55ba6f88e0d0 bp 0x7ffc84c50d20 sp 0x7ffc84c50d10 + READ of size 1 at 0x603000000baf thread T0 + #0 0x55ba6f88e0cf in format_and_pad_commit pretty.c:1712 + #1 0x55ba6f88e7b4 in format_commit_item pretty.c:1801 + #2 0x55ba6f9b1ae4 in strbuf_expand strbuf.c:429 + #3 0x55ba6f88f020 in repo_format_commit_message pretty.c:1869 + #4 0x55ba6f890ccf in pretty_print_commit pretty.c:2161 + #5 0x55ba6f7884c8 in show_log log-tree.c:781 + #6 0x55ba6f78b6ba in log_tree_commit log-tree.c:1117 + #7 0x55ba6f40fed5 in cmd_log_walk_no_free builtin/log.c:508 + #8 0x55ba6f41035b in cmd_log_walk builtin/log.c:549 + #9 0x55ba6f4131a2 in cmd_log builtin/log.c:883 + #10 0x55ba6f2ea993 in run_builtin git.c:466 + #11 0x55ba6f2eb397 in handle_builtin git.c:721 + #12 0x55ba6f2ebb07 in run_argv git.c:788 + #13 0x55ba6f2ec8a7 in cmd_main git.c:923 + #14 0x55ba6f581682 in main common-main.c:57 + #15 0x7f2d08c3c28f (/usr/lib/libc.so.6+0x2328f) + #16 0x7f2d08c3c349 in __libc_start_main (/usr/lib/libc.so.6+0x23349) + #17 0x55ba6f2e60e4 in _start ../sysdeps/x86_64/start.S:115 + + 0x603000000baf is located 1 bytes to the left of 24-byte region [0x603000000bb0,0x603000000bc8) + allocated by thread T0 here: + #0 0x7f2d08ebe7ea in __interceptor_realloc /usr/src/debug/gcc/libsanitizer/asan/asan_malloc_linux.cpp:85 + #1 0x55ba6fa5b494 in xrealloc wrapper.c:136 + #2 0x55ba6f9aefdc in strbuf_grow strbuf.c:99 + #3 0x55ba6f9b0a06 in strbuf_add strbuf.c:298 + #4 0x55ba6f9b1a25 in strbuf_expand strbuf.c:418 + #5 0x55ba6f88f020 in repo_format_commit_message pretty.c:1869 + #6 0x55ba6f890ccf in pretty_print_commit pretty.c:2161 + #7 0x55ba6f7884c8 in show_log log-tree.c:781 + #8 0x55ba6f78b6ba in log_tree_commit log-tree.c:1117 + #9 0x55ba6f40fed5 in cmd_log_walk_no_free builtin/log.c:508 + #10 0x55ba6f41035b in cmd_log_walk builtin/log.c:549 + #11 0x55ba6f4131a2 in cmd_log builtin/log.c:883 + #12 0x55ba6f2ea993 in run_builtin git.c:466 + #13 0x55ba6f2eb397 in handle_builtin git.c:721 + #14 0x55ba6f2ebb07 in run_argv git.c:788 + #15 0x55ba6f2ec8a7 in cmd_main git.c:923 + #16 0x55ba6f581682 in main common-main.c:57 + #17 0x7f2d08c3c28f (/usr/lib/libc.so.6+0x2328f) + #18 0x7f2d08c3c349 in __libc_start_main (/usr/lib/libc.so.6+0x23349) + #19 0x55ba6f2e60e4 in _start ../sysdeps/x86_64/start.S:115 + + SUMMARY: AddressSanitizer: heap-buffer-overflow pretty.c:1712 in format_and_pad_commit + Shadow bytes around the buggy address: + 0x0c067fff8120: fa fa fd fd fd fa fa fa fd fd fd fa fa fa fd fd + 0x0c067fff8130: fd fd fa fa fd fd fd fd fa fa fd fd fd fa fa fa + 0x0c067fff8140: fd fd fd fa fa fa fd fd fd fa fa fa fd fd fd fa + 0x0c067fff8150: fa fa fd fd fd fd fa fa 00 00 00 fa fa fa fd fd + 0x0c067fff8160: fd fa fa fa fd fd fd fa fa fa fd fd fd fa fa fa + =>0x0c067fff8170: fd fd fd fa fa[fa]00 00 00 fa fa fa 00 00 00 fa + 0x0c067fff8180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa + 0x0c067fff8190: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa + 0x0c067fff81a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa + 0x0c067fff81b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa + 0x0c067fff81c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa + Shadow byte legend (one shadow byte represents 8 application bytes): + Addressable: 00 + Partially addressable: 01 02 03 04 05 06 07 + Heap left redzone: fa + Freed heap region: fd + Stack left redzone: f1 + Stack mid redzone: f2 + Stack right redzone: f3 + Stack after return: f5 + Stack use after scope: f8 + Global redzone: f9 + Global init order: f6 + Poisoned by user: f7 + Container overflow: fc + Array cookie: ac + Intra object redzone: bb + ASan internal: fe + Left alloca redzone: ca + Right alloca redzone: cb + +Luckily enough, this would only cause us to copy the out-of-bounds data +into the formatted commit in case we really had an ANSI sequence +preceding our buffer. So this bug likely has no security consequences. + +Fix it regardless by not traversing past the buffer's start. + +Reported-by: Patrick Steinhardt <ps@pks.im> +Reported-by: Eric Sesterhenn <eric.sesterhenn@x41-dsec.de> +Signed-off-by: Patrick Steinhardt <ps@pks.im> +Signed-off-by: Junio C Hamano <gitster@pobox.com> + +Upstream-Status: Backport [https://github.com/git/git/commit/b49f309aa16febeddb65e82526640a91bbba3be3] +CVE: CVE-2022-41903 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + pretty.c | 2 +- + t/t4205-log-pretty-formats.sh | 6 ++++++ + 2 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/pretty.c b/pretty.c +index 637e344..4348a82 100644 +--- a/pretty.c ++++ b/pretty.c +@@ -1468,7 +1468,7 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */ + if (*ch != 'm') + break; + p = ch - 1; +- while (ch - p < 10 && *p != '\033') ++ while (p > sb->buf && ch - p < 10 && *p != '\033') + p--; + if (*p != '\033' || + ch + 1 - p != display_mode_esc_sequence_len(p)) +diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh +index a2acee1..e69caba 100755 +--- a/t/t4205-log-pretty-formats.sh ++++ b/t/t4205-log-pretty-formats.sh +@@ -788,6 +788,12 @@ test_expect_success '%S in git log --format works with other placeholders (part + test_cmp expect actual + ' + ++test_expect_success 'log --pretty with space stealing' ' ++ printf mm0 >expect && ++ git log -1 --pretty="format:mm%>>|(1)%x30" >actual && ++ test_cmp expect actual ++' ++ + test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'log --pretty with huge commit message' ' + # We only assert that this command does not crash. This needs to be + # executed with the address sanitizer to demonstrate failure. +-- +2.25.1 + diff --git a/meta/recipes-devtools/git/files/CVE-2022-41903-04.patch b/meta/recipes-devtools/git/files/CVE-2022-41903-04.patch new file mode 100644 index 0000000000..9e3c74ff67 --- /dev/null +++ b/meta/recipes-devtools/git/files/CVE-2022-41903-04.patch @@ -0,0 +1,150 @@ +From f6e0b9f38987ad5e47bab551f8760b70689a5905 Mon Sep 17 00:00:00 2001 +From: Patrick Steinhardt <ps@pks.im> +Date: Thu, 1 Dec 2022 15:46:34 +0100 +Subject: [PATCH 04/12] pretty: fix out-of-bounds read when parsing invalid padding format + +An out-of-bounds read can be triggered when parsing an incomplete +padding format string passed via `--pretty=format` or in Git archives +when files are marked with the `export-subst` gitattribute. + +This bug exists since we have introduced support for truncating output +via the `trunc` keyword a7f01c6 (pretty: support truncating in %>, %< +and %><, 2013-04-19). Before this commit, we used to find the end of the +formatting string by using strchr(3P). This function returns a `NULL` +pointer in case the character in question wasn't found. The subsequent +check whether any character was found thus simply checked the returned +pointer. After the commit we switched to strcspn(3P) though, which only +returns the offset to the first found character or to the trailing NUL +byte. As the end pointer is now computed by adding the offset to the +start pointer it won't be `NULL` anymore, and as a consequence the check +doesn't do anything anymore. + +The out-of-bounds data that is being read can in fact end up in the +formatted string. As a consequence, it is possible to leak memory +contents either by calling git-log(1) or via git-archive(1) when any of +the archived files is marked with the `export-subst` gitattribute. + + ==10888==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000398 at pc 0x7f0356047cb2 bp 0x7fff3ffb95d0 sp 0x7fff3ffb8d78 + READ of size 1 at 0x602000000398 thread T0 + #0 0x7f0356047cb1 in __interceptor_strchrnul /usr/src/debug/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:725 + #1 0x563b7cec9a43 in strbuf_expand strbuf.c:417 + #2 0x563b7cda7060 in repo_format_commit_message pretty.c:1869 + #3 0x563b7cda8d0f in pretty_print_commit pretty.c:2161 + #4 0x563b7cca04c8 in show_log log-tree.c:781 + #5 0x563b7cca36ba in log_tree_commit log-tree.c:1117 + #6 0x563b7c927ed5 in cmd_log_walk_no_free builtin/log.c:508 + #7 0x563b7c92835b in cmd_log_walk builtin/log.c:549 + #8 0x563b7c92b1a2 in cmd_log builtin/log.c:883 + #9 0x563b7c802993 in run_builtin git.c:466 + #10 0x563b7c803397 in handle_builtin git.c:721 + #11 0x563b7c803b07 in run_argv git.c:788 + #12 0x563b7c8048a7 in cmd_main git.c:923 + #13 0x563b7ca99682 in main common-main.c:57 + #14 0x7f0355e3c28f (/usr/lib/libc.so.6+0x2328f) + #15 0x7f0355e3c349 in __libc_start_main (/usr/lib/libc.so.6+0x23349) + #16 0x563b7c7fe0e4 in _start ../sysdeps/x86_64/start.S:115 + + 0x602000000398 is located 0 bytes to the right of 8-byte region [0x602000000390,0x602000000398) + allocated by thread T0 here: + #0 0x7f0356072faa in __interceptor_strdup /usr/src/debug/gcc/libsanitizer/asan/asan_interceptors.cpp:439 + #1 0x563b7cf7317c in xstrdup wrapper.c:39 + #2 0x563b7cd9a06a in save_user_format pretty.c:40 + #3 0x563b7cd9b3e5 in get_commit_format pretty.c:173 + #4 0x563b7ce54ea0 in handle_revision_opt revision.c:2456 + #5 0x563b7ce597c9 in setup_revisions revision.c:2850 + #6 0x563b7c9269e0 in cmd_log_init_finish builtin/log.c:269 + #7 0x563b7c927362 in cmd_log_init builtin/log.c:348 + #8 0x563b7c92b193 in cmd_log builtin/log.c:882 + #9 0x563b7c802993 in run_builtin git.c:466 + #10 0x563b7c803397 in handle_builtin git.c:721 + #11 0x563b7c803b07 in run_argv git.c:788 + #12 0x563b7c8048a7 in cmd_main git.c:923 + #13 0x563b7ca99682 in main common-main.c:57 + #14 0x7f0355e3c28f (/usr/lib/libc.so.6+0x2328f) + #15 0x7f0355e3c349 in __libc_start_main (/usr/lib/libc.so.6+0x23349) + #16 0x563b7c7fe0e4 in _start ../sysdeps/x86_64/start.S:115 + + SUMMARY: AddressSanitizer: heap-buffer-overflow /usr/src/debug/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:725 in __interceptor_strchrnul + Shadow bytes around the buggy address: + 0x0c047fff8020: fa fa fd fd fa fa 00 06 fa fa 05 fa fa fa fd fd + 0x0c047fff8030: fa fa 00 02 fa fa 06 fa fa fa 05 fa fa fa fd fd + 0x0c047fff8040: fa fa 00 07 fa fa 03 fa fa fa fd fd fa fa 00 00 + 0x0c047fff8050: fa fa 00 01 fa fa fd fd fa fa 00 00 fa fa 00 01 + 0x0c047fff8060: fa fa 00 06 fa fa 00 06 fa fa 05 fa fa fa 05 fa + =>0x0c047fff8070: fa fa 00[fa]fa fa fd fa fa fa fd fd fa fa fd fd + 0x0c047fff8080: fa fa fd fd fa fa 00 00 fa fa 00 fa fa fa fd fa + 0x0c047fff8090: fa fa fd fd fa fa 00 00 fa fa fa fa fa fa fa fa + 0x0c047fff80a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa + 0x0c047fff80b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa + 0x0c047fff80c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa + Shadow byte legend (one shadow byte represents 8 application bytes): + Addressable: 00 + Partially addressable: 01 02 03 04 05 06 07 + Heap left redzone: fa + Freed heap region: fd + Stack left redzone: f1 + Stack mid redzone: f2 + Stack right redzone: f3 + Stack after return: f5 + Stack use after scope: f8 + Global redzone: f9 + Global init order: f6 + Poisoned by user: f7 + Container overflow: fc + Array cookie: ac + Intra object redzone: bb + ASan internal: fe + Left alloca redzone: ca + Right alloca redzone: cb + ==10888==ABORTING + +Fix this bug by checking whether `end` points at the trailing NUL byte. +Add a test which catches this out-of-bounds read and which demonstrates +that we used to write out-of-bounds data into the formatted message. + +Reported-by: Markus Vervier <markus.vervier@x41-dsec.de> +Original-patch-by: Markus Vervier <markus.vervier@x41-dsec.de> +Signed-off-by: Patrick Steinhardt <ps@pks.im> +Signed-off-by: Junio C Hamano <gitster@pobox.com> + +Upstream-Status: Backport [https://github.com/git/git/commit/f6e0b9f38987ad5e47bab551f8760b70689a5905] +CVE: CVE-2022-41903 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + pretty.c | 2 +- + t/t4205-log-pretty-formats.sh | 6 ++++++ + 2 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/pretty.c b/pretty.c +index 4348a82..c49e818 100644 +--- a/pretty.c ++++ b/pretty.c +@@ -1024,7 +1024,7 @@ static size_t parse_padding_placeholder(const char *placeholder, + const char *end = start + strcspn(start, ",)"); + char *next; + int width; +- if (!end || end == start) ++ if (!*end || end == start) + return 0; + width = strtol(start, &next, 10); + if (next == start || width == 0) +diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh +index e69caba..8a349df 100755 +--- a/t/t4205-log-pretty-formats.sh ++++ b/t/t4205-log-pretty-formats.sh +@@ -794,6 +794,12 @@ test_expect_success 'log --pretty with space stealing' ' + test_cmp expect actual + ' + ++test_expect_success 'log --pretty with invalid padding format' ' ++ printf "%s%%<(20" "$(git rev-parse HEAD)" >expect && ++ git log -1 --pretty="format:%H%<(20" >actual && ++ test_cmp expect actual ++' ++ + test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'log --pretty with huge commit message' ' + # We only assert that this command does not crash. This needs to be + # executed with the address sanitizer to demonstrate failure. +-- +2.25.1 + diff --git a/meta/recipes-devtools/git/files/CVE-2022-41903-05.patch b/meta/recipes-devtools/git/files/CVE-2022-41903-05.patch new file mode 100644 index 0000000000..994f7a55b1 --- /dev/null +++ b/meta/recipes-devtools/git/files/CVE-2022-41903-05.patch @@ -0,0 +1,98 @@ +From 1de69c0cdd388b0a5b7bdde0bfa0bda514a354b0 Mon Sep 17 00:00:00 2001 +From: Patrick Steinhardt <ps@pks.im> +Date: Thu, 1 Dec 2022 15:46:39 +0100 +Subject: [PATCH 05/12] pretty: fix adding linefeed when placeholder is not expanded + +When a formatting directive has a `+` or ` ` after the `%`, then we add +either a line feed or space if the placeholder expands to a non-empty +string. In specific cases though this logic doesn't work as expected, +and we try to add the character even in the case where the formatting +directive is empty. + +One such pattern is `%w(1)%+d%+w(2)`. `%+d` expands to reference names +pointing to a certain commit, like in `git log --decorate`. For a tagged +commit this would for example expand to `\n (tag: v1.0.0)`, which has a +leading newline due to the `+` modifier and a space added by `%d`. Now +the second wrapping directive will cause us to rewrap the text to +`\n(tag:\nv1.0.0)`, which is one byte shorter due to the missing leading +space. The code that handles the `+` magic now notices that the length +has changed and will thus try to insert a leading line feed at the +original posititon. But as the string was shortened, the original +position is past the buffer's boundary and thus we die with an error. + +Now there are two issues here: + + 1. We check whether the buffer length has changed, not whether it + has been extended. This causes us to try and add the character + past the string boundary. + + 2. The current logic does not make any sense whatsoever. When the + string got expanded due to the rewrap, putting the separator into + the original position is likely to put it somewhere into the + middle of the rewrapped contents. + +It is debatable whether `%+w()` makes any sense in the first place. +Strictly speaking, the placeholder never expands to a non-empty string, +and consequentially we shouldn't ever accept this combination. We thus +fix the bug by simply refusing `%+w()`. + +Signed-off-by: Patrick Steinhardt <ps@pks.im> +Signed-off-by: Junio C Hamano <gitster@pobox.com> + +Upstream-Status: Backport [https://github.com/git/git/commit/1de69c0cdd388b0a5b7bdde0bfa0bda514a354b0] +CVE: CVE-2022-41903 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + pretty.c | 14 +++++++++++++- + t/t4205-log-pretty-formats.sh | 8 ++++++++ + 2 files changed, 21 insertions(+), 1 deletion(-) + +diff --git a/pretty.c b/pretty.c +index c49e818..195d005 100644 +--- a/pretty.c ++++ b/pretty.c +@@ -1551,9 +1551,21 @@ static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */ + default: + break; + } +- if (magic != NO_MAGIC) ++ if (magic != NO_MAGIC) { + placeholder++; + ++ switch (placeholder[0]) { ++ case 'w': ++ /* ++ * `%+w()` cannot ever expand to a non-empty string, ++ * and it potentially changes the layout of preceding ++ * contents. We're thus not able to handle the magic in ++ * this combination and refuse the pattern. ++ */ ++ return 0; ++ }; ++ } ++ + orig_len = sb->len; + if (((struct format_commit_context *)context)->flush_type != no_flush) + consumed = format_and_pad_commit(sb, placeholder, context); +diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh +index 8a349df..fa1bc2b 100755 +--- a/t/t4205-log-pretty-formats.sh ++++ b/t/t4205-log-pretty-formats.sh +@@ -800,6 +800,14 @@ test_expect_success 'log --pretty with invalid padding format' ' + test_cmp expect actual + ' + ++test_expect_success 'log --pretty with magical wrapping directives' ' ++ commit_id=$(git commit-tree HEAD^{tree} -m "describe me") && ++ git tag describe-me $commit_id && ++ printf "\n(tag:\ndescribe-me)%%+w(2)" >expect && ++ git log -1 --pretty="format:%w(1)%+d%+w(2)" $commit_id >actual && ++ test_cmp expect actual ++' ++ + test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'log --pretty with huge commit message' ' + # We only assert that this command does not crash. This needs to be + # executed with the address sanitizer to demonstrate failure. +-- +2.25.1 + diff --git a/meta/recipes-devtools/git/files/CVE-2022-41903-06.patch b/meta/recipes-devtools/git/files/CVE-2022-41903-06.patch new file mode 100644 index 0000000000..93fbe5c7fe --- /dev/null +++ b/meta/recipes-devtools/git/files/CVE-2022-41903-06.patch @@ -0,0 +1,90 @@ +From 48050c42c73c28b0c001d63d11dffac7e116847b Mon Sep 17 00:00:00 2001 +From: Patrick Steinhardt <ps@pks.im> +Date: Thu, 1 Dec 2022 15:46:49 +0100 +Subject: [PATCH 06/12] pretty: fix integer overflow in wrapping format + +The `%w(width,indent1,indent2)` formatting directive can be used to +rewrap text to a specific width and is designed after git-shortlog(1)'s +`-w` parameter. While the three parameters are all stored as `size_t` +internally, `strbuf_add_wrapped_text()` accepts integers as input. As a +result, the casted integers may overflow. As these now-negative integers +are later on passed to `strbuf_addchars()`, we will ultimately run into +implementation-defined behaviour due to casting a negative number back +to `size_t` again. On my platform, this results in trying to allocate +9000 petabyte of memory. + +Fix this overflow by using `cast_size_t_to_int()` so that we reject +inputs that cannot be represented as an integer. + +Signed-off-by: Patrick Steinhardt <ps@pks.im> +Signed-off-by: Junio C Hamano <gitster@pobox.com> + +Upstream-Status: Backport [https://github.com/git/git/commit/48050c42c73c28b0c001d63d11dffac7e116847b] +CVE: CVE-2022-41903 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + git-compat-util.h | 8 ++++++++ + pretty.c | 4 +++- + t/t4205-log-pretty-formats.sh | 12 ++++++++++++ + 3 files changed, 23 insertions(+), 1 deletion(-) + +diff --git a/git-compat-util.h b/git-compat-util.h +index a1ecfd3..b0f3890 100644 +--- a/git-compat-util.h ++++ b/git-compat-util.h +@@ -854,6 +854,14 @@ static inline size_t st_sub(size_t a, size_t b) + return a - b; + } + ++static inline int cast_size_t_to_int(size_t a) ++{ ++ if (a > INT_MAX) ++ die("number too large to represent as int on this platform: %"PRIuMAX, ++ (uintmax_t)a); ++ return (int)a; ++} ++ + #ifdef HAVE_ALLOCA_H + # include <alloca.h> + # define xalloca(size) (alloca(size)) +diff --git a/pretty.c b/pretty.c +index 195d005..ff9fc97 100644 +--- a/pretty.c ++++ b/pretty.c +@@ -898,7 +898,9 @@ static void strbuf_wrap(struct strbuf *sb, size_t pos, + if (pos) + strbuf_add(&tmp, sb->buf, pos); + strbuf_add_wrapped_text(&tmp, sb->buf + pos, +- (int) indent1, (int) indent2, (int) width); ++ cast_size_t_to_int(indent1), ++ cast_size_t_to_int(indent2), ++ cast_size_t_to_int(width)); + strbuf_swap(&tmp, sb); + strbuf_release(&tmp); + } +diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh +index fa1bc2b..23ac508 100755 +--- a/t/t4205-log-pretty-formats.sh ++++ b/t/t4205-log-pretty-formats.sh +@@ -808,6 +808,18 @@ test_expect_success 'log --pretty with magical wrapping directives' ' + test_cmp expect actual + ' + ++test_expect_success SIZE_T_IS_64BIT 'log --pretty with overflowing wrapping directive' ' ++ cat >expect <<-EOF && ++ fatal: number too large to represent as int on this platform: 2147483649 ++ EOF ++ test_must_fail git log -1 --pretty="format:%w(2147483649,1,1)%d" 2>error && ++ test_cmp expect error && ++ test_must_fail git log -1 --pretty="format:%w(1,2147483649,1)%d" 2>error && ++ test_cmp expect error && ++ test_must_fail git log -1 --pretty="format:%w(1,1,2147483649)%d" 2>error && ++ test_cmp expect error ++' ++ + test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'log --pretty with huge commit message' ' + # We only assert that this command does not crash. This needs to be + # executed with the address sanitizer to demonstrate failure. +-- +2.25.1 + diff --git a/meta/recipes-devtools/git/files/CVE-2022-41903-07.patch b/meta/recipes-devtools/git/files/CVE-2022-41903-07.patch new file mode 100644 index 0000000000..ec248ad6c2 --- /dev/null +++ b/meta/recipes-devtools/git/files/CVE-2022-41903-07.patch @@ -0,0 +1,123 @@ +From 522cc87fdc25449222a5894a428eebf4b8d5eaa9 Mon Sep 17 00:00:00 2001 +From: Patrick Steinhardt <ps@pks.im> +Date: Thu, 1 Dec 2022 15:46:53 +0100 +Subject: [PATCH 07/12] utf8: fix truncated string lengths in utf8_strnwidth() + +The `utf8_strnwidth()` function accepts an optional string length as +input parameter. This parameter can either be set to `-1`, in which case +we call `strlen()` on the input. Or it can be set to a positive integer +that indicates a precomputed length, which callers typically compute by +calling `strlen()` at some point themselves. + +The input parameter is an `int` though, whereas `strlen()` returns a +`size_t`. This can lead to implementation-defined behaviour though when +the `size_t` cannot be represented by the `int`. In the general case +though this leads to wrap-around and thus to negative string sizes, +which is sure enough to not lead to well-defined behaviour. + +Fix this by accepting a `size_t` instead of an `int` as string length. +While this takes away the ability of callers to simply pass in `-1` as +string length, it really is trivial enough to convert them to instead +pass in `strlen()` instead. + +Signed-off-by: Patrick Steinhardt <ps@pks.im> +Signed-off-by: Junio C Hamano <gitster@pobox.com> + +Upstream-Status: Backport [https://github.com/git/git/commit/522cc87fdc25449222a5894a428eebf4b8d5eaa9] +CVE: CVE-2022-41903 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + column.c | 2 +- + pretty.c | 4 ++-- + utf8.c | 8 +++----- + utf8.h | 2 +- + 4 files changed, 7 insertions(+), 9 deletions(-) + +diff --git a/column.c b/column.c +index 4a38eed..0c79850 100644 +--- a/column.c ++++ b/column.c +@@ -23,7 +23,7 @@ struct column_data { + /* return length of 's' in letters, ANSI escapes stripped */ + static int item_length(const char *s) + { +- return utf8_strnwidth(s, -1, 1); ++ return utf8_strnwidth(s, strlen(s), 1); + } + + /* +diff --git a/pretty.c b/pretty.c +index ff9fc97..c3c1443 100644 +--- a/pretty.c ++++ b/pretty.c +@@ -1437,7 +1437,7 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */ + int occupied; + if (!start) + start = sb->buf; +- occupied = utf8_strnwidth(start, -1, 1); ++ occupied = utf8_strnwidth(start, strlen(start), 1); + occupied += c->pretty_ctx->graph_width; + padding = (-padding) - occupied; + } +@@ -1455,7 +1455,7 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */ + placeholder++; + total_consumed++; + } +- len = utf8_strnwidth(local_sb.buf, -1, 1); ++ len = utf8_strnwidth(local_sb.buf, local_sb.len, 1); + + if (c->flush_type == flush_left_and_steal) { + const char *ch = sb->buf + sb->len - 1; +diff --git a/utf8.c b/utf8.c +index 5c8f151..a66984b 100644 +--- a/utf8.c ++++ b/utf8.c +@@ -206,13 +206,11 @@ int utf8_width(const char **start, size_t *remainder_p) + * string, assuming that the string is utf8. Returns strlen() instead + * if the string does not look like a valid utf8 string. + */ +-int utf8_strnwidth(const char *string, int len, int skip_ansi) ++int utf8_strnwidth(const char *string, size_t len, int skip_ansi) + { + int width = 0; + const char *orig = string; + +- if (len == -1) +- len = strlen(string); + while (string && string < orig + len) { + int skip; + while (skip_ansi && +@@ -225,7 +223,7 @@ int utf8_strnwidth(const char *string, int len, int skip_ansi) + + int utf8_strwidth(const char *string) + { +- return utf8_strnwidth(string, -1, 0); ++ return utf8_strnwidth(string, strlen(string), 0); + } + + int is_utf8(const char *text) +@@ -792,7 +790,7 @@ int skip_utf8_bom(char **text, size_t len) + void strbuf_utf8_align(struct strbuf *buf, align_type position, unsigned int width, + const char *s) + { +- int slen = strlen(s); ++ size_t slen = strlen(s); + int display_len = utf8_strnwidth(s, slen, 0); + int utf8_compensation = slen - display_len; + +diff --git a/utf8.h b/utf8.h +index fcd5167..6da1b6d 100644 +--- a/utf8.h ++++ b/utf8.h +@@ -7,7 +7,7 @@ typedef unsigned int ucs_char_t; /* assuming 32bit int */ + + size_t display_mode_esc_sequence_len(const char *s); + int utf8_width(const char **start, size_t *remainder_p); +-int utf8_strnwidth(const char *string, int len, int skip_ansi); ++int utf8_strnwidth(const char *string, size_t len, int skip_ansi); + int utf8_strwidth(const char *string); + int is_utf8(const char *text); + int is_encoding_utf8(const char *name); +-- +2.25.1 + diff --git a/meta/recipes-devtools/git/files/CVE-2022-41903-08.patch b/meta/recipes-devtools/git/files/CVE-2022-41903-08.patch new file mode 100644 index 0000000000..3de6a5ba6a --- /dev/null +++ b/meta/recipes-devtools/git/files/CVE-2022-41903-08.patch @@ -0,0 +1,67 @@ +From 17d23e8a3812a5ca3dd6564e74d5250f22e5d76d Mon Sep 17 00:00:00 2001 +From: Patrick Steinhardt <ps@pks.im> +Date: Thu, 1 Dec 2022 15:47:00 +0100 +Subject: [PATCH 08/12] utf8: fix returning negative string width + +The `utf8_strnwidth()` function calls `utf8_width()` in a loop and adds +its returned width to the end result. `utf8_width()` can return `-1` +though in case it reads a control character, which means that the +computed string width is going to be wrong. In the worst case where +there are more control characters than non-control characters, we may +even return a negative string width. + +Fix this bug by treating control characters as having zero width. + +Signed-off-by: Patrick Steinhardt <ps@pks.im> +Signed-off-by: Junio C Hamano <gitster@pobox.com> + +Upstream-Status: Backport [https://github.com/git/git/commit/17d23e8a3812a5ca3dd6564e74d5250f22e5d76d] +CVE: CVE-2022-41903 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + t/t4205-log-pretty-formats.sh | 6 ++++++ + utf8.c | 8 ++++++-- + 2 files changed, 12 insertions(+), 2 deletions(-) + +diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh +index 23ac508..261a6f0 100755 +--- a/t/t4205-log-pretty-formats.sh ++++ b/t/t4205-log-pretty-formats.sh +@@ -820,6 +820,12 @@ test_expect_success SIZE_T_IS_64BIT 'log --pretty with overflowing wrapping dire + test_cmp expect error + ' + ++test_expect_success 'log --pretty with padding and preceding control chars' ' ++ printf "\20\20 0" >expect && ++ git log -1 --pretty="format:%x10%x10%>|(4)%x30" >actual && ++ test_cmp expect actual ++' ++ + test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'log --pretty with huge commit message' ' + # We only assert that this command does not crash. This needs to be + # executed with the address sanitizer to demonstrate failure. +diff --git a/utf8.c b/utf8.c +index a66984b..6632bd2 100644 +--- a/utf8.c ++++ b/utf8.c +@@ -212,11 +212,15 @@ int utf8_strnwidth(const char *string, size_t len, int skip_ansi) + const char *orig = string; + + while (string && string < orig + len) { +- int skip; ++ int glyph_width, skip; ++ + while (skip_ansi && + (skip = display_mode_esc_sequence_len(string)) != 0) + string += skip; +- width += utf8_width(&string, NULL); ++ ++ glyph_width = utf8_width(&string, NULL); ++ if (glyph_width > 0) ++ width += glyph_width; + } + return string ? width : len; + } +-- +2.25.1 + diff --git a/meta/recipes-devtools/git/files/CVE-2022-41903-09.patch b/meta/recipes-devtools/git/files/CVE-2022-41903-09.patch new file mode 100644 index 0000000000..761d4c6a9f --- /dev/null +++ b/meta/recipes-devtools/git/files/CVE-2022-41903-09.patch @@ -0,0 +1,162 @@ +From 937b71cc8b5b998963a7f9a33312ba3549d55510 Mon Sep 17 00:00:00 2001 +From: Patrick Steinhardt <ps@pks.im> +Date: Thu, 1 Dec 2022 15:47:04 +0100 +Subject: [PATCH 09/12] utf8: fix overflow when returning string width + +The return type of both `utf8_strwidth()` and `utf8_strnwidth()` is +`int`, but we operate on string lengths which are typically of type +`size_t`. This means that when the string is longer than `INT_MAX`, we +will overflow and thus return a negative result. + +This can lead to an out-of-bounds write with `--pretty=format:%<1)%B` +and a commit message that is 2^31+1 bytes long: + + ================================================================= + ==26009==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x603000001168 at pc 0x7f95c4e5f427 bp 0x7ffd8541c900 sp 0x7ffd8541c0a8 + WRITE of size 2147483649 at 0x603000001168 thread T0 + #0 0x7f95c4e5f426 in __interceptor_memcpy /usr/src/debug/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:827 + #1 0x5612bbb1068c in format_and_pad_commit pretty.c:1763 + #2 0x5612bbb1087a in format_commit_item pretty.c:1801 + #3 0x5612bbc33bab in strbuf_expand strbuf.c:429 + #4 0x5612bbb110e7 in repo_format_commit_message pretty.c:1869 + #5 0x5612bbb12d96 in pretty_print_commit pretty.c:2161 + #6 0x5612bba0a4d5 in show_log log-tree.c:781 + #7 0x5612bba0d6c7 in log_tree_commit log-tree.c:1117 + #8 0x5612bb691ed5 in cmd_log_walk_no_free builtin/log.c:508 + #9 0x5612bb69235b in cmd_log_walk builtin/log.c:549 + #10 0x5612bb6951a2 in cmd_log builtin/log.c:883 + #11 0x5612bb56c993 in run_builtin git.c:466 + #12 0x5612bb56d397 in handle_builtin git.c:721 + #13 0x5612bb56db07 in run_argv git.c:788 + #14 0x5612bb56e8a7 in cmd_main git.c:923 + #15 0x5612bb803682 in main common-main.c:57 + #16 0x7f95c4c3c28f (/usr/lib/libc.so.6+0x2328f) + #17 0x7f95c4c3c349 in __libc_start_main (/usr/lib/libc.so.6+0x23349) + #18 0x5612bb5680e4 in _start ../sysdeps/x86_64/start.S:115 + + 0x603000001168 is located 0 bytes to the right of 24-byte region [0x603000001150,0x603000001168) + allocated by thread T0 here: + #0 0x7f95c4ebe7ea in __interceptor_realloc /usr/src/debug/gcc/libsanitizer/asan/asan_malloc_linux.cpp:85 + #1 0x5612bbcdd556 in xrealloc wrapper.c:136 + #2 0x5612bbc310a3 in strbuf_grow strbuf.c:99 + #3 0x5612bbc32acd in strbuf_add strbuf.c:298 + #4 0x5612bbc33aec in strbuf_expand strbuf.c:418 + #5 0x5612bbb110e7 in repo_format_commit_message pretty.c:1869 + #6 0x5612bbb12d96 in pretty_print_commit pretty.c:2161 + #7 0x5612bba0a4d5 in show_log log-tree.c:781 + #8 0x5612bba0d6c7 in log_tree_commit log-tree.c:1117 + #9 0x5612bb691ed5 in cmd_log_walk_no_free builtin/log.c:508 + #10 0x5612bb69235b in cmd_log_walk builtin/log.c:549 + #11 0x5612bb6951a2 in cmd_log builtin/log.c:883 + #12 0x5612bb56c993 in run_builtin git.c:466 + #13 0x5612bb56d397 in handle_builtin git.c:721 + #14 0x5612bb56db07 in run_argv git.c:788 + #15 0x5612bb56e8a7 in cmd_main git.c:923 + #16 0x5612bb803682 in main common-main.c:57 + #17 0x7f95c4c3c28f (/usr/lib/libc.so.6+0x2328f) + + SUMMARY: AddressSanitizer: heap-buffer-overflow /usr/src/debug/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:827 in __interceptor_memcpy + Shadow bytes around the buggy address: + 0x0c067fff81d0: fd fd fd fa fa fa fd fd fd fa fa fa fd fd fd fa + 0x0c067fff81e0: fa fa fd fd fd fd fa fa fd fd fd fd fa fa fd fd + 0x0c067fff81f0: fd fa fa fa fd fd fd fa fa fa fd fd fd fa fa fa + 0x0c067fff8200: fd fd fd fa fa fa fd fd fd fd fa fa 00 00 00 fa + 0x0c067fff8210: fa fa fd fd fd fa fa fa fd fd fd fa fa fa fd fd + =>0x0c067fff8220: fd fa fa fa fd fd fd fa fa fa 00 00 00[fa]fa fa + 0x0c067fff8230: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa + 0x0c067fff8240: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa + 0x0c067fff8250: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa + 0x0c067fff8260: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa + 0x0c067fff8270: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa + Shadow byte legend (one shadow byte represents 8 application bytes): + Addressable: 00 + Partially addressable: 01 02 03 04 05 06 07 + Heap left redzone: fa + Freed heap region: fd + Stack left redzone: f1 + Stack mid redzone: f2 + Stack right redzone: f3 + Stack after return: f5 + Stack use after scope: f8 + Global redzone: f9 + Global init order: f6 + Poisoned by user: f7 + Container overflow: fc + Array cookie: ac + Intra object redzone: bb + ASan internal: fe + Left alloca redzone: ca + Right alloca redzone: cb + ==26009==ABORTING + +Now the proper fix for this would be to convert both functions to return +an `size_t` instead of an `int`. But given that this commit may be part +of a security release, let's instead do the minimal viable fix and die +in case we see an overflow. + +Add a test that would have previously caused us to crash. + +Signed-off-by: Patrick Steinhardt <ps@pks.im> +Signed-off-by: Junio C Hamano <gitster@pobox.com> + +Upstream-Status: Backport [https://github.com/git/git/commit/937b71cc8b5b998963a7f9a33312ba3549d55510] +CVE: CVE-2022-41903 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + t/t4205-log-pretty-formats.sh | 8 ++++++++ + utf8.c | 12 +++++++++--- + 2 files changed, 17 insertions(+), 3 deletions(-) + +diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh +index 261a6f0..de15007 100755 +--- a/t/t4205-log-pretty-formats.sh ++++ b/t/t4205-log-pretty-formats.sh +@@ -843,4 +843,12 @@ test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'log --pretty with huge commit mes + test_cmp expect actual + ' + ++test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'log --pretty with huge commit message does not cause allocation failure' ' ++ test_must_fail git log -1 --format="%<(1)%B" $huge_commit 2>error && ++ cat >expect <<-EOF && ++ fatal: number too large to represent as int on this platform: 2147483649 ++ EOF ++ test_cmp expect error ++' ++ + test_done +diff --git a/utf8.c b/utf8.c +index 6632bd2..03be475 100644 +--- a/utf8.c ++++ b/utf8.c +@@ -208,11 +208,12 @@ int utf8_width(const char **start, size_t *remainder_p) + */ + int utf8_strnwidth(const char *string, size_t len, int skip_ansi) + { +- int width = 0; + const char *orig = string; ++ size_t width = 0; + + while (string && string < orig + len) { +- int glyph_width, skip; ++ int glyph_width; ++ size_t skip; + + while (skip_ansi && + (skip = display_mode_esc_sequence_len(string)) != 0) +@@ -222,7 +223,12 @@ int utf8_strnwidth(const char *string, size_t len, int skip_ansi) + if (glyph_width > 0) + width += glyph_width; + } +- return string ? width : len; ++ ++ /* ++ * TODO: fix the interface of this function and `utf8_strwidth()` to ++ * return `size_t` instead of `int`. ++ */ ++ return cast_size_t_to_int(string ? width : len); + } + + int utf8_strwidth(const char *string) +-- +2.25.1 + diff --git a/meta/recipes-devtools/git/files/CVE-2022-41903-10.patch b/meta/recipes-devtools/git/files/CVE-2022-41903-10.patch new file mode 100644 index 0000000000..bbfc6e758f --- /dev/null +++ b/meta/recipes-devtools/git/files/CVE-2022-41903-10.patch @@ -0,0 +1,99 @@ +From 81c2d4c3a5ba0e6ab8c348708441fed170e63a82 Mon Sep 17 00:00:00 2001 +From: Patrick Steinhardt <ps@pks.im> +Date: Thu, 1 Dec 2022 15:47:10 +0100 +Subject: [PATCH 10/12] utf8: fix checking for glyph width in strbuf_utf8_replace() + +In `strbuf_utf8_replace()`, we call `utf8_width()` to compute the width +of the current glyph. If the glyph is a control character though it can +be that `utf8_width()` returns `-1`, but because we assign this value to +a `size_t` the conversion will cause us to underflow. This bug can +easily be triggered with the following command: + + $ git log --pretty='format:xxx%<|(1,trunc)%x10' + +>From all I can see though this seems to be a benign underflow that has +no security-related consequences. + +Fix the bug by using an `int` instead. When we see a control character, +we now copy it into the target buffer but don't advance the current +width of the string. + +Signed-off-by: Patrick Steinhardt <ps@pks.im> +Signed-off-by: Junio C Hamano <gitster@pobox.com> + +Upstream-Status: Backport [https://github.com/git/git/commit/81c2d4c3a5ba0e6ab8c348708441fed170e63a82] +CVE: CVE-2022-41903 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + t/t4205-log-pretty-formats.sh | 7 +++++++ + utf8.c | 19 ++++++++++++++----- + 2 files changed, 21 insertions(+), 5 deletions(-) + +diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh +index de15007..52c8bc8 100755 +--- a/t/t4205-log-pretty-formats.sh ++++ b/t/t4205-log-pretty-formats.sh +@@ -826,6 +826,13 @@ test_expect_success 'log --pretty with padding and preceding control chars' ' + test_cmp expect actual + ' + ++test_expect_success 'log --pretty truncation with control chars' ' ++ test_commit "$(printf "\20\20\20\20xxxx")" file contents commit-with-control-chars && ++ printf "\20\20\20\20x.." >expect && ++ git log -1 --pretty="format:%<(3,trunc)%s" commit-with-control-chars >actual && ++ test_cmp expect actual ++' ++ + test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'log --pretty with huge commit message' ' + # We only assert that this command does not crash. This needs to be + # executed with the address sanitizer to demonstrate failure. +diff --git a/utf8.c b/utf8.c +index 03be475..ec03e69 100644 +--- a/utf8.c ++++ b/utf8.c +@@ -377,6 +377,7 @@ void strbuf_utf8_replace(struct strbuf *sb_src, int pos, int width, + dst = sb_dst.buf; + + while (src < end) { ++ int glyph_width; + char *old; + size_t n; + +@@ -390,21 +391,29 @@ void strbuf_utf8_replace(struct strbuf *sb_src, int pos, int width, + break; + + old = src; +- n = utf8_width((const char**)&src, NULL); +- if (!src) /* broken utf-8, do nothing */ ++ glyph_width = utf8_width((const char**)&src, NULL); ++ if (!src) /* broken utf-8, do nothing */ + goto out; +- if (n && w >= pos && w < pos + width) { ++ ++ /* ++ * In case we see a control character we copy it into the ++ * buffer, but don't add it to the width. ++ */ ++ if (glyph_width < 0) ++ glyph_width = 0; ++ ++ if (glyph_width && w >= pos && w < pos + width) { + if (subst) { + memcpy(dst, subst, subst_len); + dst += subst_len; + subst = NULL; + } +- w += n; ++ w += glyph_width; + continue; + } + memcpy(dst, old, src - old); + dst += src - old; +- w += n; ++ w += glyph_width; + } + strbuf_setlen(&sb_dst, dst - sb_dst.buf); + strbuf_swap(sb_src, &sb_dst); +-- +2.25.1 + diff --git a/meta/recipes-devtools/git/files/CVE-2022-41903-11.patch b/meta/recipes-devtools/git/files/CVE-2022-41903-11.patch new file mode 100644 index 0000000000..f339edfc8a --- /dev/null +++ b/meta/recipes-devtools/git/files/CVE-2022-41903-11.patch @@ -0,0 +1,90 @@ +From f930a2394303b902e2973f4308f96529f736b8bc Mon Sep 17 00:00:00 2001 +From: Patrick Steinhardt <ps@pks.im> +Date: Thu, 1 Dec 2022 15:47:15 +0100 +Subject: [PATCH 11/12] utf8: refactor strbuf_utf8_replace to not rely on preallocated buffer + +In `strbuf_utf8_replace`, we preallocate the destination buffer and then +use `memcpy` to copy bytes into it at computed offsets. This feels +rather fragile and is hard to understand at times. Refactor the code to +instead use `strbuf_add` and `strbuf_addstr` so that we can be sure that +there is no possibility to perform an out-of-bounds write. + +Signed-off-by: Patrick Steinhardt <ps@pks.im> +Signed-off-by: Junio C Hamano <gitster@pobox.com> + +Upstream-Status: Backport [https://github.com/git/git/commit/f930a2394303b902e2973f4308f96529f736b8bc] +CVE: CVE-2022-41903 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + utf8.c | 34 +++++++++++++--------------------- + 1 file changed, 13 insertions(+), 21 deletions(-) + +diff --git a/utf8.c b/utf8.c +index ec03e69..a13f5e3 100644 +--- a/utf8.c ++++ b/utf8.c +@@ -365,26 +365,20 @@ void strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len, + void strbuf_utf8_replace(struct strbuf *sb_src, int pos, int width, + const char *subst) + { +- struct strbuf sb_dst = STRBUF_INIT; +- char *src = sb_src->buf; +- char *end = src + sb_src->len; +- char *dst; +- int w = 0, subst_len = 0; ++ const char *src = sb_src->buf, *end = sb_src->buf + sb_src->len; ++ struct strbuf dst; ++ int w = 0; + +- if (subst) +- subst_len = strlen(subst); +- strbuf_grow(&sb_dst, sb_src->len + subst_len); +- dst = sb_dst.buf; ++ strbuf_init(&dst, sb_src->len); + + while (src < end) { ++ const char *old; + int glyph_width; +- char *old; + size_t n; + + while ((n = display_mode_esc_sequence_len(src))) { +- memcpy(dst, src, n); ++ strbuf_add(&dst, src, n); + src += n; +- dst += n; + } + + if (src >= end) +@@ -404,21 +398,19 @@ void strbuf_utf8_replace(struct strbuf *sb_src, int pos, int width, + + if (glyph_width && w >= pos && w < pos + width) { + if (subst) { +- memcpy(dst, subst, subst_len); +- dst += subst_len; ++ strbuf_addstr(&dst, subst); + subst = NULL; + } +- w += glyph_width; +- continue; ++ } else { ++ strbuf_add(&dst, old, src - old); + } +- memcpy(dst, old, src - old); +- dst += src - old; ++ + w += glyph_width; + } +- strbuf_setlen(&sb_dst, dst - sb_dst.buf); +- strbuf_swap(sb_src, &sb_dst); ++ ++ strbuf_swap(sb_src, &dst); + out: +- strbuf_release(&sb_dst); ++ strbuf_release(&dst); + } + + /* +-- +2.25.1 + diff --git a/meta/recipes-devtools/git/files/CVE-2022-41903-12.patch b/meta/recipes-devtools/git/files/CVE-2022-41903-12.patch new file mode 100644 index 0000000000..978865978d --- /dev/null +++ b/meta/recipes-devtools/git/files/CVE-2022-41903-12.patch @@ -0,0 +1,124 @@ +From 304a50adff6480ede46b68f7545baab542cbfb46 Mon Sep 17 00:00:00 2001 +From: Patrick Steinhardt <ps@pks.im> +Date: Thu, 1 Dec 2022 15:47:23 +0100 +Subject: [PATCH 12/12] pretty: restrict input lengths for padding and wrapping formats + +Both the padding and wrapping formatting directives allow the caller to +specify an integer that ultimately leads to us adding this many chars to +the result buffer. As a consequence, it is trivial to e.g. allocate 2GB +of RAM via a single formatting directive and cause resource exhaustion +on the machine executing this logic. Furthermore, it is debatable +whether there are any sane usecases that require the user to pad data to +2GB boundaries or to indent wrapped data by 2GB. + +Restrict the input sizes to 16 kilobytes at a maximum to limit the +amount of bytes that can be requested by the user. This is not meant +as a fix because there are ways to trivially amplify the amount of +data we generate via formatting directives; the real protection is +achieved by the changes in previous steps to catch and avoid integer +wraparound that causes us to under-allocate and access beyond the +end of allocated memory reagions. But having such a limit +significantly helps fuzzing the pretty format, because the fuzzer is +otherwise quite fast to run out-of-memory as it discovers these +formatters. + +Signed-off-by: Patrick Steinhardt <ps@pks.im> +Signed-off-by: Junio C Hamano <gitster@pobox.com> + +Upstream-Status: Backport [https://github.com/git/git/commit/304a50adff6480ede46b68f7545baab542cbfb46] +CVE: CVE-2022-41903 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + pretty.c | 26 ++++++++++++++++++++++++++ + t/t4205-log-pretty-formats.sh | 24 +++++++++++++++--------- + 2 files changed, 41 insertions(+), 9 deletions(-) + +diff --git a/pretty.c b/pretty.c +index c3c1443..e9687f0 100644 +--- a/pretty.c ++++ b/pretty.c +@@ -13,6 +13,13 @@ + #include "gpg-interface.h" + #include "trailer.h" + ++/* ++ * The limit for formatting directives, which enable the caller to append ++ * arbitrarily many bytes to the formatted buffer. This includes padding ++ * and wrapping formatters. ++ */ ++#define FORMATTING_LIMIT (16 * 1024) ++ + static char *user_format; + static struct cmt_fmt_map { + const char *name; +@@ -1029,6 +1036,15 @@ static size_t parse_padding_placeholder(const char *placeholder, + if (!*end || end == start) + return 0; + width = strtol(start, &next, 10); ++ ++ /* ++ * We need to limit the amount of padding, or otherwise this ++ * would allow the user to pad the buffer by arbitrarily many ++ * bytes and thus cause resource exhaustion. ++ */ ++ if (width < -FORMATTING_LIMIT || width > FORMATTING_LIMIT) ++ return 0; ++ + if (next == start || width == 0) + return 0; + if (width < 0) { +@@ -1188,6 +1204,16 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */ + if (*next != ')') + return 0; + } ++ ++ /* ++ * We need to limit the format here as it allows the ++ * user to prepend arbitrarily many bytes to the buffer ++ * when rewrapping. ++ */ ++ if (width > FORMATTING_LIMIT || ++ indent1 > FORMATTING_LIMIT || ++ indent2 > FORMATTING_LIMIT) ++ return 0; + rewrap_message_tail(sb, c, width, indent1, indent2); + return end - placeholder + 1; + } else +diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh +index 52c8bc8..572d02f 100755 +--- a/t/t4205-log-pretty-formats.sh ++++ b/t/t4205-log-pretty-formats.sh +@@ -809,15 +809,21 @@ test_expect_success 'log --pretty with magical wrapping directives' ' + ' + + test_expect_success SIZE_T_IS_64BIT 'log --pretty with overflowing wrapping directive' ' +- cat >expect <<-EOF && +- fatal: number too large to represent as int on this platform: 2147483649 +- EOF +- test_must_fail git log -1 --pretty="format:%w(2147483649,1,1)%d" 2>error && +- test_cmp expect error && +- test_must_fail git log -1 --pretty="format:%w(1,2147483649,1)%d" 2>error && +- test_cmp expect error && +- test_must_fail git log -1 --pretty="format:%w(1,1,2147483649)%d" 2>error && +- test_cmp expect error ++ printf "%%w(2147483649,1,1)0" >expect && ++ git log -1 --pretty="format:%w(2147483649,1,1)%x30" >actual && ++ test_cmp expect actual && ++ printf "%%w(1,2147483649,1)0" >expect && ++ git log -1 --pretty="format:%w(1,2147483649,1)%x30" >actual && ++ test_cmp expect actual && ++ printf "%%w(1,1,2147483649)0" >expect && ++ git log -1 --pretty="format:%w(1,1,2147483649)%x30" >actual && ++ test_cmp expect actual ++' ++ ++test_expect_success SIZE_T_IS_64BIT 'log --pretty with overflowing padding directive' ' ++ printf "%%<(2147483649)0" >expect && ++ git log -1 --pretty="format:%<(2147483649)%x30" >actual && ++ test_cmp expect actual + ' + + test_expect_success 'log --pretty with padding and preceding control chars' ' +-- +2.25.1 + diff --git a/meta/recipes-devtools/git/files/CVE-2023-22490-1.patch b/meta/recipes-devtools/git/files/CVE-2023-22490-1.patch new file mode 100644 index 0000000000..cc9b448c5c --- /dev/null +++ b/meta/recipes-devtools/git/files/CVE-2023-22490-1.patch @@ -0,0 +1,179 @@ +From 58325b93c5b6212697b088371809e9948fee8052 Mon Sep 17 00:00:00 2001 +From: Taylor Blau <me@ttaylorr.com> +Date: Tue, 24 Jan 2023 19:43:45 -0500 +Subject: [PATCH 1/3] t5619: demonstrate clone_local() with ambiguous transport + +When cloning a repository, Git must determine (a) what transport +mechanism to use, and (b) whether or not the clone is local. + +Since f38aa83 (use local cloning if insteadOf makes a local URL, +2014-07-17), the latter check happens after the remote has been +initialized, and references the remote's URL instead of the local path. +This is done to make it possible for a `url.<base>.insteadOf` rule to +convert a remote URL into a local one, in which case the `clone_local()` +mechanism should be used. + +However, with a specially crafted repository, Git can be tricked into +using a non-local transport while still setting `is_local` to "1" and +using the `clone_local()` optimization. The below test case +demonstrates such an instance, and shows that it can be used to include +arbitrary (known) paths in the working copy of a cloned repository on a +victim's machine[^1], even if local file clones are forbidden by +`protocol.file.allow`. + +This happens in a few parts: + + 1. We first call `get_repo_path()` to see if the remote is a local + path. If it is, we replace the repo name with its absolute path. + + 2. We then call `transport_get()` on the repo name and decide how to + access it. If it was turned into an absolute path in the previous + step, then we should always treat it like a file. + + 3. We use `get_repo_path()` again, and set `is_local` as appropriate. + But it's already too late to rewrite the repo name as an absolute + path, since we've already fed it to the transport code. + +The attack works by including a submodule whose URL corresponds to a +path on disk. In the below example, the repository "sub" is reachable +via the dumb HTTP protocol at (something like): + + http://127.0.0.1:NNNN/dumb/sub.git + +However, the path "http:/127.0.0.1:NNNN/dumb" (that is, a top-level +directory called "http:", then nested directories "127.0.0.1:NNNN", and +"dumb") exists within the repository, too. + +To determine this, it first picks the appropriate transport, which is +dumb HTTP. It then uses the remote's URL in order to determine whether +the repository exists locally on disk. However, the malicious repository +also contains an embedded stub repository which is the target of a +symbolic link at the local path corresponding to the "sub" repository on +disk (i.e., there is a symbolic link at "http:/127.0.0.1/dumb/sub.git", +pointing to the stub repository via ".git/modules/sub/../../../repo"). + +This stub repository fools Git into thinking that a local repository +exists at that URL and thus can be cloned locally. The affected call is +in `get_repo_path()`, which in turn calls `get_repo_path_1()`, which +locates a valid repository at that target. + +This then causes Git to set the `is_local` variable to "1", and in turn +instructs Git to clone the repository using its local clone optimization +via the `clone_local()` function. + +The exploit comes into play because the stub repository's top-level +"$GIT_DIR/objects" directory is a symbolic link which can point to an +arbitrary path on the victim's machine. `clone_local()` resolves the +top-level "objects" directory through a `stat(2)` call, meaning that we +read through the symbolic link and copy or hardlink the directory +contents at the destination of the link. + +In other words, we can get steps (1) and (3) to disagree by leveraging +the dangling symlink to pick a non-local transport in the first step, +and then set is_local to "1" in the third step when cloning with +`--separate-git-dir`, which makes the symlink non-dangling. + +This can result in data-exfiltration on the victim's machine when +sensitive data is at a known path (e.g., "/home/$USER/.ssh"). + +The appropriate fix is two-fold: + + - Resolve the transport later on (to avoid using the local + clone optimization with a non-local transport). + + - Avoid reading through the top-level "objects" directory when + (correctly) using the clone_local() optimization. + +This patch merely demonstrates the issue. The following two patches will +implement each part of the above fix, respectively. + +[^1]: Provided that any target directory does not contain symbolic + links, in which case the changes from 6f054f9 (builtin/clone.c: + disallow `--local` clones with symlinks, 2022-07-28) will abort the + clone. + +Reported-by: yvvdwf <yvvdwf@gmail.com> +Signed-off-by: Taylor Blau <me@ttaylorr.com> +Signed-off-by: Junio C Hamano <gitster@pobox.com> + +Upstream-Status: Backport +[https://github.com/git/git/commit/58325b93c5b6212697b088371809e9948fee8052] +CVE: CVE-2023-22490 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + t/t5619-clone-local-ambiguous-transport.sh | 63 ++++++++++++++++++++++ + 1 file changed, 63 insertions(+) + create mode 100644 t/t5619-clone-local-ambiguous-transport.sh + +diff --git a/t/t5619-clone-local-ambiguous-transport.sh b/t/t5619-clone-local-ambiguous-transport.sh +new file mode 100644 +index 0000000..7ebd31a +--- /dev/null ++++ b/t/t5619-clone-local-ambiguous-transport.sh +@@ -0,0 +1,63 @@ ++#!/bin/sh ++ ++test_description='test local clone with ambiguous transport' ++ ++. ./test-lib.sh ++. "$TEST_DIRECTORY/lib-httpd.sh" ++ ++if ! test_have_prereq SYMLINKS ++then ++ skip_all='skipping test, symlink support unavailable' ++ test_done ++fi ++ ++start_httpd ++ ++REPO="$HTTPD_DOCUMENT_ROOT_PATH/sub.git" ++URI="$HTTPD_URL/dumb/sub.git" ++ ++test_expect_success 'setup' ' ++ mkdir -p sensitive && ++ echo "secret" >sensitive/secret && ++ ++ git init --bare "$REPO" && ++ test_commit_bulk -C "$REPO" --ref=main 1 && ++ ++ git -C "$REPO" update-ref HEAD main && ++ git -C "$REPO" update-server-info && ++ ++ git init malicious && ++ ( ++ cd malicious && ++ ++ git submodule add "$URI" && ++ ++ mkdir -p repo/refs && ++ touch repo/refs/.gitkeep && ++ printf "ref: refs/heads/a" >repo/HEAD && ++ ln -s "$(cd .. && pwd)/sensitive" repo/objects && ++ ++ mkdir -p "$HTTPD_URL/dumb" && ++ ln -s "../../../.git/modules/sub/../../../repo/" "$URI" && ++ ++ git add . && ++ git commit -m "initial commit" ++ ) && ++ ++ # Delete all of the references in our malicious submodule to ++ # avoid the client attempting to checkout any objects (which ++ # will be missing, and thus will cause the clone to fail before ++ # we can trigger the exploit). ++ git -C "$REPO" for-each-ref --format="delete %(refname)" >in && ++ git -C "$REPO" update-ref --stdin <in && ++ git -C "$REPO" update-server-info ++' ++ ++test_expect_failure 'ambiguous transport does not lead to arbitrary file-inclusion' ' ++ git clone malicious clone && ++ git -C clone submodule update --init && ++ ++ test_path_is_missing clone/.git/modules/sub/objects/secret ++' ++ ++test_done +-- +2.25.1 + diff --git a/meta/recipes-devtools/git/files/CVE-2023-22490-2.patch b/meta/recipes-devtools/git/files/CVE-2023-22490-2.patch new file mode 100644 index 0000000000..0b5b40f827 --- /dev/null +++ b/meta/recipes-devtools/git/files/CVE-2023-22490-2.patch @@ -0,0 +1,122 @@ +From cf8f6ce02a13f4d1979a53241afbee15a293fce9 Mon Sep 17 00:00:00 2001 +From: Taylor Blau <me@ttaylorr.com> +Date: Tue, 24 Jan 2023 19:43:48 -0500 +Subject: [PATCH 2/3] clone: delay picking a transport until after get_repo_path() + +In the previous commit, t5619 demonstrates an issue where two calls to +`get_repo_path()` could trick Git into using its local clone mechanism +in conjunction with a non-local transport. + +That sequence is: + + - the starting state is that the local path https:/example.com/foo is a + symlink that points to ../../../.git/modules/foo. So it's dangling. + + - get_repo_path() sees that no such path exists (because it's + dangling), and thus we do not canonicalize it into an absolute path + + - because we're using --separate-git-dir, we create .git/modules/foo. + Now our symlink is no longer dangling! + + - we pass the url to transport_get(), which sees it as an https URL. + + - we call get_repo_path() again, on the url. This second call was + introduced by f38aa83 (use local cloning if insteadOf makes a + local URL, 2014-07-17). The idea is that we want to pull the url + fresh from the remote.c API, because it will apply any aliases. + +And of course now it sees that there is a local file, which is a +mismatch with the transport we already selected. + +The issue in the above sequence is calling `transport_get()` before +deciding whether or not the repository is indeed local, and not passing +in an absolute path if it is local. + +This is reminiscent of a similar bug report in [1], where it was +suggested to perform the `insteadOf` lookup earlier. Taking that +approach may not be as straightforward, since the intent is to store the +original URL in the config, but to actually fetch from the insteadOf +one, so conflating the two early on is a non-starter. + +Note: we pass the path returned by `get_repo_path(remote->url[0])`, +which should be the same as `repo_name` (aside from any `insteadOf` +rewrites). + +We *could* pass `absolute_pathdup()` of the same argument, which +86521ac (Bring local clone's origin URL in line with that of a remote +clone, 2008-09-01) indicates may differ depending on the presence of +".git/" for a non-bare repo. That matters for forming relative submodule +paths, but doesn't matter for the second call, since we're just feeding +it to the transport code, which is fine either way. + +[1]: https://lore.kernel.org/git/CAMoD=Bi41mB3QRn3JdZL-FGHs4w3C2jGpnJB-CqSndO7FMtfzA@mail.gmail.com/ + +Signed-off-by: Jeff King <peff@peff.net> +Signed-off-by: Taylor Blau <me@ttaylorr.com> +Signed-off-by: Junio C Hamano <gitster@pobox.com> + +Upstream-Status: Backport +[https://github.com/git/git/commit/cf8f6ce02a13f4d1979a53241afbee15a293fce9] +CVE: CVE-2023-22490 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + builtin/clone.c | 8 ++++---- + t/t5619-clone-local-ambiguous-transport.sh | 15 +++++++++++---- + 2 files changed, 15 insertions(+), 8 deletions(-) + +diff --git a/builtin/clone.c b/builtin/clone.c +index 53e04b1..b57e703 100644 +--- a/builtin/clone.c ++++ b/builtin/clone.c +@@ -1112,10 +1112,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix) + branch_top.buf); + refspec_append(&remote->fetch, default_refspec.buf); + +- transport = transport_get(remote, remote->url[0]); +- transport_set_verbosity(transport, option_verbosity, option_progress); +- transport->family = family; +- + path = get_repo_path(remote->url[0], &is_bundle); + is_local = option_local != 0 && path && !is_bundle; + if (is_local) { +@@ -1135,6 +1131,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix) + } + if (option_local > 0 && !is_local) + warning(_("--local is ignored")); ++ ++ transport = transport_get(remote, path ? path : remote->url[0]); ++ transport_set_verbosity(transport, option_verbosity, option_progress); ++ transport->family = family; + transport->cloning = 1; + + transport_set_option(transport, TRANS_OPT_KEEP, "yes"); +diff --git a/t/t5619-clone-local-ambiguous-transport.sh b/t/t5619-clone-local-ambiguous-transport.sh +index 7ebd31a..cce62bf 100644 +--- a/t/t5619-clone-local-ambiguous-transport.sh ++++ b/t/t5619-clone-local-ambiguous-transport.sh +@@ -53,11 +53,18 @@ test_expect_success 'setup' ' + git -C "$REPO" update-server-info + ' + +-test_expect_failure 'ambiguous transport does not lead to arbitrary file-inclusion' ' ++test_expect_success 'ambiguous transport does not lead to arbitrary file-inclusion' ' + git clone malicious clone && +- git -C clone submodule update --init && +- +- test_path_is_missing clone/.git/modules/sub/objects/secret ++ test_must_fail git -C clone submodule update --init 2>err && ++ ++ test_path_is_missing clone/.git/modules/sub/objects/secret && ++ # We would actually expect "transport .file. not allowed" here, ++ # but due to quirks of the URL detection in Git, we mis-parse ++ # the absolute path as a bogus URL and die before that step. ++ # ++ # This works for now, and if we ever fix the URL detection, it ++ # is OK to change this to detect the transport error. ++ grep "protocol .* is not supported" err + ' + + test_done +-- +2.25.1 + diff --git a/meta/recipes-devtools/git/files/CVE-2023-22490-3.patch b/meta/recipes-devtools/git/files/CVE-2023-22490-3.patch new file mode 100644 index 0000000000..08fb7f840b --- /dev/null +++ b/meta/recipes-devtools/git/files/CVE-2023-22490-3.patch @@ -0,0 +1,154 @@ +From bffc762f87ae8d18c6001bf0044a76004245754c Mon Sep 17 00:00:00 2001 +From: Taylor Blau <me@ttaylorr.com> +Date: Tue, 24 Jan 2023 19:43:51 -0500 +Subject: [PATCH 3/3] dir-iterator: prevent top-level symlinks without FOLLOW_SYMLINKS + +When using the dir_iterator API, we first stat(2) the base path, and +then use that as a starting point to enumerate the directory's contents. + +If the directory contains symbolic links, we will immediately die() upon +encountering them without the `FOLLOW_SYMLINKS` flag. The same is not +true when resolving the top-level directory, though. + +As explained in a previous commit, this oversight in 6f054f9 +(builtin/clone.c: disallow `--local` clones with symlinks, 2022-07-28) +can be used as an attack vector to include arbitrary files on a victim's +filesystem from outside of the repository. + +Prevent resolving top-level symlinks unless the FOLLOW_SYMLINKS flag is +given, which will cause clones of a repository with a symlink'd +"$GIT_DIR/objects" directory to fail. + +Signed-off-by: Taylor Blau <me@ttaylorr.com> +Signed-off-by: Junio C Hamano <gitster@pobox.com> + +Upstream-Status: Backport +[https://github.com/git/git/commit/bffc762f87ae8d18c6001bf0044a76004245754c] +CVE: CVE-2023-22490 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + dir-iterator.c | 13 +++++++++---- + dir-iterator.h | 5 +++++ + t/t0066-dir-iterator.sh | 27 ++++++++++++++++++++++++++- + t/t5604-clone-reference.sh | 16 ++++++++++++++++ + 4 files changed, 56 insertions(+), 5 deletions(-) + +diff --git a/dir-iterator.c b/dir-iterator.c +index b17e9f9..3764dd8 100644 +--- a/dir-iterator.c ++++ b/dir-iterator.c +@@ -203,7 +203,7 @@ struct dir_iterator *dir_iterator_begin(const char *path, unsigned int flags) + { + struct dir_iterator_int *iter = xcalloc(1, sizeof(*iter)); + struct dir_iterator *dir_iterator = &iter->base; +- int saved_errno; ++ int saved_errno, err; + + strbuf_init(&iter->base.path, PATH_MAX); + strbuf_addstr(&iter->base.path, path); +@@ -213,10 +213,15 @@ struct dir_iterator *dir_iterator_begin(const char *path, unsigned int flags) + iter->flags = flags; + + /* +- * Note: stat already checks for NULL or empty strings and +- * inexistent paths. ++ * Note: stat/lstat already checks for NULL or empty strings and ++ * nonexistent paths. + */ +- if (stat(iter->base.path.buf, &iter->base.st) < 0) { ++ if (iter->flags & DIR_ITERATOR_FOLLOW_SYMLINKS) ++ err = stat(iter->base.path.buf, &iter->base.st); ++ else ++ err = lstat(iter->base.path.buf, &iter->base.st); ++ ++ if (err < 0) { + saved_errno = errno; + goto error_out; + } +diff --git a/dir-iterator.h b/dir-iterator.h +index 0822915..e3b6ff2 100644 +--- a/dir-iterator.h ++++ b/dir-iterator.h +@@ -61,6 +61,11 @@ + * not the symlinks themselves, which is the default behavior. Broken + * symlinks are ignored. + * ++ * Note: setting DIR_ITERATOR_FOLLOW_SYMLINKS affects resolving the ++ * starting path as well (e.g., attempting to iterate starting at a ++ * symbolic link pointing to a directory without FOLLOW_SYMLINKS will ++ * result in an error). ++ * + * Warning: circular symlinks are also followed when + * DIR_ITERATOR_FOLLOW_SYMLINKS is set. The iteration may end up with + * an ELOOP if they happen and DIR_ITERATOR_PEDANTIC is set. +diff --git a/t/t0066-dir-iterator.sh b/t/t0066-dir-iterator.sh +index 92910e4..c826f60 100755 +--- a/t/t0066-dir-iterator.sh ++++ b/t/t0066-dir-iterator.sh +@@ -109,7 +109,9 @@ test_expect_success SYMLINKS 'setup dirs with symlinks' ' + mkdir -p dir5/a/c && + ln -s ../c dir5/a/b/d && + ln -s ../ dir5/a/b/e && +- ln -s ../../ dir5/a/b/f ++ ln -s ../../ dir5/a/b/f && ++ ++ ln -s dir4 dir6 + ' + + test_expect_success SYMLINKS 'dir-iterator should not follow symlinks by default' ' +@@ -145,4 +147,27 @@ test_expect_success SYMLINKS 'dir-iterator should follow symlinks w/ follow flag + test_cmp expected-follow-sorted-output actual-follow-sorted-output + ' + ++test_expect_success SYMLINKS 'dir-iterator does not resolve top-level symlinks' ' ++ test_must_fail test-tool dir-iterator ./dir6 >out && ++ ++ grep "ENOTDIR" out ++' ++ ++test_expect_success SYMLINKS 'dir-iterator resolves top-level symlinks w/ follow flag' ' ++ cat >expected-follow-sorted-output <<-EOF && ++ [d] (a) [a] ./dir6/a ++ [d] (a/f) [f] ./dir6/a/f ++ [d] (a/f/c) [c] ./dir6/a/f/c ++ [d] (b) [b] ./dir6/b ++ [d] (b/c) [c] ./dir6/b/c ++ [f] (a/d) [d] ./dir6/a/d ++ [f] (a/e) [e] ./dir6/a/e ++ EOF ++ ++ test-tool dir-iterator --follow-symlinks ./dir6 >out && ++ sort out >actual-follow-sorted-output && ++ ++ test_cmp expected-follow-sorted-output actual-follow-sorted-output ++' ++ + test_done +diff --git a/t/t5604-clone-reference.sh b/t/t5604-clone-reference.sh +index 4894237..615b981 100755 +--- a/t/t5604-clone-reference.sh ++++ b/t/t5604-clone-reference.sh +@@ -354,4 +354,20 @@ test_expect_success SYMLINKS 'clone repo with symlinked or unknown files at obje + test_must_be_empty T--shared.objects-symlinks.raw + ' + ++test_expect_success SYMLINKS 'clone repo with symlinked objects directory' ' ++ test_when_finished "rm -fr sensitive malicious" && ++ ++ mkdir -p sensitive && ++ echo "secret" >sensitive/file && ++ ++ git init malicious && ++ rm -fr malicious/.git/objects && ++ ln -s "$(pwd)/sensitive" ./malicious/.git/objects && ++ ++ test_must_fail git clone --local malicious clone 2>err && ++ ++ test_path_is_missing clone && ++ grep "failed to start iterator over" err ++' ++ + test_done +-- +2.25.1 + diff --git a/meta/recipes-devtools/git/files/CVE-2023-23946.patch b/meta/recipes-devtools/git/files/CVE-2023-23946.patch new file mode 100644 index 0000000000..3629ff57b2 --- /dev/null +++ b/meta/recipes-devtools/git/files/CVE-2023-23946.patch @@ -0,0 +1,184 @@ +From fade728df1221598f42d391cf377e9e84a32053f Mon Sep 17 00:00:00 2001 +From: Patrick Steinhardt <ps@pks.im> +Date: Thu, 2 Feb 2023 11:54:34 +0100 +Subject: [PATCH] apply: fix writing behind newly created symbolic links + +When writing files git-apply(1) initially makes sure that none of the +files it is about to create are behind a symlink: + +``` + $ git init repo + Initialized empty Git repository in /tmp/repo/.git/ + $ cd repo/ + $ ln -s dir symlink + $ git apply - <<EOF + diff --git a/symlink/file b/symlink/file + new file mode 100644 + index 0000000..e69de29 + EOF + error: affected file 'symlink/file' is beyond a symbolic link +``` + +This safety mechanism is crucial to ensure that we don't write outside +of the repository's working directory. It can be fooled though when the +patch that is being applied creates the symbolic link in the first +place, which can lead to writing files in arbitrary locations. + +Fix this by checking whether the path we're about to create is +beyond a symlink or not. Tightening these checks like this should be +fine as we already have these precautions in Git as explained +above. Ideally, we should update the check we do up-front before +starting to reflect the computed changes to the working tree so that +we catch this case as well, but as part of embargoed security work, +adding an equivalent check just before we try to write out a file +should serve us well as a reasonable first step. + +Digging back into history shows that this vulnerability has existed +since at least Git v2.9.0. As Git v2.8.0 and older don't build on my +system anymore I cannot tell whether older versions are affected, as +well. + +Reported-by: Joern Schneeweisz <jschneeweisz@gitlab.com> +Signed-off-by: Patrick Steinhardt <ps@pks.im> +Signed-off-by: Junio C Hamano <gitster@pobox.com> + +Upstream-Status: Backport +[https://github.com/git/git/commit/fade728df1221598f42d391cf377e9e84a32053f] +CVE: CVE-2023-23946 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + apply.c | 27 ++++++++++++++ + t/t4115-apply-symlink.sh | 81 ++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 108 insertions(+) + +diff --git a/apply.c b/apply.c +index f8a046a..4f303bf 100644 +--- a/apply.c ++++ b/apply.c +@@ -4373,6 +4373,33 @@ static int create_one_file(struct apply_state *state, + if (state->cached) + return 0; + ++ /* ++ * We already try to detect whether files are beyond a symlink in our ++ * up-front checks. But in the case where symlinks are created by any ++ * of the intermediate hunks it can happen that our up-front checks ++ * didn't yet see the symlink, but at the point of arriving here there ++ * in fact is one. We thus repeat the check for symlinks here. ++ * ++ * Note that this does not make the up-front check obsolete as the ++ * failure mode is different: ++ * ++ * - The up-front checks cause us to abort before we have written ++ * anything into the working directory. So when we exit this way the ++ * working directory remains clean. ++ * ++ * - The checks here happen in the middle of the action where we have ++ * already started to apply the patch. The end result will be a dirty ++ * working directory. ++ * ++ * Ideally, we should update the up-front checks to catch what would ++ * happen when we apply the patch before we damage the working tree. ++ * We have all the information necessary to do so. But for now, as a ++ * part of embargoed security work, having this check would serve as a ++ * reasonable first step. ++ */ ++ if (path_is_beyond_symlink(state, path)) ++ return error(_("affected file '%s' is beyond a symbolic link"), path); ++ + res = try_create_file(state, path, mode, buf, size); + if (res < 0) + return -1; +diff --git a/t/t4115-apply-symlink.sh b/t/t4115-apply-symlink.sh +index 872fcda..1acb7b2 100755 +--- a/t/t4115-apply-symlink.sh ++++ b/t/t4115-apply-symlink.sh +@@ -44,4 +44,85 @@ test_expect_success 'apply --index symlink patch' ' + + ' + ++test_expect_success 'symlink setup' ' ++ ln -s .git symlink && ++ git add symlink && ++ git commit -m "add symlink" ++' ++ ++test_expect_success SYMLINKS 'symlink escape when creating new files' ' ++ test_when_finished "git reset --hard && git clean -dfx" && ++ ++ cat >patch <<-EOF && ++ diff --git a/symlink b/renamed-symlink ++ similarity index 100% ++ rename from symlink ++ rename to renamed-symlink ++ -- ++ diff --git /dev/null b/renamed-symlink/create-me ++ new file mode 100644 ++ index 0000000..039727e ++ --- /dev/null ++ +++ b/renamed-symlink/create-me ++ @@ -0,0 +1,1 @@ ++ +busted ++ EOF ++ ++ test_must_fail git apply patch 2>stderr && ++ cat >expected_stderr <<-EOF && ++ error: affected file ${SQ}renamed-symlink/create-me${SQ} is beyond a symbolic link ++ EOF ++ test_cmp expected_stderr stderr && ++ ! test_path_exists .git/create-me ++' ++ ++test_expect_success SYMLINKS 'symlink escape when modifying file' ' ++ test_when_finished "git reset --hard && git clean -dfx" && ++ touch .git/modify-me && ++ ++ cat >patch <<-EOF && ++ diff --git a/symlink b/renamed-symlink ++ similarity index 100% ++ rename from symlink ++ rename to renamed-symlink ++ -- ++ diff --git a/renamed-symlink/modify-me b/renamed-symlink/modify-me ++ index 1111111..2222222 100644 ++ --- a/renamed-symlink/modify-me ++ +++ b/renamed-symlink/modify-me ++ @@ -0,0 +1,1 @@ ++ +busted ++ EOF ++ ++ test_must_fail git apply patch 2>stderr && ++ cat >expected_stderr <<-EOF && ++ error: renamed-symlink/modify-me: No such file or directory ++ EOF ++ test_cmp expected_stderr stderr && ++ test_must_be_empty .git/modify-me ++' ++ ++test_expect_success SYMLINKS 'symlink escape when deleting file' ' ++ test_when_finished "git reset --hard && git clean -dfx && rm .git/delete-me" && ++ touch .git/delete-me && ++ ++ cat >patch <<-EOF && ++ diff --git a/symlink b/renamed-symlink ++ similarity index 100% ++ rename from symlink ++ rename to renamed-symlink ++ -- ++ diff --git a/renamed-symlink/delete-me b/renamed-symlink/delete-me ++ deleted file mode 100644 ++ index 1111111..0000000 100644 ++ EOF ++ ++ test_must_fail git apply patch 2>stderr && ++ cat >expected_stderr <<-EOF && ++ error: renamed-symlink/delete-me: No such file or directory ++ EOF ++ test_cmp expected_stderr stderr && ++ test_path_is_file .git/delete-me ++' ++ + test_done +-- +2.25.1 + diff --git a/meta/recipes-devtools/git/files/CVE-2023-25652.patch b/meta/recipes-devtools/git/files/CVE-2023-25652.patch new file mode 100644 index 0000000000..d6b17a2b8a --- /dev/null +++ b/meta/recipes-devtools/git/files/CVE-2023-25652.patch @@ -0,0 +1,94 @@ +From 9db05711c98efc14f414d4c87135a34c13586e0b Mon Sep 17 00:00:00 2001 +From: Johannes Schindelin <johannes.schindelin@gmx.de> +Date: Thu, 9 Mar 2023 16:02:54 +0100 +Subject: [PATCH] apply --reject: overwrite existing `.rej` symlink if it + exists + +The `git apply --reject` is expected to write out `.rej` files in case +one or more hunks fail to apply cleanly. Historically, the command +overwrites any existing `.rej` files. The idea being that +apply/reject/edit cycles are relatively common, and the generated `.rej` +files are not considered precious. + +But the command does not overwrite existing `.rej` symbolic links, and +instead follows them. This is unsafe because the same patch could +potentially create such a symbolic link and point at arbitrary paths +outside the current worktree, and `git apply` would write the contents +of the `.rej` file into that location. + +Therefore, let's make sure that any existing `.rej` file or symbolic +link is removed before writing it. + +Reported-by: RyotaK <ryotak.mail@gmail.com> +Helped-by: Taylor Blau <me@ttaylorr.com> +Helped-by: Junio C Hamano <gitster@pobox.com> +Helped-by: Linus Torvalds <torvalds@linuxfoundation.org> +Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> + +Upstream-Status: Backport [https://github.com/git/git/commit/9db05711c98efc14f414d4c87135a34c13586e0b] +CVE: CVE-2023-25652 +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> +--- + apply.c | 14 ++++++++++++-- + t/t4115-apply-symlink.sh | 15 +++++++++++++++ + 2 files changed, 27 insertions(+), 2 deletions(-) + +diff --git a/apply.c b/apply.c +index 4f303bf..aa7111d 100644 +--- a/apply.c ++++ b/apply.c +@@ -4531,7 +4531,7 @@ static int write_out_one_reject(struct apply_state *state, struct patch *patch) + FILE *rej; + char namebuf[PATH_MAX]; + struct fragment *frag; +- int cnt = 0; ++ int fd, cnt = 0; + struct strbuf sb = STRBUF_INIT; + + for (cnt = 0, frag = patch->fragments; frag; frag = frag->next) { +@@ -4571,7 +4571,17 @@ static int write_out_one_reject(struct apply_state *state, struct patch *patch) + memcpy(namebuf, patch->new_name, cnt); + memcpy(namebuf + cnt, ".rej", 5); + +- rej = fopen(namebuf, "w"); ++ fd = open(namebuf, O_CREAT | O_EXCL | O_WRONLY, 0666); ++ if (fd < 0) { ++ if (errno != EEXIST) ++ return error_errno(_("cannot open %s"), namebuf); ++ if (unlink(namebuf)) ++ return error_errno(_("cannot unlink '%s'"), namebuf); ++ fd = open(namebuf, O_CREAT | O_EXCL | O_WRONLY, 0666); ++ if (fd < 0) ++ return error_errno(_("cannot open %s"), namebuf); ++ } ++ rej = fdopen(fd, "w"); + if (!rej) + return error_errno(_("cannot open %s"), namebuf); + +diff --git a/t/t4115-apply-symlink.sh b/t/t4115-apply-symlink.sh +index 1acb7b2..2b034ff 100755 +--- a/t/t4115-apply-symlink.sh ++++ b/t/t4115-apply-symlink.sh +@@ -125,4 +125,19 @@ test_expect_success SYMLINKS 'symlink escape when deleting file' ' + test_path_is_file .git/delete-me + ' + ++test_expect_success SYMLINKS '--reject removes .rej symlink if it exists' ' ++ test_when_finished "git reset --hard && git clean -dfx" && ++ ++ test_commit file && ++ echo modified >file.t && ++ git diff -- file.t >patch && ++ echo modified-again >file.t && ++ ++ ln -s foo file.t.rej && ++ test_must_fail git apply patch --reject 2>err && ++ test_i18ngrep "Rejected hunk" err && ++ test_path_is_missing foo && ++ test_path_is_file file.t.rej ++' ++ + test_done +-- +2.25.1 + diff --git a/meta/recipes-devtools/git/files/CVE-2023-29007.patch b/meta/recipes-devtools/git/files/CVE-2023-29007.patch new file mode 100644 index 0000000000..e166c01412 --- /dev/null +++ b/meta/recipes-devtools/git/files/CVE-2023-29007.patch @@ -0,0 +1,159 @@ +From 057c07a7b1fae22fdeef26c243f4cfbe3afc90ce Mon Sep 17 00:00:00 2001 +From: Taylor Blau <me@ttaylorr.com> +Date: Fri, 14 Apr 2023 11:46:59 -0400 +Subject: [PATCH] Merge branch 'tb/config-copy-or-rename-in-file-injection' + +Avoids issues with renaming or deleting sections with long lines, where +configuration values may be interpreted as sections, leading to +configuration injection. Addresses CVE-2023-29007. + +* tb/config-copy-or-rename-in-file-injection: + config.c: disallow overly-long lines in `copy_or_rename_section_in_file()` + config.c: avoid integer truncation in `copy_or_rename_section_in_file()` + config: avoid fixed-sized buffer when renaming/deleting a section + t1300: demonstrate failure when renaming sections with long lines + +Signed-off-by: Taylor Blau <me@ttaylorr.com> + +Upstream-Status: Backport [https://github.com/git/git/commit/528290f8c61222433a8cf02fb7cfffa8438432b4] +CVE: CVE-2023-29007 +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> +--- + config.c | 36 +++++++++++++++++++++++++----------- + t/t1300-config.sh | 30 ++++++++++++++++++++++++++++++ + 2 files changed, 55 insertions(+), 11 deletions(-) + +diff --git a/config.c b/config.c +index e7052b3..676b687 100644 +--- a/config.c ++++ b/config.c +@@ -2987,9 +2987,10 @@ void git_config_set_multivar(const char *key, const char *value, + multi_replace); + } + +-static int section_name_match (const char *buf, const char *name) ++static size_t section_name_match (const char *buf, const char *name) + { +- int i = 0, j = 0, dot = 0; ++ size_t i = 0, j = 0; ++ int dot = 0; + if (buf[i] != '[') + return 0; + for (i = 1; buf[i] && buf[i] != ']'; i++) { +@@ -3042,6 +3043,8 @@ static int section_name_is_ok(const char *name) + return 1; + } + ++#define GIT_CONFIG_MAX_LINE_LEN (512 * 1024) ++ + /* if new_name == NULL, the section is removed instead */ + static int git_config_copy_or_rename_section_in_file(const char *config_filename, + const char *old_name, +@@ -3051,11 +3054,12 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename + char *filename_buf = NULL; + struct lock_file lock = LOCK_INIT; + int out_fd; +- char buf[1024]; ++ struct strbuf buf = STRBUF_INIT; + FILE *config_file = NULL; + struct stat st; + struct strbuf copystr = STRBUF_INIT; + struct config_store_data store; ++ uint32_t line_nr = 0; + + memset(&store, 0, sizeof(store)); + +@@ -3092,16 +3096,25 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename + goto out; + } + +- while (fgets(buf, sizeof(buf), config_file)) { +- int i; +- int length; ++ while (!strbuf_getwholeline(&buf, config_file, '\n')) { ++ size_t i, length; + int is_section = 0; +- char *output = buf; +- for (i = 0; buf[i] && isspace(buf[i]); i++) ++ char *output = buf.buf; ++ ++ line_nr++; ++ ++ if (buf.len >= GIT_CONFIG_MAX_LINE_LEN) { ++ ret = error(_("refusing to work with overly long line " ++ "in '%s' on line %"PRIuMAX), ++ config_filename, (uintmax_t)line_nr); ++ goto out; ++ } ++ ++ for (i = 0; buf.buf[i] && isspace(buf.buf[i]); i++) + ; /* do nothing */ +- if (buf[i] == '[') { ++ if (buf.buf[i] == '[') { + /* it's a section */ +- int offset; ++ size_t offset; + is_section = 1; + + /* +@@ -3118,7 +3131,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename + strbuf_reset(©str); + } + +- offset = section_name_match(&buf[i], old_name); ++ offset = section_name_match(&buf.buf[i], old_name); + if (offset > 0) { + ret++; + if (new_name == NULL) { +@@ -3193,6 +3206,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename + out_no_rollback: + free(filename_buf); + config_store_data_clear(&store); ++ strbuf_release(&buf); + return ret; + } + +diff --git a/t/t1300-config.sh b/t/t1300-config.sh +index 983a0a1..9b67f6b 100755 +--- a/t/t1300-config.sh ++++ b/t/t1300-config.sh +@@ -616,6 +616,36 @@ test_expect_success 'renaming to bogus section is rejected' ' + test_must_fail git config --rename-section branch.zwei "bogus name" + ' + ++test_expect_success 'renaming a section with a long line' ' ++ { ++ printf "[b]\\n" && ++ printf " c = d %1024s [a] e = f\\n" " " && ++ printf "[a] g = h\\n" ++ } >y && ++ git config -f y --rename-section a xyz && ++ test_must_fail git config -f y b.e ++' ++ ++test_expect_success 'renaming an embedded section with a long line' ' ++ { ++ printf "[b]\\n" && ++ printf " c = d %1024s [a] [foo] e = f\\n" " " && ++ printf "[a] g = h\\n" ++ } >y && ++ git config -f y --rename-section a xyz && ++ test_must_fail git config -f y foo.e ++' ++ ++test_expect_success 'renaming a section with an overly-long line' ' ++ { ++ printf "[b]\\n" && ++ printf " c = d %525000s e" " " && ++ printf "[a] g = h\\n" ++ } >y && ++ test_must_fail git config -f y --rename-section a xyz 2>err && ++ test_i18ngrep "refusing to work with overly long line in .y. on line 2" err ++' ++ + cat >> .git/config << EOF + [branch "zwei"] a = 1 [branch "vier"] + EOF +-- +2.25.1 + diff --git a/meta/recipes-devtools/git/git.inc b/meta/recipes-devtools/git/git.inc index 738a429875..e64472ea28 100644 --- a/meta/recipes-devtools/git/git.inc +++ b/meta/recipes-devtools/git/git.inc @@ -9,15 +9,43 @@ PROVIDES_append_class-native = " git-replacement-native" SRC_URI = "${KERNELORG_MIRROR}/software/scm/git/git-${PV}.tar.gz;name=tarball \ ${KERNELORG_MIRROR}/software/scm/git/git-manpages-${PV}.tar.gz;name=manpages \ - file://CVE-2021-21300.patch \ -" - + file://fixsort.patch \ + file://CVE-2021-40330.patch \ + file://CVE-2022-23521.patch \ + file://CVE-2022-41903-01.patch \ + file://CVE-2022-41903-02.patch \ + file://CVE-2022-41903-03.patch \ + file://CVE-2022-41903-04.patch \ + file://CVE-2022-41903-05.patch \ + file://CVE-2022-41903-06.patch \ + file://CVE-2022-41903-07.patch \ + file://CVE-2022-41903-08.patch \ + file://CVE-2022-41903-09.patch \ + file://CVE-2022-41903-10.patch \ + file://CVE-2022-41903-11.patch \ + file://CVE-2022-41903-12.patch \ + file://CVE-2023-22490-1.patch \ + file://CVE-2023-22490-2.patch \ + file://CVE-2023-22490-3.patch \ + file://CVE-2023-23946.patch \ + file://CVE-2023-29007.patch \ + file://CVE-2023-25652.patch \ + " S = "${WORKDIR}/git-${PV}" LIC_FILES_CHKSUM = "file://COPYING;md5=7c0d7ef03a7eb04ce795b0f60e68e7e1" CVE_PRODUCT = "git-scm:git" +# This is about a manpage not mentioning --mirror may "leak" information +# in mirrored git repos. Most OE users wouldn't build the docs and +# we don't see this as a major issue for our general users/usecases. +CVE_CHECK_WHITELIST += "CVE-2022-24975" +# This is specific to Git-for-Windows +CVE_CHECK_WHITELIST += "CVE-2022-41953" +# specific to Git for Windows +CVE_CHECK_WHITELIST += "CVE-2023-22743" + PACKAGECONFIG ??= "" PACKAGECONFIG[cvsserver] = "" PACKAGECONFIG[svn] = "" diff --git a/meta/recipes-devtools/git/git/fixsort.patch b/meta/recipes-devtools/git/git/fixsort.patch new file mode 100644 index 0000000000..eec1f84945 --- /dev/null +++ b/meta/recipes-devtools/git/git/fixsort.patch @@ -0,0 +1,36 @@ +[PATCH] generate-cmdlist.sh: Fix determinism issue + +Currently git binaries are not entirely reproducible, at least partly +due to config-list.h differing in order depending on the system's +locale settings. Under different locales, the entries: + +"sendemail.identity", +"sendemail.<identity>.*", + +would differ in order for example and this leads to differences in +the debug symbols for the binaries. + +This can be fixed by specifying the C locale for the sort in the +shell script generating the header. + +Note: This is a backport of Richard Purdie's original patch for a more +recent version of git. The offending code in this older version is +in generate-cmdlist.sh. The upstream current version has this code +in generate-configlist.sh. + +Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org> +Signed-off-by: Steve Sakoman <steve@sakoman.com> +Upstream-Status: Submitted [https://public-inbox.org/git/f029a942dd3d50d85e60bd37d8e454524987842f.camel@linuxfoundation.org/T/#u] + +index 71158f7..c137091 100755 +--- a/generate-cmdlist.sh ++++ b/generate-cmdlist.sh +@@ -82,7 +82,7 @@ static const char *config_name_list[] = { + EOF + grep -h '^[a-zA-Z].*\..*::$' Documentation/*config.txt Documentation/config/*.txt | + sed '/deprecated/d; s/::$//; s/, */\n/g' | +- sort | ++ LC_ALL=C sort | + while read line + do + echo " \"$line\"," diff --git a/meta/recipes-devtools/git/git_2.24.3.bb b/meta/recipes-devtools/git/git_2.24.4.bb index ddd875f07b..f38c25f0ef 100644 --- a/meta/recipes-devtools/git/git_2.24.3.bb +++ b/meta/recipes-devtools/git/git_2.24.4.bb @@ -5,5 +5,5 @@ EXTRA_OECONF += "ac_cv_snprintf_returns_bogus=no \ " EXTRA_OEMAKE += "NO_GETTEXT=1" -SRC_URI[tarball.sha256sum] = "ef6d1d1de1d7921a54d23d07479bd2766f050d6435cea5d3b5322aa4897cb3d7" -SRC_URI[manpages.sha256sum] = "325795ba33c0be02370de79636f32ad3b447665c1f2b5b4de65181fa804bed31" +SRC_URI[tarball.sha256sum] = "6e119e70d3762f28e1dc9928c526eb4d7519fd3870f862775cd10186653eb85a" +SRC_URI[manpages.sha256sum] = "e687bcc91a6fd9cb74243f91a9c2d77c50ce202a09b35931021ecc521a373ed5" diff --git a/meta/recipes-devtools/glide/glide_0.13.3.bb b/meta/recipes-devtools/glide/glide_0.13.3.bb index 6eb87df7c3..21773d91f9 100644 --- a/meta/recipes-devtools/glide/glide_0.13.3.bb +++ b/meta/recipes-devtools/glide/glide_0.13.3.bb @@ -5,7 +5,7 @@ LICENSE = "MIT" LIC_FILES_CHKSUM = "file://src/${GO_IMPORT}/LICENSE;md5=54905cf894f8cc416a92f4fc350c35b2" GO_IMPORT = "github.com/Masterminds/glide" -SRC_URI = "git://${GO_IMPORT}" +SRC_URI = "git://${GO_IMPORT};branch=master" SRCREV = "8ed5b9292379d86c39592a7e6a58eb9c903877cf" inherit go diff --git a/meta/recipes-devtools/gnu-config/gnu-config_git.bb b/meta/recipes-devtools/gnu-config/gnu-config_git.bb index 7299a1d4a4..05cd6a1e63 100644 --- a/meta/recipes-devtools/gnu-config/gnu-config_git.bb +++ b/meta/recipes-devtools/gnu-config/gnu-config_git.bb @@ -12,7 +12,7 @@ INHIBIT_DEFAULT_DEPS = "1" SRCREV = "5256817ace8493502ec88501a19e4051c2e220b0" PV = "20200117+git${SRCPV}" -SRC_URI = "git://git.savannah.gnu.org/config.git \ +SRC_URI = "git://git.savannah.gnu.org/git/config.git;protocol=https;branch=master \ file://gnu-configize.in" S = "${WORKDIR}/git" UPSTREAM_CHECK_COMMITS = "1" diff --git a/meta/recipes-devtools/go/go-1.14.inc b/meta/recipes-devtools/go/go-1.14.inc index 3dfd671d11..9c7ceda891 100644 --- a/meta/recipes-devtools/go/go-1.14.inc +++ b/meta/recipes-devtools/go/go-1.14.inc @@ -16,6 +16,112 @@ SRC_URI += "\ file://0006-cmd-dist-separate-host-and-target-builds.patch \ file://0007-cmd-go-make-GOROOT-precious-by-default.patch \ file://0008-use-GOBUILDMODE-to-set-buildmode.patch \ + file://CVE-2021-34558.patch \ + file://CVE-2021-33196.patch \ + file://CVE-2021-33197.patch \ + file://CVE-2021-38297.patch \ + file://CVE-2022-23806.patch \ + file://CVE-2022-23772.patch \ + file://CVE-2021-44717.patch \ + file://CVE-2022-24675.patch \ + file://CVE-2021-31525.patch \ + file://CVE-2022-30629.patch \ + file://CVE-2022-30631.patch \ + file://CVE-2022-30632.patch \ + file://CVE-2022-30633.patch \ + file://CVE-2022-30635.patch \ + file://CVE-2022-32148.patch \ + file://CVE-2022-32189.patch \ + file://CVE-2021-27918.patch \ + file://CVE-2021-36221.patch \ + file://CVE-2021-39293.patch \ + file://CVE-2021-41771.patch \ + file://CVE-2022-27664.patch \ + file://0001-CVE-2022-32190.patch \ + file://0002-CVE-2022-32190.patch \ + file://0003-CVE-2022-32190.patch \ + file://0004-CVE-2022-32190.patch \ + file://CVE-2022-2880.patch \ + file://CVE-2022-2879.patch \ + file://CVE-2021-33195.patch \ + file://CVE-2021-33198.patch \ + file://CVE-2021-44716.patch \ + file://CVE-2022-24921.patch \ + file://CVE-2022-28131.patch \ + file://CVE-2022-28327.patch \ + file://CVE-2022-41715.patch \ + file://CVE-2022-41717.patch \ + file://CVE-2022-1962.patch \ + file://CVE-2022-41723.patch \ + file://CVE-2022-41722-1.patch \ + file://CVE-2022-41722-2.patch \ + file://CVE-2020-29510.patch \ + file://CVE-2023-24537.patch \ + file://CVE-2023-24534.patch \ + file://CVE-2023-24538-1.patch \ + file://CVE-2023-24538-2.patch \ + file://CVE-2023-24538_3.patch \ + file://CVE-2023-24538_4.patch \ + file://CVE-2023-24538_5.patch \ + file://CVE-2023-24538_6.patch \ + file://CVE-2023-24539.patch \ + file://CVE-2023-24540.patch \ + file://CVE-2023-29405-1.patch \ + file://CVE-2023-29405-2.patch \ + file://CVE-2023-29402.patch \ + file://CVE-2023-29404.patch \ + file://CVE-2023-29400.patch \ + file://CVE-2023-29406-1.patch \ + file://CVE-2023-29406-2.patch \ + file://CVE-2023-29409.patch \ + file://CVE-2022-41725-pre1.patch \ + file://CVE-2022-41725-pre2.patch \ + file://CVE-2022-41725-pre3.patch \ + file://CVE-2022-41725.patch \ + file://CVE-2023-24536_1.patch \ + file://CVE-2023-24536_2.patch \ + file://CVE-2023-24536_3.patch \ + file://CVE-2023-39318.patch \ + file://CVE-2023-39319.patch \ + file://CVE-2023-39326.patch \ + file://CVE-2023-45287-pre1.patch \ + file://CVE-2023-45287-pre2.patch \ + file://CVE-2023-45287-pre3.patch \ + file://CVE-2023-45287.patch \ + file://CVE-2023-45289.patch \ + file://CVE-2023-45290.patch \ + file://CVE-2024-24785.patch \ + file://CVE-2024-24784.patch \ " + SRC_URI_append_libc-musl = " file://0009-ld-replace-glibc-dynamic-linker-with-musl.patch" SRC_URI[main.sha256sum] = "7ed13b2209e54a451835997f78035530b331c5b6943cdcd68a3d815fdc009149" + +# Upstream don't believe it is a signifiant real world issue and will only +# fix in 1.17 onwards where we can drop this. +# https://github.com/golang/go/issues/30999#issuecomment-910470358 +CVE_CHECK_WHITELIST += "CVE-2021-29923" + +# this issue affected go1.15 onwards +# https://security-tracker.debian.org/tracker/CVE-2022-29526 +CVE_CHECK_WHITELIST += "CVE-2022-29526" + +# Issue only on windows +CVE_CHECK_WHITELIST += "CVE-2022-29804" +CVE_CHECK_WHITELIST += "CVE-2022-30580" +CVE_CHECK_WHITELIST += "CVE-2022-30634" + +# Issue is in golang.org/x/net/html/parse.go, not used in go compiler +CVE_CHECK_WHITELIST += "CVE-2021-33194" + +# Issue introduced in go1.16, does not exist in 1.14 +CVE_CHECK_WHITELIST += "CVE-2021-41772" + +# Fixes code that was added in go1.16, does not exist in 1.14 +CVE_CHECK_WHITELIST += "CVE-2022-30630" + +# This is specific to Microsoft Windows +CVE_CHECK_WHITELIST += "CVE-2022-41716" + +# Issue introduced in go1.15beta1, does not exist in 1.14 +CVE_CHECK_WHITELIST += "CVE-2022-1705" diff --git a/meta/recipes-devtools/go/go-1.14/0001-CVE-2022-32190.patch b/meta/recipes-devtools/go/go-1.14/0001-CVE-2022-32190.patch new file mode 100644 index 0000000000..ad263b8023 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/0001-CVE-2022-32190.patch @@ -0,0 +1,74 @@ +From 755f2dc35a19e6806de3ecbf836fa06ad875c67a Mon Sep 17 00:00:00 2001 +From: Carl Johnson <me@carlmjohnson.net> +Date: Fri, 4 Mar 2022 14:49:52 +0000 +Subject: [PATCH 1/4] net/url: add JoinPath, URL.JoinPath + +Builds on CL 332209. + +Fixes #47005 + +Change-Id: I82708dede05d79a196ca63f5a4e7cb5ac9a041ea +GitHub-Last-Rev: 51b735066eef74f5e67c3e8899c58f44c0383c61 +GitHub-Pull-Request: golang/go#50383 +Reviewed-on: https://go-review.googlesource.com/c/go/+/374654 +Reviewed-by: Russ Cox <rsc@golang.org> +Auto-Submit: Russ Cox <rsc@golang.org> +Trust: Ian Lance Taylor <iant@golang.org> +Reviewed-by: Damien Neil <dneil@google.com> +Run-TryBot: Ian Lance Taylor <iant@golang.org> +TryBot-Result: Gopher Robot <gobot@golang.org> + +Upstream-Status: Backport [https://github.com/golang/go/commit/604140d93111f89911e17cb147dcf6a02d2700d0] +CVE: CVE-2022-32190 +Signed-off-by: Shubham Kulkarni <skulkarni@mvista.com> +--- + src/net/url/url.go | 23 +++++++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/src/net/url/url.go b/src/net/url/url.go +index 2880e82..dea8bfe 100644 +--- a/src/net/url/url.go ++++ b/src/net/url/url.go +@@ -13,6 +13,7 @@ package url + import ( + "errors" + "fmt" ++ "path" + "sort" + "strconv" + "strings" +@@ -1104,6 +1105,17 @@ func (u *URL) UnmarshalBinary(text []byte) error { + return nil + } + ++// JoinPath returns a new URL with the provided path elements joined to ++// any existing path and the resulting path cleaned of any ./ or ../ elements. ++func (u *URL) JoinPath(elem ...string) *URL { ++ url := *u ++ if len(elem) > 0 { ++ elem = append([]string{u.Path}, elem...) ++ url.setPath(path.Join(elem...)) ++ } ++ return &url ++} ++ + // validUserinfo reports whether s is a valid userinfo string per RFC 3986 + // Section 3.2.1: + // userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) +@@ -1144,3 +1156,14 @@ func stringContainsCTLByte(s string) bool { + } + return false + } ++ ++// JoinPath returns a URL string with the provided path elements joined to ++// the existing path of base and the resulting path cleaned of any ./ or ../ elements. ++func JoinPath(base string, elem ...string) (result string, err error) { ++ url, err := Parse(base) ++ if err != nil { ++ return ++ } ++ result = url.JoinPath(elem...).String() ++ return ++} +-- +2.7.4 diff --git a/meta/recipes-devtools/go/go-1.14/0002-CVE-2022-32190.patch b/meta/recipes-devtools/go/go-1.14/0002-CVE-2022-32190.patch new file mode 100644 index 0000000000..1a11cc72bc --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/0002-CVE-2022-32190.patch @@ -0,0 +1,48 @@ +From 985108de87e7d2ecb2b28cb53b323d530387b884 Mon Sep 17 00:00:00 2001 +From: Ian Lance Taylor <iant@golang.org> +Date: Thu, 31 Mar 2022 13:21:39 -0700 +Subject: [PATCH 2/4] net/url: preserve a trailing slash in JoinPath + +Fixes #52074 + +Change-Id: I30897f32e70a6ca0c4e11aaf07088c27336efaba +Reviewed-on: https://go-review.googlesource.com/c/go/+/397256 +Trust: Ian Lance Taylor <iant@golang.org> +Run-TryBot: Ian Lance Taylor <iant@golang.org> +TryBot-Result: Gopher Robot <gobot@golang.org> +Reviewed-by: Matt Layher <mdlayher@gmail.com> +Trust: Matt Layher <mdlayher@gmail.com> + +Upstream-Status: Backport [https://github.com/golang/go/commit/dbb52cc9f3e83a3040f46c2ae7650c15ab342179] +CVE: CVE-2022-32190 +Signed-off-by: Shubham Kulkarni <skulkarni@mvista.com> +--- + src/net/url/url.go | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/src/net/url/url.go b/src/net/url/url.go +index dea8bfe..3436707 100644 +--- a/src/net/url/url.go ++++ b/src/net/url/url.go +@@ -1107,11 +1107,18 @@ func (u *URL) UnmarshalBinary(text []byte) error { + + // JoinPath returns a new URL with the provided path elements joined to + // any existing path and the resulting path cleaned of any ./ or ../ elements. ++// Any sequences of multiple / characters will be reduced to a single /. + func (u *URL) JoinPath(elem ...string) *URL { + url := *u + if len(elem) > 0 { + elem = append([]string{u.Path}, elem...) +- url.setPath(path.Join(elem...)) ++ p := path.Join(elem...) ++ // path.Join will remove any trailing slashes. ++ // Preserve at least one. ++ if strings.HasSuffix(elem[len(elem)-1], "/") && !strings.HasSuffix(p, "/") { ++ p += "/" ++ } ++ url.setPath(p) + } + return &url + } +-- +2.7.4 diff --git a/meta/recipes-devtools/go/go-1.14/0003-CVE-2022-32190.patch b/meta/recipes-devtools/go/go-1.14/0003-CVE-2022-32190.patch new file mode 100644 index 0000000000..816d914983 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/0003-CVE-2022-32190.patch @@ -0,0 +1,36 @@ +From 2c632b883b0f11084cc247c8b50ad6c71fa7b447 Mon Sep 17 00:00:00 2001 +From: Sean Liao <sean@liao.dev> +Date: Sat, 9 Jul 2022 18:38:45 +0100 +Subject: [PATCH 3/4] net/url: use EscapedPath for url.JoinPath + +Fixes #53763 + +Change-Id: I08b53f159ebdce7907e8cc17316fd0c982363239 +Reviewed-on: https://go-review.googlesource.com/c/go/+/416774 +TryBot-Result: Gopher Robot <gobot@golang.org> +Reviewed-by: Damien Neil <dneil@google.com> +Reviewed-by: Bryan Mills <bcmills@google.com> +Run-TryBot: Ian Lance Taylor <iant@golang.org> + +Upstream-Status: Backport [https://github.com/golang/go/commit/bf5898ef53d1693aa572da0da746c05e9a6f15c5] +CVE: CVE-2022-32190 +Signed-off-by: Shubham Kulkarni <skulkarni@mvista.com> +--- + src/net/url/url.go | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/net/url/url.go b/src/net/url/url.go +index 3436707..73079a5 100644 +--- a/src/net/url/url.go ++++ b/src/net/url/url.go +@@ -1111,7 +1111,7 @@ func (u *URL) UnmarshalBinary(text []byte) error { + func (u *URL) JoinPath(elem ...string) *URL { + url := *u + if len(elem) > 0 { +- elem = append([]string{u.Path}, elem...) ++ elem = append([]string{u.EscapedPath()}, elem...) + p := path.Join(elem...) + // path.Join will remove any trailing slashes. + // Preserve at least one. +-- +2.7.4 diff --git a/meta/recipes-devtools/go/go-1.14/0004-CVE-2022-32190.patch b/meta/recipes-devtools/go/go-1.14/0004-CVE-2022-32190.patch new file mode 100644 index 0000000000..4bdff3aed4 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/0004-CVE-2022-32190.patch @@ -0,0 +1,82 @@ +From f61e428699cbb52bab31fe2c124f49d085a209fe Mon Sep 17 00:00:00 2001 +From: Damien Neil <dneil@google.com> +Date: Fri, 12 Aug 2022 16:21:09 -0700 +Subject: [PATCH 4/4] net/url: consistently remove ../ elements in JoinPath + +JoinPath would fail to remove relative elements from the start of +the path when the first path element is "". + +In addition, JoinPath would return the original path unmodified +when provided with no elements to join, violating the documented +behavior of always cleaning the resulting path. + +Correct both these cases. + + JoinPath("http://go.dev", "../go") + // before: http://go.dev/../go + // after: http://go.dev/go + + JoinPath("http://go.dev/../go") + // before: http://go.dev/../go + // after: http://go.dev/go + +For #54385. +Fixes #54635. +Fixes CVE-2022-32190. + +Change-Id: I6d22cd160d097c50703dd96e4f453c6c118fd5d9 +Reviewed-on: https://go-review.googlesource.com/c/go/+/423514 +Reviewed-by: David Chase <drchase@google.com> +Reviewed-by: Alan Donovan <adonovan@google.com> +(cherry picked from commit 0765da5884adcc8b744979303a36a27092d8fc51) +Reviewed-on: https://go-review.googlesource.com/c/go/+/425357 +Run-TryBot: Damien Neil <dneil@google.com> +TryBot-Result: Gopher Robot <gobot@golang.org> + +Upstream-Status: Backport [https://github.com/golang/go/commit/28335508913a46e05ef0c04a18e8a1a6beb775ec] +CVE: CVE-2022-32190 +Signed-off-by: Shubham Kulkarni <skulkarni@mvista.com> +--- + src/net/url/url.go | 26 ++++++++++++++++---------- + 1 file changed, 16 insertions(+), 10 deletions(-) + +diff --git a/src/net/url/url.go b/src/net/url/url.go +index 73079a5..1e8baf9 100644 +--- a/src/net/url/url.go ++++ b/src/net/url/url.go +@@ -1109,17 +1109,23 @@ func (u *URL) UnmarshalBinary(text []byte) error { + // any existing path and the resulting path cleaned of any ./ or ../ elements. + // Any sequences of multiple / characters will be reduced to a single /. + func (u *URL) JoinPath(elem ...string) *URL { +- url := *u +- if len(elem) > 0 { +- elem = append([]string{u.EscapedPath()}, elem...) +- p := path.Join(elem...) +- // path.Join will remove any trailing slashes. +- // Preserve at least one. +- if strings.HasSuffix(elem[len(elem)-1], "/") && !strings.HasSuffix(p, "/") { +- p += "/" +- } +- url.setPath(p) ++ elem = append([]string{u.EscapedPath()}, elem...) ++ var p string ++ if !strings.HasPrefix(elem[0], "/") { ++ // Return a relative path if u is relative, ++ // but ensure that it contains no ../ elements. ++ elem[0] = "/" + elem[0] ++ p = path.Join(elem...)[1:] ++ } else { ++ p = path.Join(elem...) + } ++ // path.Join will remove any trailing slashes. ++ // Preserve at least one. ++ if strings.HasSuffix(elem[len(elem)-1], "/") && !strings.HasSuffix(p, "/") { ++ p += "/" ++ } ++ url := *u ++ url.setPath(p) + return &url + } + +-- +2.7.4 diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2020-29510.patch b/meta/recipes-devtools/go/go-1.14/CVE-2020-29510.patch new file mode 100644 index 0000000000..e1c9e0bdb9 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2020-29510.patch @@ -0,0 +1,65 @@ +From a0bf4d38dc2057d28396594264bbdd43d412de22 Mon Sep 17 00:00:00 2001 +From: Filippo Valsorda <filippo@golang.org> +Date: Tue, 27 Oct 2020 00:21:30 +0100 +Subject: [PATCH] encoding/xml: replace comments inside directives with a space + +A Directive (like <!ENTITY xxx []>) can't have other nodes nested inside +it (in our data structure representation), so there is no way to +preserve comments. The previous behavior was to just elide them, which +however might change the semantic meaning of the surrounding markup. +Instead, replace them with a space which hopefully has the same semantic +effect of the comment. + +Directives are not actually a node type in the XML spec, which instead +specifies each of them separately (<!ENTITY, <!DOCTYPE, etc.), each with +its own grammar. The rules for where and when the comments are allowed +are not straightforward, and can't be implemented without implementing +custom logic for each of the directives. + +Simply preserving the comments in the body of the directive would be +problematic, as there can be unmatched quotes inside the comment. +Whether those quotes are considered meaningful semantically or not, +other parsers might disagree and interpret the output differently. + +This issue was reported by Juho Nurminen of Mattermost as it leads to +round-trip mismatches. See #43168. It's not being fixed in a security +release because round-trip stability is not a currently supported +security property of encoding/xml, and we don't believe these fixes +would be sufficient to reliably guarantee it in the future. + +Fixes CVE-2020-29510 +Updates #43168 + +Change-Id: Icd86c75beff3e1e0689543efebdad10ed5178ce3 +Reviewed-on: https://go-review.googlesource.com/c/go/+/277893 +Run-TryBot: Filippo Valsorda <filippo@golang.org> +TryBot-Result: Go Bot <gobot@golang.org> +Trust: Filippo Valsorda <filippo@golang.org> +Reviewed-by: Katie Hockman <katie@golang.org> + +Upstream-Status: Backport from https://github.com/golang/go/commit/a9cfd55e2b09735a25976d1b008a0a3c767494f8 +CVE: CVE-2020-29510 +Signed-off-by: Shubham Kulkarni <skulkarni@mvista.com> +--- + src/encoding/xml/xml.go | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/encoding/xml/xml.go b/src/encoding/xml/xml.go +index 01a1460..98647b2 100644 +--- a/src/encoding/xml/xml.go ++++ b/src/encoding/xml/xml.go +@@ -768,6 +768,12 @@ func (d *Decoder) rawToken() (Token, error) { + } + b0, b1 = b1, b + } ++ ++ // Replace the comment with a space in the returned Directive ++ // body, so that markup parts that were separated by the comment ++ // (like a "<" and a "!") don't get joined when re-encoding the ++ // Directive, taking new semantic meaning. ++ d.buf.WriteByte(' ') + } + } + return Directive(d.buf.Bytes()), nil +-- +2.7.4 diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2021-27918.patch b/meta/recipes-devtools/go/go-1.14/CVE-2021-27918.patch new file mode 100644 index 0000000000..faa3f7f641 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2021-27918.patch @@ -0,0 +1,191 @@ +From d0b79e3513a29628f3599dc8860666b6eed75372 Mon Sep 17 00:00:00 2001 +From: Katie Hockman <katie@golang.org> +Date: Mon, 1 Mar 2021 09:54:00 -0500 +Subject: [PATCH] encoding/xml: prevent infinite loop while decoding + +This change properly handles a TokenReader which +returns an EOF in the middle of an open XML +element. + +Thanks to Sam Whited for reporting this. + +Fixes CVE-2021-27918 +Fixes #44913 + +Change-Id: Id02a3f3def4a1b415fa2d9a8e3b373eb6cb0f433 +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1004594 +Reviewed-by: Russ Cox <rsc@google.com> +Reviewed-by: Roland Shoemaker <bracewell@google.com> +Reviewed-by: Filippo Valsorda <valsorda@google.com> +Reviewed-on: https://go-review.googlesource.com/c/go/+/300391 +Trust: Katie Hockman <katie@golang.org> +Run-TryBot: Katie Hockman <katie@golang.org> +TryBot-Result: Go Bot <gobot@golang.org> +Reviewed-by: Alexander Rakoczy <alex@golang.org> +Reviewed-by: Filippo Valsorda <filippo@golang.org> + +https://github.com/golang/go/commit/d0b79e3513a29628f3599dc8860666b6eed75372 +CVE: CVE-2021-27918 +Upstream-Status: Backport +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> +--- + src/encoding/xml/xml.go | 19 ++++--- + src/encoding/xml/xml_test.go | 104 +++++++++++++++++++++++++++-------- + 2 files changed, 92 insertions(+), 31 deletions(-) + +diff --git a/src/encoding/xml/xml.go b/src/encoding/xml/xml.go +index adaf4daf198b9..6f9594d7ba7a3 100644 +--- a/src/encoding/xml/xml.go ++++ b/src/encoding/xml/xml.go +@@ -271,7 +271,7 @@ func NewTokenDecoder(t TokenReader) *Decoder { + // it will return an error. + // + // Token implements XML name spaces as described by +-// https://www.w3.org/TR/REC-xml-names/. Each of the ++// https://www.w3.org/TR/REC-xml-names/. Each of the + // Name structures contained in the Token has the Space + // set to the URL identifying its name space when known. + // If Token encounters an unrecognized name space prefix, +@@ -285,16 +285,17 @@ func (d *Decoder) Token() (Token, error) { + if d.nextToken != nil { + t = d.nextToken + d.nextToken = nil +- } else if t, err = d.rawToken(); err != nil { +- switch { +- case err == io.EOF && d.t != nil: +- err = nil +- case err == io.EOF && d.stk != nil && d.stk.kind != stkEOF: +- err = d.syntaxError("unexpected EOF") ++ } else { ++ if t, err = d.rawToken(); t == nil && err != nil { ++ if err == io.EOF && d.stk != nil && d.stk.kind != stkEOF { ++ err = d.syntaxError("unexpected EOF") ++ } ++ return nil, err + } +- return t, err ++ // We still have a token to process, so clear any ++ // errors (e.g. EOF) and proceed. ++ err = nil + } +- + if !d.Strict { + if t1, ok := d.autoClose(t); ok { + d.nextToken = t +diff --git a/src/encoding/xml/xml_test.go b/src/encoding/xml/xml_test.go +index efddca43e9102..5672ebb375f0d 100644 +--- a/src/encoding/xml/xml_test.go ++++ b/src/encoding/xml/xml_test.go +@@ -33,30 +33,90 @@ func (t *toks) Token() (Token, error) { + + func TestDecodeEOF(t *testing.T) { + start := StartElement{Name: Name{Local: "test"}} +- t.Run("EarlyEOF", func(t *testing.T) { +- d := NewTokenDecoder(&toks{earlyEOF: true, t: []Token{ +- start, +- start.End(), +- }}) +- err := d.Decode(&struct { +- XMLName Name `xml:"test"` +- }{}) +- if err != nil { +- t.Error(err) ++ tests := []struct { ++ name string ++ tokens []Token ++ ok bool ++ }{ ++ { ++ name: "OK", ++ tokens: []Token{ ++ start, ++ start.End(), ++ }, ++ ok: true, ++ }, ++ { ++ name: "Malformed", ++ tokens: []Token{ ++ start, ++ StartElement{Name: Name{Local: "bad"}}, ++ start.End(), ++ }, ++ ok: false, ++ }, ++ } ++ for _, tc := range tests { ++ for _, eof := range []bool{true, false} { ++ name := fmt.Sprintf("%s/earlyEOF=%v", tc.name, eof) ++ t.Run(name, func(t *testing.T) { ++ d := NewTokenDecoder(&toks{ ++ earlyEOF: eof, ++ t: tc.tokens, ++ }) ++ err := d.Decode(&struct { ++ XMLName Name `xml:"test"` ++ }{}) ++ if tc.ok && err != nil { ++ t.Fatalf("d.Decode: expected nil error, got %v", err) ++ } ++ if _, ok := err.(*SyntaxError); !tc.ok && !ok { ++ t.Errorf("d.Decode: expected syntax error, got %v", err) ++ } ++ }) + } +- }) +- t.Run("LateEOF", func(t *testing.T) { +- d := NewTokenDecoder(&toks{t: []Token{ +- start, +- start.End(), +- }}) +- err := d.Decode(&struct { +- XMLName Name `xml:"test"` +- }{}) +- if err != nil { +- t.Error(err) ++ } ++} ++ ++type toksNil struct { ++ returnEOF bool ++ t []Token ++} ++ ++func (t *toksNil) Token() (Token, error) { ++ if len(t.t) == 0 { ++ if !t.returnEOF { ++ // Return nil, nil before returning an EOF. It's legal, but ++ // discouraged. ++ t.returnEOF = true ++ return nil, nil + } +- }) ++ return nil, io.EOF ++ } ++ var tok Token ++ tok, t.t = t.t[0], t.t[1:] ++ return tok, nil ++} ++ ++func TestDecodeNilToken(t *testing.T) { ++ for _, strict := range []bool{true, false} { ++ name := fmt.Sprintf("Strict=%v", strict) ++ t.Run(name, func(t *testing.T) { ++ start := StartElement{Name: Name{Local: "test"}} ++ bad := StartElement{Name: Name{Local: "bad"}} ++ d := NewTokenDecoder(&toksNil{ ++ // Malformed ++ t: []Token{start, bad, start.End()}, ++ }) ++ d.Strict = strict ++ err := d.Decode(&struct { ++ XMLName Name `xml:"test"` ++ }{}) ++ if _, ok := err.(*SyntaxError); !ok { ++ t.Errorf("d.Decode: expected syntax error, got %v", err) ++ } ++ }) ++ } + } + + const testInput = ` diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2021-31525.patch b/meta/recipes-devtools/go/go-1.14/CVE-2021-31525.patch new file mode 100644 index 0000000000..afe4b0d2b8 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2021-31525.patch @@ -0,0 +1,38 @@ +From efb465ada003d23353a91ef930be408eb575dba6 Mon Sep 17 00:00:00 2001 +From: Hitendra Prajapati <hprajapati@mvista.com> +Date: Thu, 16 Jun 2022 17:40:12 +0530 +Subject: [PATCH] CVE-2021-31525 + +Upstream-Status: Backport [https://github.com/argoheyard/lang-net/commit/701957006ef151feb43f86aa99c8a1f474f69282] +CVE: CVE-2021-31525 +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> + +--- + src/vendor/golang.org/x/net/http/httpguts/httplex.go | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/src/vendor/golang.org/x/net/http/httpguts/httplex.go b/src/vendor/golang.org/x/net/http/httpguts/httplex.go +index e7de24e..c79aa73 100644 +--- a/src/vendor/golang.org/x/net/http/httpguts/httplex.go ++++ b/src/vendor/golang.org/x/net/http/httpguts/httplex.go +@@ -137,11 +137,13 @@ func trimOWS(x string) string { + // contains token amongst its comma-separated tokens, ASCII + // case-insensitively. + func headerValueContainsToken(v string, token string) bool { +- v = trimOWS(v) +- if comma := strings.IndexByte(v, ','); comma != -1 { +- return tokenEqual(trimOWS(v[:comma]), token) || headerValueContainsToken(v[comma+1:], token) ++ for comma := strings.IndexByte(v, ','); comma != -1; comma = strings.IndexByte(v, ',') { ++ if tokenEqual(trimOWS(v[:comma]), token) { ++ return true ++ } ++ v = v[comma+1:] + } +- return tokenEqual(v, token) ++ return tokenEqual(trimOWS(v), token) + } + + // lowerASCII returns the ASCII lowercase version of b. +-- +2.25.1 + diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2021-33195.patch b/meta/recipes-devtools/go/go-1.14/CVE-2021-33195.patch new file mode 100644 index 0000000000..3d9de888ff --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2021-33195.patch @@ -0,0 +1,373 @@ +From 9324d7e53151e9dfa4b25af994a28c2e0b11f729 Mon Sep 17 00:00:00 2001 +From: Roland Shoemaker <roland@golang.org> +Date: Thu, 27 May 2021 10:40:06 -0700 +Subject: [PATCH] net: verify results from Lookup* are valid domain names + +Upstream-Status: Backport [https://github.com/golang/go/commit/31d60cda1f58b7558fc5725d2b9e4531655d980e] +CVE: CVE-2021-33195 +Signed-off-by: Ralph Siemsen <ralph.siemsen@linaro.org> + + +For the methods LookupCNAME, LookupSRV, LookupMX, LookupNS, and +LookupAddr check that the returned domain names are in fact valid DNS +names using the existing isDomainName function. + +Thanks to Philipp Jeitner and Haya Shulman from Fraunhofer SIT for +reporting this issue. + +Updates #46241 +Fixes #46356 +Fixes CVE-2021-33195 + +Change-Id: I47a4f58c031cb752f732e88bbdae7f819f0af4f3 +Reviewed-on: https://go-review.googlesource.com/c/go/+/323131 +Trust: Roland Shoemaker <roland@golang.org> +Run-TryBot: Roland Shoemaker <roland@golang.org> +TryBot-Result: Go Bot <gobot@golang.org> +Reviewed-by: Filippo Valsorda <filippo@golang.org> +Reviewed-by: Katie Hockman <katie@golang.org> +(cherry picked from commit cdcd02842da7c004efd023881e3719105209c908) +Reviewed-on: https://go-review.googlesource.com/c/go/+/323269 +--- + src/net/dnsclient_unix_test.go | 157 +++++++++++++++++++++++++++++++++ + src/net/lookup.go | 111 ++++++++++++++++++++--- + 2 files changed, 255 insertions(+), 13 deletions(-) + +diff --git a/src/net/dnsclient_unix_test.go b/src/net/dnsclient_unix_test.go +index 2ad40df..b8617d9 100644 +--- a/src/net/dnsclient_unix_test.go ++++ b/src/net/dnsclient_unix_test.go +@@ -1800,3 +1800,160 @@ func TestPTRandNonPTR(t *testing.T) { + t.Errorf("names = %q; want %q", names, want) + } + } ++ ++func TestCVE202133195(t *testing.T) { ++ fake := fakeDNSServer{ ++ rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) { ++ r := dnsmessage.Message{ ++ Header: dnsmessage.Header{ ++ ID: q.Header.ID, ++ Response: true, ++ RCode: dnsmessage.RCodeSuccess, ++ RecursionAvailable: true, ++ }, ++ Questions: q.Questions, ++ } ++ switch q.Questions[0].Type { ++ case dnsmessage.TypeCNAME: ++ r.Answers = []dnsmessage.Resource{} ++ case dnsmessage.TypeA: // CNAME lookup uses a A/AAAA as a proxy ++ r.Answers = append(r.Answers, ++ dnsmessage.Resource{ ++ Header: dnsmessage.ResourceHeader{ ++ Name: dnsmessage.MustNewName("<html>.golang.org."), ++ Type: dnsmessage.TypeA, ++ Class: dnsmessage.ClassINET, ++ Length: 4, ++ }, ++ Body: &dnsmessage.AResource{ ++ A: TestAddr, ++ }, ++ }, ++ ) ++ case dnsmessage.TypeSRV: ++ n := q.Questions[0].Name ++ if n.String() == "_hdr._tcp.golang.org." { ++ n = dnsmessage.MustNewName("<html>.golang.org.") ++ } ++ r.Answers = append(r.Answers, ++ dnsmessage.Resource{ ++ Header: dnsmessage.ResourceHeader{ ++ Name: n, ++ Type: dnsmessage.TypeSRV, ++ Class: dnsmessage.ClassINET, ++ Length: 4, ++ }, ++ Body: &dnsmessage.SRVResource{ ++ Target: dnsmessage.MustNewName("<html>.golang.org."), ++ }, ++ }, ++ ) ++ case dnsmessage.TypeMX: ++ r.Answers = append(r.Answers, ++ dnsmessage.Resource{ ++ Header: dnsmessage.ResourceHeader{ ++ Name: dnsmessage.MustNewName("<html>.golang.org."), ++ Type: dnsmessage.TypeMX, ++ Class: dnsmessage.ClassINET, ++ Length: 4, ++ }, ++ Body: &dnsmessage.MXResource{ ++ MX: dnsmessage.MustNewName("<html>.golang.org."), ++ }, ++ }, ++ ) ++ case dnsmessage.TypeNS: ++ r.Answers = append(r.Answers, ++ dnsmessage.Resource{ ++ Header: dnsmessage.ResourceHeader{ ++ Name: dnsmessage.MustNewName("<html>.golang.org."), ++ Type: dnsmessage.TypeNS, ++ Class: dnsmessage.ClassINET, ++ Length: 4, ++ }, ++ Body: &dnsmessage.NSResource{ ++ NS: dnsmessage.MustNewName("<html>.golang.org."), ++ }, ++ }, ++ ) ++ case dnsmessage.TypePTR: ++ r.Answers = append(r.Answers, ++ dnsmessage.Resource{ ++ Header: dnsmessage.ResourceHeader{ ++ Name: dnsmessage.MustNewName("<html>.golang.org."), ++ Type: dnsmessage.TypePTR, ++ Class: dnsmessage.ClassINET, ++ Length: 4, ++ }, ++ Body: &dnsmessage.PTRResource{ ++ PTR: dnsmessage.MustNewName("<html>.golang.org."), ++ }, ++ }, ++ ) ++ } ++ return r, nil ++ }, ++ } ++ ++ r := Resolver{PreferGo: true, Dial: fake.DialContext} ++ // Change the default resolver to match our manipulated resolver ++ originalDefault := DefaultResolver ++ DefaultResolver = &r ++ defer func() { ++ DefaultResolver = originalDefault ++ }() ++ ++ _, err := r.LookupCNAME(context.Background(), "golang.org") ++ if expected := "lookup golang.org: CNAME target is invalid"; err == nil || err.Error() != expected { ++ t.Errorf("Resolver.LookupCNAME returned unexpected error, got %q, want %q", err.Error(), expected) ++ } ++ _, err = LookupCNAME("golang.org") ++ if expected := "lookup golang.org: CNAME target is invalid"; err == nil || err.Error() != expected { ++ t.Errorf("LookupCNAME returned unexpected error, got %q, want %q", err.Error(), expected) ++ } ++ ++ _, _, err = r.LookupSRV(context.Background(), "target", "tcp", "golang.org") ++ if expected := "lookup golang.org: SRV target is invalid"; err == nil || err.Error() != expected { ++ t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err.Error(), expected) ++ } ++ _, _, err = LookupSRV("target", "tcp", "golang.org") ++ if expected := "lookup golang.org: SRV target is invalid"; err == nil || err.Error() != expected { ++ t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err.Error(), expected) ++ } ++ ++ _, _, err = r.LookupSRV(context.Background(), "hdr", "tcp", "golang.org") ++ if expected := "lookup golang.org: SRV header name is invalid"; err == nil || err.Error() != expected { ++ t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err.Error(), expected) ++ } ++ _, _, err = LookupSRV("hdr", "tcp", "golang.org") ++ if expected := "lookup golang.org: SRV header name is invalid"; err == nil || err.Error() != expected { ++ t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err.Error(), expected) ++ } ++ ++ _, err = r.LookupMX(context.Background(), "golang.org") ++ if expected := "lookup golang.org: MX target is invalid"; err == nil || err.Error() != expected { ++ t.Errorf("Resolver.LookupMX returned unexpected error, got %q, want %q", err.Error(), expected) ++ } ++ _, err = LookupMX("golang.org") ++ if expected := "lookup golang.org: MX target is invalid"; err == nil || err.Error() != expected { ++ t.Errorf("LookupMX returned unexpected error, got %q, want %q", err.Error(), expected) ++ } ++ ++ _, err = r.LookupNS(context.Background(), "golang.org") ++ if expected := "lookup golang.org: NS target is invalid"; err == nil || err.Error() != expected { ++ t.Errorf("Resolver.LookupNS returned unexpected error, got %q, want %q", err.Error(), expected) ++ } ++ _, err = LookupNS("golang.org") ++ if expected := "lookup golang.org: NS target is invalid"; err == nil || err.Error() != expected { ++ t.Errorf("LookupNS returned unexpected error, got %q, want %q", err.Error(), expected) ++ } ++ ++ _, err = r.LookupAddr(context.Background(), "1.2.3.4") ++ if expected := "lookup 1.2.3.4: PTR target is invalid"; err == nil || err.Error() != expected { ++ t.Errorf("Resolver.LookupAddr returned unexpected error, got %q, want %q", err.Error(), expected) ++ } ++ _, err = LookupAddr("1.2.3.4") ++ if expected := "lookup 1.2.3.4: PTR target is invalid"; err == nil || err.Error() != expected { ++ t.Errorf("LookupAddr returned unexpected error, got %q, want %q", err.Error(), expected) ++ } ++} +diff --git a/src/net/lookup.go b/src/net/lookup.go +index 9cebd10..05e88e4 100644 +--- a/src/net/lookup.go ++++ b/src/net/lookup.go +@@ -364,8 +364,11 @@ func (r *Resolver) LookupPort(ctx context.Context, network, service string) (por + // LookupCNAME does not return an error if host does not + // contain DNS "CNAME" records, as long as host resolves to + // address records. ++// ++// The returned canonical name is validated to be a properly ++// formatted presentation-format domain name. + func LookupCNAME(host string) (cname string, err error) { +- return DefaultResolver.lookupCNAME(context.Background(), host) ++ return DefaultResolver.LookupCNAME(context.Background(), host) + } + + // LookupCNAME returns the canonical name for the given host. +@@ -378,8 +381,18 @@ func LookupCNAME(host string) (cname string, err error) { + // LookupCNAME does not return an error if host does not + // contain DNS "CNAME" records, as long as host resolves to + // address records. +-func (r *Resolver) LookupCNAME(ctx context.Context, host string) (cname string, err error) { +- return r.lookupCNAME(ctx, host) ++// ++// The returned canonical name is validated to be a properly ++// formatted presentation-format domain name. ++func (r *Resolver) LookupCNAME(ctx context.Context, host string) (string, error) { ++ cname, err := r.lookupCNAME(ctx, host) ++ if err != nil { ++ return "", err ++ } ++ if !isDomainName(cname) { ++ return "", &DNSError{Err: "CNAME target is invalid", Name: host} ++ } ++ return cname, nil + } + + // LookupSRV tries to resolve an SRV query of the given service, +@@ -391,8 +404,11 @@ func (r *Resolver) LookupCNAME(ctx context.Context, host string) (cname string, + // That is, it looks up _service._proto.name. To accommodate services + // publishing SRV records under non-standard names, if both service + // and proto are empty strings, LookupSRV looks up name directly. ++// ++// The returned service names are validated to be properly ++// formatted presentation-format domain names. + func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) { +- return DefaultResolver.lookupSRV(context.Background(), service, proto, name) ++ return DefaultResolver.LookupSRV(context.Background(), service, proto, name) + } + + // LookupSRV tries to resolve an SRV query of the given service, +@@ -404,28 +420,82 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err err + // That is, it looks up _service._proto.name. To accommodate services + // publishing SRV records under non-standard names, if both service + // and proto are empty strings, LookupSRV looks up name directly. +-func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*SRV, err error) { +- return r.lookupSRV(ctx, service, proto, name) ++// ++// The returned service names are validated to be properly ++// formatted presentation-format domain names. ++func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) { ++ cname, addrs, err := r.lookupSRV(ctx, service, proto, name) ++ if err != nil { ++ return "", nil, err ++ } ++ if cname != "" && !isDomainName(cname) { ++ return "", nil, &DNSError{Err: "SRV header name is invalid", Name: name} ++ } ++ for _, addr := range addrs { ++ if addr == nil { ++ continue ++ } ++ if !isDomainName(addr.Target) { ++ return "", nil, &DNSError{Err: "SRV target is invalid", Name: name} ++ } ++ } ++ return cname, addrs, nil + } + + // LookupMX returns the DNS MX records for the given domain name sorted by preference. ++// ++// The returned mail server names are validated to be properly ++// formatted presentation-format domain names. + func LookupMX(name string) ([]*MX, error) { +- return DefaultResolver.lookupMX(context.Background(), name) ++ return DefaultResolver.LookupMX(context.Background(), name) + } + + // LookupMX returns the DNS MX records for the given domain name sorted by preference. ++// ++// The returned mail server names are validated to be properly ++// formatted presentation-format domain names. + func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) { +- return r.lookupMX(ctx, name) ++ records, err := r.lookupMX(ctx, name) ++ if err != nil { ++ return nil, err ++ } ++ for _, mx := range records { ++ if mx == nil { ++ continue ++ } ++ if !isDomainName(mx.Host) { ++ return nil, &DNSError{Err: "MX target is invalid", Name: name} ++ } ++ } ++ return records, nil + } + + // LookupNS returns the DNS NS records for the given domain name. ++// ++// The returned name server names are validated to be properly ++// formatted presentation-format domain names. + func LookupNS(name string) ([]*NS, error) { +- return DefaultResolver.lookupNS(context.Background(), name) ++ return DefaultResolver.LookupNS(context.Background(), name) + } + + // LookupNS returns the DNS NS records for the given domain name. ++// ++// The returned name server names are validated to be properly ++// formatted presentation-format domain names. + func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) { +- return r.lookupNS(ctx, name) ++ records, err := r.lookupNS(ctx, name) ++ if err != nil { ++ return nil, err ++ } ++ for _, ns := range records { ++ if ns == nil { ++ continue ++ } ++ if !isDomainName(ns.Host) { ++ return nil, &DNSError{Err: "NS target is invalid", Name: name} ++ } ++ } ++ return records, nil + } + + // LookupTXT returns the DNS TXT records for the given domain name. +@@ -441,14 +511,29 @@ func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error) + // LookupAddr performs a reverse lookup for the given address, returning a list + // of names mapping to that address. + // ++// The returned names are validated to be properly formatted presentation-format ++// domain names. ++// + // When using the host C library resolver, at most one result will be + // returned. To bypass the host resolver, use a custom Resolver. + func LookupAddr(addr string) (names []string, err error) { +- return DefaultResolver.lookupAddr(context.Background(), addr) ++ return DefaultResolver.LookupAddr(context.Background(), addr) + } + + // LookupAddr performs a reverse lookup for the given address, returning a list + // of names mapping to that address. +-func (r *Resolver) LookupAddr(ctx context.Context, addr string) (names []string, err error) { +- return r.lookupAddr(ctx, addr) ++// ++// The returned names are validated to be properly formatted presentation-format ++// domain names. ++func (r *Resolver) LookupAddr(ctx context.Context, addr string) ([]string, error) { ++ names, err := r.lookupAddr(ctx, addr) ++ if err != nil { ++ return nil, err ++ } ++ for _, name := range names { ++ if !isDomainName(name) { ++ return nil, &DNSError{Err: "PTR target is invalid", Name: addr} ++ } ++ } ++ return names, nil + } diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2021-33196.patch b/meta/recipes-devtools/go/go-1.14/CVE-2021-33196.patch new file mode 100644 index 0000000000..2e2dc62c49 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2021-33196.patch @@ -0,0 +1,124 @@ +From 74242baa4136c7a9132a8ccd9881354442788c8c Mon Sep 17 00:00:00 2001 +From: Roland Shoemaker <roland@golang.org> +Date: Tue, 11 May 2021 11:31:31 -0700 +Subject: [PATCH] archive/zip: only preallocate File slice if reasonably sized + +Since the number of files in the EOCD record isn't validated, it isn't +safe to preallocate Reader.Files using that field. A malformed archive +can indicate it contains up to 1 << 128 - 1 files. We can still safely +preallocate the slice by checking if the specified number of files in +the archive is reasonable, given the size of the archive. + +Thanks to the OSS-Fuzz project for discovering this issue and to +Emmanuel Odeke for reporting it. + +Fixes #46242 +Fixes CVE-2021-33196 + +Change-Id: I3c76d8eec178468b380d87fdb4a3f2cb06f0ee76 +Reviewed-on: https://go-review.googlesource.com/c/go/+/318909 +Trust: Roland Shoemaker <roland@golang.org> +Trust: Katie Hockman <katie@golang.org> +Trust: Joe Tsai <thebrokentoaster@gmail.com> +Run-TryBot: Roland Shoemaker <roland@golang.org> +TryBot-Result: Go Bot <gobot@golang.org> +Reviewed-by: Katie Hockman <katie@golang.org> +Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com> + +Upstream-Status: Backport +CVE: CVE-2021-33196 +Signed-off-by: Armin Kuster <akuster@mvista.com> + +--- + src/archive/zip/reader.go | 10 +++++- + src/archive/zip/reader_test.go | 59 ++++++++++++++++++++++++++++++++++ + 2 files changed, 68 insertions(+), 1 deletion(-) + +Index: go/src/archive/zip/reader.go +=================================================================== +--- go.orig/src/archive/zip/reader.go ++++ go/src/archive/zip/reader.go +@@ -84,7 +84,15 @@ func (z *Reader) init(r io.ReaderAt, siz + return err + } + z.r = r +- z.File = make([]*File, 0, end.directoryRecords) ++ // Since the number of directory records is not validated, it is not ++ // safe to preallocate z.File without first checking that the specified ++ // number of files is reasonable, since a malformed archive may ++ // indicate it contains up to 1 << 128 - 1 files. Since each file has a ++ // header which will be _at least_ 30 bytes we can safely preallocate ++ // if (data size / 30) >= end.directoryRecords. ++ if (uint64(size)-end.directorySize)/30 >= end.directoryRecords { ++ z.File = make([]*File, 0, end.directoryRecords) ++ } + z.Comment = end.comment + rs := io.NewSectionReader(r, 0, size) + if _, err = rs.Seek(int64(end.directoryOffset), io.SeekStart); err != nil { +Index: go/src/archive/zip/reader_test.go +=================================================================== +--- go.orig/src/archive/zip/reader_test.go ++++ go/src/archive/zip/reader_test.go +@@ -1070,3 +1070,62 @@ func TestIssue12449(t *testing.T) { + t.Errorf("Error reading the archive: %v", err) + } + } ++ ++func TestCVE202133196(t *testing.T) { ++ // Archive that indicates it has 1 << 128 -1 files, ++ // this would previously cause a panic due to attempting ++ // to allocate a slice with 1 << 128 -1 elements. ++ data := []byte{ ++ 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x08, 0x08, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x02, ++ 0x03, 0x62, 0x61, 0x65, 0x03, 0x04, 0x00, 0x00, ++ 0xff, 0xff, 0x50, 0x4b, 0x07, 0x08, 0xbe, 0x20, ++ 0x5c, 0x6c, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, ++ 0x00, 0x00, 0x50, 0x4b, 0x01, 0x02, 0x14, 0x00, ++ 0x14, 0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0xbe, 0x20, 0x5c, 0x6c, 0x09, 0x00, ++ 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x01, 0x02, 0x03, 0x50, 0x4b, 0x06, 0x06, 0x2c, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, ++ 0x00, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0x31, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0x4b, 0x06, 0x07, 0x00, ++ 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, ++ 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0x00, 0x00, ++ } ++ _, err := NewReader(bytes.NewReader(data), int64(len(data))) ++ if err != ErrFormat { ++ t.Fatalf("unexpected error, got: %v, want: %v", err, ErrFormat) ++ } ++ ++ // Also check that an archive containing a handful of empty ++ // files doesn't cause an issue ++ b := bytes.NewBuffer(nil) ++ w := NewWriter(b) ++ for i := 0; i < 5; i++ { ++ _, err := w.Create("") ++ if err != nil { ++ t.Fatalf("Writer.Create failed: %s", err) ++ } ++ } ++ if err := w.Close(); err != nil { ++ t.Fatalf("Writer.Close failed: %s", err) ++ } ++ r, err := NewReader(bytes.NewReader(b.Bytes()), int64(b.Len())) ++ if err != nil { ++ t.Fatalf("NewReader failed: %s", err) ++ } ++ if len(r.File) != 5 { ++ t.Errorf("Archive has unexpected number of files, got %d, want 5", len(r.File)) ++ } ++} diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2021-33197.patch b/meta/recipes-devtools/go/go-1.14/CVE-2021-33197.patch new file mode 100644 index 0000000000..2052b1d3db --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2021-33197.patch @@ -0,0 +1,152 @@ +From cbd1ca84453fecf3825a6bb9f985823e8bc32b76 Mon Sep 17 00:00:00 2001 +From: Filippo Valsorda <filippo@golang.org> +Date: Fri, 21 May 2021 14:02:30 -0400 +Subject: [PATCH] [release-branch.go1.15] net/http/httputil: always remove + hop-by-hop headers + +Previously, we'd fail to remove the Connection header from a request +like this: + + Connection: + Connection: x-header + +Updates #46313 +Fixes #46314 +Fixes CVE-2021-33197 + +Change-Id: Ie3009e926ceecfa86dfa6bcc6fe14ff01086be7d +Reviewed-on: https://go-review.googlesource.com/c/go/+/321929 +Run-TryBot: Filippo Valsorda <filippo@golang.org> +Reviewed-by: Katie Hockman <katie@golang.org> +Trust: Katie Hockman <katie@golang.org> +Trust: Filippo Valsorda <filippo@golang.org> +TryBot-Result: Go Bot <gobot@golang.org> +Reviewed-on: https://go-review.googlesource.com/c/go/+/323091 +Run-TryBot: Katie Hockman <katie@golang.org> + +Upstream-Status: Backport +CVE: CVE-2021-33197 +Signed-off-by: Armin Kuster <akuster@mvista.com> + +--- + src/net/http/httputil/reverseproxy.go | 22 ++++---- + src/net/http/httputil/reverseproxy_test.go | 63 +++++++++++++++++++++- + 2 files changed, 70 insertions(+), 15 deletions(-) + +Index: go/src/net/http/httputil/reverseproxy.go +=================================================================== +--- go.orig/src/net/http/httputil/reverseproxy.go ++++ go/src/net/http/httputil/reverseproxy.go +@@ -221,22 +221,18 @@ func (p *ReverseProxy) ServeHTTP(rw http + // important is "Connection" because we want a persistent + // connection, regardless of what the client sent to us. + for _, h := range hopHeaders { +- hv := outreq.Header.Get(h) +- if hv == "" { +- continue +- } +- if h == "Te" && hv == "trailers" { +- // Issue 21096: tell backend applications that +- // care about trailer support that we support +- // trailers. (We do, but we don't go out of +- // our way to advertise that unless the +- // incoming client request thought it was +- // worth mentioning) +- continue +- } + outreq.Header.Del(h) + } + ++ // Issue 21096: tell backend applications that care about trailer support ++ // that we support trailers. (We do, but we don't go out of our way to ++ // advertise that unless the incoming client request thought it was worth ++ // mentioning.) Note that we look at req.Header, not outreq.Header, since ++ // the latter has passed through removeConnectionHeaders. ++ if httpguts.HeaderValuesContainsToken(req.Header["Te"], "trailers") { ++ outreq.Header.Set("Te", "trailers") ++ } ++ + // After stripping all the hop-by-hop connection headers above, add back any + // necessary for protocol upgrades, such as for websockets. + if reqUpType != "" { +Index: go/src/net/http/httputil/reverseproxy_test.go +=================================================================== +--- go.orig/src/net/http/httputil/reverseproxy_test.go ++++ go/src/net/http/httputil/reverseproxy_test.go +@@ -91,8 +91,9 @@ func TestReverseProxy(t *testing.T) { + + getReq, _ := http.NewRequest("GET", frontend.URL, nil) + getReq.Host = "some-name" +- getReq.Header.Set("Connection", "close") +- getReq.Header.Set("Te", "trailers") ++ getReq.Header.Set("Connection", "close, TE") ++ getReq.Header.Add("Te", "foo") ++ getReq.Header.Add("Te", "bar, trailers") + getReq.Header.Set("Proxy-Connection", "should be deleted") + getReq.Header.Set("Upgrade", "foo") + getReq.Close = true +@@ -236,6 +237,64 @@ func TestReverseProxyStripHeadersPresent + } + } + ++func TestReverseProxyStripEmptyConnection(t *testing.T) { ++ // See Issue 46313. ++ const backendResponse = "I am the backend" ++ ++ // someConnHeader is some arbitrary header to be declared as a hop-by-hop header ++ // in the Request's Connection header. ++ const someConnHeader = "X-Some-Conn-Header" ++ ++ backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ++ if c := r.Header.Values("Connection"); len(c) != 0 { ++ t.Errorf("handler got header %q = %v; want empty", "Connection", c) ++ } ++ if c := r.Header.Get(someConnHeader); c != "" { ++ t.Errorf("handler got header %q = %q; want empty", someConnHeader, c) ++ } ++ w.Header().Add("Connection", "") ++ w.Header().Add("Connection", someConnHeader) ++ w.Header().Set(someConnHeader, "should be deleted") ++ io.WriteString(w, backendResponse) ++ })) ++ defer backend.Close() ++ backendURL, err := url.Parse(backend.URL) ++ if err != nil { ++ t.Fatal(err) ++ } ++ proxyHandler := NewSingleHostReverseProxy(backendURL) ++ frontend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ++ proxyHandler.ServeHTTP(w, r) ++ if c := r.Header.Get(someConnHeader); c != "should be deleted" { ++ t.Errorf("handler modified header %q = %q; want %q", someConnHeader, c, "should be deleted") ++ } ++ })) ++ defer frontend.Close() ++ ++ getReq, _ := http.NewRequest("GET", frontend.URL, nil) ++ getReq.Header.Add("Connection", "") ++ getReq.Header.Add("Connection", someConnHeader) ++ getReq.Header.Set(someConnHeader, "should be deleted") ++ res, err := frontend.Client().Do(getReq) ++ if err != nil { ++ t.Fatalf("Get: %v", err) ++ } ++ defer res.Body.Close() ++ bodyBytes, err := ioutil.ReadAll(res.Body) ++ if err != nil { ++ t.Fatalf("reading body: %v", err) ++ } ++ if got, want := string(bodyBytes), backendResponse; got != want { ++ t.Errorf("got body %q; want %q", got, want) ++ } ++ if c := res.Header.Get("Connection"); c != "" { ++ t.Errorf("handler got header %q = %q; want empty", "Connection", c) ++ } ++ if c := res.Header.Get(someConnHeader); c != "" { ++ t.Errorf("handler got header %q = %q; want empty", someConnHeader, c) ++ } ++} ++ + func TestXForwardedFor(t *testing.T) { + const prevForwardedFor = "client ip" + const backendResponse = "I am the backend" diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2021-33198.patch b/meta/recipes-devtools/go/go-1.14/CVE-2021-33198.patch new file mode 100644 index 0000000000..241c08dad7 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2021-33198.patch @@ -0,0 +1,113 @@ +From c8866491ac424cdf39aedb325e6dec9e54418cfb Mon Sep 17 00:00:00 2001 +From: Robert Griesemer <gri@golang.org> +Date: Sun, 2 May 2021 11:27:03 -0700 +Subject: [PATCH] math/big: check for excessive exponents in Rat.SetString + +CVE-2021-33198 + +Upstream-Status: Backport [https://github.com/golang/go/commit/df9ce19db6df32d94eae8760927bdfbc595433c3] +CVE: CVE-2021-33198 +Signed-off-by: Ralph Siemsen <ralph.siemsen@linaro.org> + + +Found by OSS-Fuzz https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=33284 + +Thanks to Emmanuel Odeke for reporting this issue. + +Updates #45910 +Fixes #46305 +Fixes CVE-2021-33198 + +Change-Id: I61e7b04dbd80343420b57eede439e361c0f7b79c +Reviewed-on: https://go-review.googlesource.com/c/go/+/316149 +Trust: Robert Griesemer <gri@golang.org> +Trust: Katie Hockman <katie@golang.org> +Run-TryBot: Robert Griesemer <gri@golang.org> +TryBot-Result: Go Bot <gobot@golang.org> +Reviewed-by: Katie Hockman <katie@golang.org> +Reviewed-by: Emmanuel Odeke <emmanuel@orijtech.com> +(cherry picked from commit 6c591f79b0b5327549bd4e94970f7a279efb4ab0) +Reviewed-on: https://go-review.googlesource.com/c/go/+/321831 +Run-TryBot: Katie Hockman <katie@golang.org> +Reviewed-by: Roland Shoemaker <roland@golang.org> +--- + src/math/big/ratconv.go | 15 ++++++++------- + src/math/big/ratconv_test.go | 25 +++++++++++++++++++++++++ + 2 files changed, 33 insertions(+), 7 deletions(-) + +diff --git a/src/math/big/ratconv.go b/src/math/big/ratconv.go +index e8cbdbe..90053a9 100644 +--- a/src/math/big/ratconv.go ++++ b/src/math/big/ratconv.go +@@ -51,7 +51,8 @@ func (z *Rat) Scan(s fmt.ScanState, ch rune) error { + // An optional base-10 ``e'' or base-2 ``p'' (or their upper-case variants) + // exponent may be provided as well, except for hexadecimal floats which + // only accept an (optional) ``p'' exponent (because an ``e'' or ``E'' cannot +-// be distinguished from a mantissa digit). ++// be distinguished from a mantissa digit). If the exponent's absolute value ++// is too large, the operation may fail. + // The entire string, not just a prefix, must be valid for success. If the + // operation failed, the value of z is undefined but the returned value is nil. + func (z *Rat) SetString(s string) (*Rat, bool) { +@@ -174,6 +175,9 @@ func (z *Rat) SetString(s string) (*Rat, bool) { + return nil, false + } + } ++ if n > 1e6 { ++ return nil, false // avoid excessively large exponents ++ } + pow5 := z.b.abs.expNN(natFive, nat(nil).setWord(Word(n)), nil) // use underlying array of z.b.abs + if exp5 > 0 { + z.a.abs = z.a.abs.mul(z.a.abs, pow5) +@@ -186,15 +190,12 @@ func (z *Rat) SetString(s string) (*Rat, bool) { + } + + // apply exp2 contributions ++ if exp2 < -1e7 || exp2 > 1e7 { ++ return nil, false // avoid excessively large exponents ++ } + if exp2 > 0 { +- if int64(uint(exp2)) != exp2 { +- panic("exponent too large") +- } + z.a.abs = z.a.abs.shl(z.a.abs, uint(exp2)) + } else if exp2 < 0 { +- if int64(uint(-exp2)) != -exp2 { +- panic("exponent too large") +- } + z.b.abs = z.b.abs.shl(z.b.abs, uint(-exp2)) + } + +diff --git a/src/math/big/ratconv_test.go b/src/math/big/ratconv_test.go +index b820df4..e55e655 100644 +--- a/src/math/big/ratconv_test.go ++++ b/src/math/big/ratconv_test.go +@@ -590,3 +590,28 @@ func TestIssue31184(t *testing.T) { + } + } + } ++ ++func TestIssue45910(t *testing.T) { ++ var x Rat ++ for _, test := range []struct { ++ input string ++ want bool ++ }{ ++ {"1e-1000001", false}, ++ {"1e-1000000", true}, ++ {"1e+1000000", true}, ++ {"1e+1000001", false}, ++ ++ {"0p1000000000000", true}, ++ {"1p-10000001", false}, ++ {"1p-10000000", true}, ++ {"1p+10000000", true}, ++ {"1p+10000001", false}, ++ {"1.770p02041010010011001001", false}, // test case from issue ++ } { ++ _, got := x.SetString(test.input) ++ if got != test.want { ++ t.Errorf("SetString(%s) got ok = %v; want %v", test.input, got, test.want) ++ } ++ } ++} diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2021-34558.patch b/meta/recipes-devtools/go/go-1.14/CVE-2021-34558.patch new file mode 100644 index 0000000000..8fb346d622 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2021-34558.patch @@ -0,0 +1,51 @@ +From a98589711da5e9d935e8d690cfca92892e86d557 Mon Sep 17 00:00:00 2001 +From: Roland Shoemaker <roland@golang.org> +Date: Wed, 9 Jun 2021 11:31:27 -0700 +Subject: [PATCH] crypto/tls: test key type when casting + +When casting the certificate public key in generateClientKeyExchange, +check the type is appropriate. This prevents a panic when a server +agrees to a RSA based key exchange, but then sends an ECDSA (or +other) certificate. + +Fixes #47143 +Fixes CVE-2021-34558 + +Thanks to Imre Rad for reporting this issue. + +Change-Id: Iabccacca6052769a605cccefa1216a9f7b7f6aea +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1116723 +Reviewed-by: Filippo Valsorda <valsorda@google.com> +Reviewed-by: Katie Hockman <katiehockman@google.com> +Reviewed-on: https://go-review.googlesource.com/c/go/+/334031 +Trust: Filippo Valsorda <filippo@golang.org> +Run-TryBot: Filippo Valsorda <filippo@golang.org> +TryBot-Result: Go Bot <gobot@golang.org> +Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org> + +Upstream-Status: Backport +https://github.com/golang/go/commit/a98589711da5e9d935e8d690cfca92892e86d557 +CVE: CVE-2021-34558 +Signed-off-by: Armin Kuster <akuster@mvista.com> + +--- + src/crypto/tls/key_agreement.go | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +Index: go/src/crypto/tls/key_agreement.go +=================================================================== +--- go.orig/src/crypto/tls/key_agreement.go ++++ go/src/crypto/tls/key_agreement.go +@@ -67,7 +67,11 @@ func (ka rsaKeyAgreement) generateClient + return nil, nil, err + } + +- encrypted, err := rsa.EncryptPKCS1v15(config.rand(), cert.PublicKey.(*rsa.PublicKey), preMasterSecret) ++ rsaKey, ok := cert.PublicKey.(*rsa.PublicKey) ++ if !ok { ++ return nil, nil, errors.New("tls: server certificate contains incorrect key type for selected ciphersuite") ++ } ++ encrypted, err := rsa.EncryptPKCS1v15(config.rand(), rsaKey, preMasterSecret) + if err != nil { + return nil, nil, err + } diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2021-36221.patch b/meta/recipes-devtools/go/go-1.14/CVE-2021-36221.patch new file mode 100644 index 0000000000..9c00d4ebb2 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2021-36221.patch @@ -0,0 +1,101 @@ +From b7a85e0003cedb1b48a1fd3ae5b746ec6330102e Mon Sep 17 00:00:00 2001 +From: Damien Neil <dneil@google.com> +Date: Wed, 7 Jul 2021 16:34:34 -0700 +Subject: [PATCH] net/http/httputil: close incoming ReverseProxy request body + +Reading from an incoming request body after the request handler aborts +with a panic can cause a panic, becuse http.Server does not (contrary +to its documentation) close the request body in this case. + +Always close the incoming request body in ReverseProxy.ServeHTTP to +ensure that any in-flight outgoing requests using the body do not +read from it. + +Updates #46866 +Fixes CVE-2021-36221 + +Change-Id: I310df269200ad8732c5d9f1a2b00de68725831df +Reviewed-on: https://go-review.googlesource.com/c/go/+/333191 +Trust: Damien Neil <dneil@google.com> +Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> +Reviewed-by: Filippo Valsorda <filippo@golang.org> + +https://github.com/golang/go/commit/b7a85e0003cedb1b48a1fd3ae5b746ec6330102e +CVE: CVE-2021-36221 +Upstream-Status: Backport +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> +--- + src/net/http/httputil/reverseproxy.go | 9 +++++ + src/net/http/httputil/reverseproxy_test.go | 39 ++++++++++++++++++++++ + 2 files changed, 48 insertions(+) + +diff --git a/src/net/http/httputil/reverseproxy.go b/src/net/http/httputil/reverseproxy.go +index 5d39955d62d15..8b63368386f43 100644 +--- a/src/net/http/httputil/reverseproxy.go ++++ b/src/net/http/httputil/reverseproxy.go +@@ -235,6 +235,15 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { + if req.ContentLength == 0 { + outreq.Body = nil // Issue 16036: nil Body for http.Transport retries + } ++ if outreq.Body != nil { ++ // Reading from the request body after returning from a handler is not ++ // allowed, and the RoundTrip goroutine that reads the Body can outlive ++ // this handler. This can lead to a crash if the handler panics (see ++ // Issue 46866). Although calling Close doesn't guarantee there isn't ++ // any Read in flight after the handle returns, in practice it's safe to ++ // read after closing it. ++ defer outreq.Body.Close() ++ } + if outreq.Header == nil { + outreq.Header = make(http.Header) // Issue 33142: historical behavior was to always allocate + } +diff --git a/src/net/http/httputil/reverseproxy_test.go b/src/net/http/httputil/reverseproxy_test.go +index 1898ed8b8afde..4b6ad77a29466 100644 +--- a/src/net/http/httputil/reverseproxy_test.go ++++ b/src/net/http/httputil/reverseproxy_test.go +@@ -1122,6 +1122,45 @@ func TestReverseProxy_PanicBodyError(t *testing.T) { + rproxy.ServeHTTP(httptest.NewRecorder(), req) + } + ++// Issue #46866: panic without closing incoming request body causes a panic ++func TestReverseProxy_PanicClosesIncomingBody(t *testing.T) { ++ backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ++ out := "this call was relayed by the reverse proxy" ++ // Coerce a wrong content length to induce io.ErrUnexpectedEOF ++ w.Header().Set("Content-Length", fmt.Sprintf("%d", len(out)*2)) ++ fmt.Fprintln(w, out) ++ })) ++ defer backend.Close() ++ backendURL, err := url.Parse(backend.URL) ++ if err != nil { ++ t.Fatal(err) ++ } ++ proxyHandler := NewSingleHostReverseProxy(backendURL) ++ proxyHandler.ErrorLog = log.New(io.Discard, "", 0) // quiet for tests ++ frontend := httptest.NewServer(proxyHandler) ++ defer frontend.Close() ++ frontendClient := frontend.Client() ++ ++ var wg sync.WaitGroup ++ for i := 0; i < 2; i++ { ++ wg.Add(1) ++ go func() { ++ defer wg.Done() ++ for j := 0; j < 10; j++ { ++ const reqLen = 6 * 1024 * 1024 ++ req, _ := http.NewRequest("POST", frontend.URL, &io.LimitedReader{R: neverEnding('x'), N: reqLen}) ++ req.ContentLength = reqLen ++ resp, _ := frontendClient.Transport.RoundTrip(req) ++ if resp != nil { ++ io.Copy(io.Discard, resp.Body) ++ resp.Body.Close() ++ } ++ } ++ }() ++ } ++ wg.Wait() ++} ++ + func TestSelectFlushInterval(t *testing.T) { + tests := []struct { + name string diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2021-38297.patch b/meta/recipes-devtools/go/go-1.14/CVE-2021-38297.patch new file mode 100644 index 0000000000..24ceabf808 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2021-38297.patch @@ -0,0 +1,97 @@ +From 4548fcc8dfd933c237f29bba6f90040a85922564 Mon Sep 17 00:00:00 2001 +From: Michael Knyszek <mknyszek@google.com> +Date: Thu, 2 Sep 2021 16:51:59 -0400 +Subject: [PATCH] [release-branch.go1.16] misc/wasm, cmd/link: do not let + command line args overwrite global data + +On Wasm, wasm_exec.js puts command line arguments at the beginning +of the linear memory (following the "zero page"). Currently there +is no limit for this, and a very long command line can overwrite +the program's data section. Prevent this by limiting the command +line to 4096 bytes, and in the linker ensuring the data section +starts at a high enough address (8192). + +(Arguably our address assignment on Wasm is a bit confusing. This +is the minimum fix I can come up with.) + +Thanks to Ben Lubar for reporting this issue. + +Change by Cherry Mui <cherryyz@google.com>. + +For #48797 +Fixes #48799 +Fixes CVE-2021-38297 + +Change-Id: I0f50fbb2a5b6d0d047e3c134a88988d9133e4ab3 +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1205933 +Reviewed-by: Roland Shoemaker <bracewell@google.com> +Reviewed-by: Than McIntosh <thanm@google.com> +Reviewed-on: https://go-review.googlesource.com/c/go/+/354591 +Trust: Michael Knyszek <mknyszek@google.com> +Reviewed-by: Heschi Kreinick <heschi@google.com> + +CVE: CVE-2021-38297 + +Upstream-Status: Backport: +https://github.com/golang/go/commit/4548fcc8dfd933c237f29bba6f90040a85922564 + +Inline of ctxt.isWAsm followin this implemetation: +https://github.com/golang/go/blob/4548fcc8dfd933c237f29bba6f90040a85922564/src/cmd/link/internal/ld/target.go#L127 + +Signed-off-by: Davide Gardenal <davide.gardenal@huawei.com> +--- + misc/wasm/wasm_exec.js | 7 +++++++ + src/cmd/link/internal/ld/data.go | 11 ++++++++++- + 2 files changed, 17 insertions(+), 1 deletion(-) + +diff --git a/misc/wasm/wasm_exec.js b/misc/wasm/wasm_exec.js +index 82041e6bb901..a0a264278b1b 100644 +--- a/misc/wasm/wasm_exec.js ++++ b/misc/wasm/wasm_exec.js +@@ -564,6 +564,13 @@ + offset += 8; + }); + ++ // The linker guarantees global data starts from at least wasmMinDataAddr. ++ // Keep in sync with cmd/link/internal/ld/data.go:wasmMinDataAddr. ++ const wasmMinDataAddr = 4096 + 4096; ++ if (offset >= wasmMinDataAddr) { ++ throw new Error("command line too long"); ++ } ++ + this._inst.exports.run(argc, argv); + if (this.exited) { + this._resolveExitPromise(); +diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go +index 52035e96301c..54a1d188cdb9 100644 +--- a/src/cmd/link/internal/ld/data.go ++++ b/src/cmd/link/internal/ld/data.go +@@ -2330,6 +2330,11 @@ func assignAddress(ctxt *Link, sect *sym.Section, n int, s loader.Sym, va uint64 + return sect, n, va + } + ++// On Wasm, we reserve 4096 bytes for zero page, then 4096 bytes for wasm_exec.js ++// to store command line args. Data sections starts from at least address 8192. ++// Keep in sync with wasm_exec.js. ++const wasmMinDataAddr = 4096 + 4096 ++ + // address assigns virtual addresses to all segments and sections and + // returns all segments in file order. + func (ctxt *Link) address() []*sym.Segment { +@@ -2339,10 +2344,14 @@ func (ctxt *Link) address() []*sym.Segment { + order = append(order, &Segtext) + Segtext.Rwx = 05 + Segtext.Vaddr = va +- for _, s := range Segtext.Sections { ++ for i, s := range Segtext.Sections { + va = uint64(Rnd(int64(va), int64(s.Align))) + s.Vaddr = va + va += s.Length ++ ++ if ctxt.Arch.Family == sys.Wasm && i == 0 && va < wasmMinDataAddr { ++ va = wasmMinDataAddr ++ } + } + + Segtext.Length = va - uint64(*FlagTextAddr) +
\ No newline at end of file diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2021-39293.patch b/meta/recipes-devtools/go/go-1.14/CVE-2021-39293.patch new file mode 100644 index 0000000000..88fca9cad9 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2021-39293.patch @@ -0,0 +1,79 @@ +From 6c480017ae600b2c90a264a922e041df04dfa785 Mon Sep 17 00:00:00 2001 +From: Roland Shoemaker <roland@golang.org> +Date: Wed, 18 Aug 2021 11:49:29 -0700 +Subject: [PATCH] [release-branch.go1.16] archive/zip: prevent preallocation + check from overflowing + +If the indicated directory size in the archive header is so large that +subtracting it from the archive size overflows a uint64, the check that +the indicated number of files in the archive can be effectively +bypassed. Prevent this from happening by checking that the indicated +directory size is less than the size of the archive. + +Thanks to the OSS-Fuzz project for discovering this issue and to +Emmanuel Odeke for reporting it. + +Fixes #47985 +Updates #47801 +Fixes CVE-2021-39293 + +Change-Id: Ifade26b98a40f3b37398ca86bd5252d12394dd24 +Reviewed-on: https://go-review.googlesource.com/c/go/+/343434 +Trust: Roland Shoemaker <roland@golang.org> +Run-TryBot: Roland Shoemaker <roland@golang.org> +TryBot-Result: Go Bot <gobot@golang.org> +Reviewed-by: Russ Cox <rsc@golang.org> +(cherry picked from commit bacbc33439b124ffd7392c91a5f5d96eca8c0c0b) +Reviewed-on: https://go-review.googlesource.com/c/go/+/345409 +Reviewed-by: Emmanuel Odeke <emmanuel@orijtech.com> +Run-TryBot: Emmanuel Odeke <emmanuel@orijtech.com> +Trust: Cherry Mui <cherryyz@google.com> + +https://github.com/golang/go/commit/6c480017ae600b2c90a264a922e041df04dfa785 +CVE: CVE-2021-39293 +Upstream-Status: Backport +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> +--- + src/archive/zip/reader.go | 2 +- + src/archive/zip/reader_test.go | 18 ++++++++++++++++++ + 2 files changed, 19 insertions(+), 1 deletion(-) + +diff --git a/src/archive/zip/reader.go b/src/archive/zip/reader.go +index ddef2b7b5a517..801d1313b6c32 100644 +--- a/src/archive/zip/reader.go ++++ b/src/archive/zip/reader.go +@@ -105,7 +105,7 @@ func (z *Reader) init(r io.ReaderAt, size int64) error { + // indicate it contains up to 1 << 128 - 1 files. Since each file has a + // header which will be _at least_ 30 bytes we can safely preallocate + // if (data size / 30) >= end.directoryRecords. +- if (uint64(size)-end.directorySize)/30 >= end.directoryRecords { ++ if end.directorySize < uint64(size) && (uint64(size)-end.directorySize)/30 >= end.directoryRecords { + z.File = make([]*File, 0, end.directoryRecords) + } + z.Comment = end.comment +diff --git a/src/archive/zip/reader_test.go b/src/archive/zip/reader_test.go +index 471be27bb1004..99f13345d8d06 100644 +--- a/src/archive/zip/reader_test.go ++++ b/src/archive/zip/reader_test.go +@@ -1225,3 +1225,21 @@ func TestCVE202133196(t *testing.T) { + t.Errorf("Archive has unexpected number of files, got %d, want 5", len(r.File)) + } + } ++ ++func TestCVE202139293(t *testing.T) { ++ // directory size is so large, that the check in Reader.init ++ // overflows when subtracting from the archive size, causing ++ // the pre-allocation check to be bypassed. ++ data := []byte{ ++ 0x50, 0x4b, 0x06, 0x06, 0x05, 0x06, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x4b, ++ 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ++ 0x00, 0x00, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x4b, ++ 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ++ 0x00, 0x00, 0x00, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, ++ 0xff, 0x50, 0xfe, 0x00, 0xff, 0x00, 0x3a, 0x00, 0x00, 0x00, 0xff, ++ } ++ _, err := NewReader(bytes.NewReader(data), int64(len(data))) ++ if err != ErrFormat { ++ t.Fatalf("unexpected error, got: %v, want: %v", err, ErrFormat) ++ } ++} diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2021-41771.patch b/meta/recipes-devtools/go/go-1.14/CVE-2021-41771.patch new file mode 100644 index 0000000000..526796dbcb --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2021-41771.patch @@ -0,0 +1,86 @@ +From d19c5bdb24e093a2d5097b7623284eb02726cede Mon Sep 17 00:00:00 2001 +From: Roland Shoemaker <roland@golang.org> +Date: Thu, 14 Oct 2021 13:02:01 -0700 +Subject: [PATCH] [release-branch.go1.16] debug/macho: fail on invalid dynamic + symbol table command +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fail out when loading a file that contains a dynamic symbol table +command that indicates a larger number of symbols than exist in the +loaded symbol table. + +Thanks to Burak Çarıkçı - Yunus Yıldırım (CT-Zer0 Crypttech) for +reporting this issue. + +Updates #48990 +Fixes #48991 +Fixes CVE-2021-41771 + +Change-Id: Ic3d6e6529241afcc959544b326b21b663262bad5 +Reviewed-on: https://go-review.googlesource.com/c/go/+/355990 +Reviewed-by: Julie Qiu <julie@golang.org> +Reviewed-by: Katie Hockman <katie@golang.org> +Reviewed-by: Emmanuel Odeke <emmanuel@orijtech.com> +Run-TryBot: Roland Shoemaker <roland@golang.org> +TryBot-Result: Go Bot <gobot@golang.org> +Trust: Katie Hockman <katie@golang.org> +(cherry picked from commit 61536ec03063b4951163bd09609c86d82631fa27) +Reviewed-on: https://go-review.googlesource.com/c/go/+/359454 +Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org> + +https://github.com/golang/go/commit/d19c5bdb24e093a2d5097b7623284eb02726cede +CVE: CVE-2021-41771 +Upstream-Status: Backport +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> +--- + src/debug/macho/file.go | 9 +++++++++ + src/debug/macho/file_test.go | 7 +++++++ + .../testdata/gcc-amd64-darwin-exec-with-bad-dysym.base64 | 1 + + 3 files changed, 17 insertions(+) + create mode 100644 src/debug/macho/testdata/gcc-amd64-darwin-exec-with-bad-dysym.base64 + +diff --git a/src/debug/macho/file.go b/src/debug/macho/file.go +index 085b0c8219bad..73cfce3c7606e 100644 +--- a/src/debug/macho/file.go ++++ b/src/debug/macho/file.go +@@ -345,6 +345,15 @@ func NewFile(r io.ReaderAt) (*File, error) { + if err := binary.Read(b, bo, &hdr); err != nil { + return nil, err + } ++ if hdr.Iundefsym > uint32(len(f.Symtab.Syms)) { ++ return nil, &FormatError{offset, fmt.Sprintf( ++ "undefined symbols index in dynamic symbol table command is greater than symbol table length (%d > %d)", ++ hdr.Iundefsym, len(f.Symtab.Syms)), nil} ++ } else if hdr.Iundefsym+hdr.Nundefsym > uint32(len(f.Symtab.Syms)) { ++ return nil, &FormatError{offset, fmt.Sprintf( ++ "number of undefined symbols after index in dynamic symbol table command is greater than symbol table length (%d > %d)", ++ hdr.Iundefsym+hdr.Nundefsym, len(f.Symtab.Syms)), nil} ++ } + dat := make([]byte, hdr.Nindirectsyms*4) + if _, err := r.ReadAt(dat, int64(hdr.Indirectsymoff)); err != nil { + return nil, err +diff --git a/src/debug/macho/file_test.go b/src/debug/macho/file_test.go +index 03915c86e23d9..9beeb80dd27c1 100644 +--- a/src/debug/macho/file_test.go ++++ b/src/debug/macho/file_test.go +@@ -416,3 +416,10 @@ func TestTypeString(t *testing.T) { + t.Errorf("got %v, want %v", TypeExec.GoString(), "macho.Exec") + } + } ++ ++func TestOpenBadDysymCmd(t *testing.T) { ++ _, err := openObscured("testdata/gcc-amd64-darwin-exec-with-bad-dysym.base64") ++ if err == nil { ++ t.Fatal("openObscured did not fail when opening a file with an invalid dynamic symbol table command") ++ } ++} +diff --git a/src/debug/macho/testdata/gcc-amd64-darwin-exec-with-bad-dysym.base64 b/src/debug/macho/testdata/gcc-amd64-darwin-exec-with-bad-dysym.base64 +new file mode 100644 +index 0000000000000..8e0436639c109 +--- /dev/null ++++ b/src/debug/macho/testdata/gcc-amd64-darwin-exec-with-bad-dysym.base64 +@@ -0,0 +1 @@ ++z/rt/gcAAAEDAACAAgAAAAsAAABoBQAAhQAAAAAAAAAZAAAASAAAAF9fUEFHRVpFUk8AAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAA2AEAAF9fVEVYVAAAAAAAAAAAAAAAAAAAAQAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAcAAAAFAAAABQAAAAAAAABfX3RleHQAAAAAAAAAAAAAX19URVhUAAAAAAAAAAAAABQPAAABAAAAbQAAAAAAAAAUDwAAAgAAAAAAAAAAAAAAAAQAgAAAAAAAAAAAAAAAAF9fc3ltYm9sX3N0dWIxAABfX1RFWFQAAAAAAAAAAAAAgQ8AAAEAAAAMAAAAAAAAAIEPAAAAAAAAAAAAAAAAAAAIBACAAAAAAAYAAAAAAAAAX19zdHViX2hlbHBlcgAAAF9fVEVYVAAAAAAAAAAAAACQDwAAAQAAABgAAAAAAAAAkA8AAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABfX2NzdHJpbmcAAAAAAAAAX19URVhUAAAAAAAAAAAAAKgPAAABAAAADQAAAAAAAACoDwAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAF9fZWhfZnJhbWUAAAAAAABfX1RFWFQAAAAAAAAAAAAAuA8AAAEAAABIAAAAAAAAALgPAAADAAAAAAAAAAAAAAALAABgAAAAAAAAAAAAAAAAGQAAADgBAABfX0RBVEEAAAAAAAAAAAAAABAAAAEAAAAAEAAAAAAAAAAQAAAAAAAAABAAAAAAAAAHAAAAAwAAAAMAAAAAAAAAX19kYXRhAAAAAAAAAAAAAF9fREFUQQAAAAAAAAAAAAAAEAAAAQAAABwAAAAAAAAAABAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABfX2R5bGQAAAAAAAAAAAAAX19EQVRBAAAAAAAAAAAAACAQAAABAAAAOAAAAAAAAAAgEAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF9fbGFfc3ltYm9sX3B0cgBfX0RBVEEAAAAAAAAAAAAAWBAAAAEAAAAQAAAAAAAAAFgQAAACAAAAAAAAAAAAAAAHAAAAAgAAAAAAAAAAAAAAGQAAAEgAAABfX0xJTktFRElUAAAAAAAAACAAAAEAAAAAEAAAAAAAAAAgAAAAAAAAQAEAAAAAAAAHAAAAAQAAAAAAAAAAAAAAAgAAABgAAAAAIAAACwAAAMAgAACAAAAACwAAAFAAAAAAAAAAAgAAAAIAAAAHAAAACQAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwIAAABAAAAAAAAAAAAAAAAAAAAAAAAAAOAAAAIAAAAAwAAAAvdXNyL2xpYi9keWxkAAAAAAAAABsAAAAYAAAAOyS4cg5FdtQoqu6JsMEhXQUAAAC4AAAABAAAACoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQPAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAOAAAABgAAAACAAAAAAABAAAAAQAvdXNyL2xpYi9saWJnY2Nfcy4xLmR5bGliAAAAAAAAAAwAAAA4AAAAGAAAAAIAAAAEAW8AAAABAC91c3IvbGliL2xpYlN5c3RlbS5CLmR5bGliAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABqAEiJ5UiD5PBIi30ISI11EIn6g8IBweIDSAHySInR6wRIg8EISIM5AHX2SIPBCOgiAAAAicfoMgAAAPRBU0yNHafw//9BU/8lvwAAAA8fAP8lvgAAAFVIieVIjT0zAAAA6A0AAAC4AAAAAMnD/yXRAAAA/yXTAAAAAAAATI0dwQAAAOm0////TI0dvQAAAOmo////aGVsbG8sIHdvcmxkAAAAABQAAAAAAAAAAXpSAAF4EAEQDAcIkAEAACwAAAAcAAAAkv////////8XAAAAAAAAAAAEAQAAAA4QhgIEAwAAAA0GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABDAX/9/AAAIEMBf/38AAAAAAAABAAAAGBAAAAEAAAAQEAAAAQAAAAgQAAABAAAAABAAAAEAAACQDwAAAQAAAJwPAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAHgEAAFAPAAABAAAAGwAAAB4BAABkDwAAAQAAAC4AAAAPBgAAGBAAAAEAAAA2AAAADwYAABAQAAABAAAAPgAAAA8GAAAAEAAAAQAAAEoAAAADABAAAAAAAAEAAABeAAAADwYAAAgQAAABAAAAZwAAAA8BAABqDwAAAQAAAG0AAAAPAQAAFA8AAAEAAABzAAAAAQABAgAAAAAAAAAAeQAAAAEAAQIAAAAAAAAAAAkAAAAKAAAACQAAAAoAAAAgAGR5bGRfc3R1Yl9iaW5kaW5nX2hlbHBlcgBfX2R5bGRfZnVuY19sb29rdXAAX05YQXJnYwBfTlhBcmd2AF9fX3Byb2duYW1lAF9fbWhfZXhlY3V0ZV9oZWFkZXIAX2Vudmlyb24AX21haW4Ac3RhcnQAX2V4aXQAX3B1dHMAAA== +\ No newline at end of file diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2021-44716.patch b/meta/recipes-devtools/go/go-1.14/CVE-2021-44716.patch new file mode 100644 index 0000000000..9c4fee2db4 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2021-44716.patch @@ -0,0 +1,93 @@ +From 9f1860075990e7bf908ca7cc329d1d3ef91741c8 Mon Sep 17 00:00:00 2001 +From: Filippo Valsorda <filippo@golang.org> +Date: Thu, 9 Dec 2021 06:13:31 -0500 +Subject: [PATCH] net/http: update bundled golang.org/x/net/http2 + +Upstream-Status: Backport [https://github.com/golang/go/commit/d0aebe3e74fe14799f97ddd3f01129697c6a290a] +CVE: CVE-2021-44716 +Signed-off-by: Ralph Siemsen <ralph.siemsen@linaro.org> + + +Pull in security fix + + a5309b3 http2: cap the size of the server's canonical header cache + +Updates #50058 +Fixes CVE-2021-44716 + +Change-Id: Ifdd13f97fce168de5fb4b2e74ef2060d059800b9 +Reviewed-on: https://go-review.googlesource.com/c/go/+/370575 +Trust: Filippo Valsorda <filippo@golang.org> +Run-TryBot: Filippo Valsorda <filippo@golang.org> +Reviewed-by: Alex Rakoczy <alex@golang.org> +TryBot-Result: Gopher Robot <gobot@golang.org> +(cherry picked from commit d0aebe3e74fe14799f97ddd3f01129697c6a290a) +--- + src/go.mod | 2 +- + src/go.sum | 4 ++-- + src/net/http/h2_bundle.go | 10 +++++++++- + src/vendor/modules.txt | 2 +- + 4 files changed, 13 insertions(+), 5 deletions(-) + +diff --git a/src/go.mod b/src/go.mod +index ec6bd98..56f2fbb 100644 +--- a/src/go.mod ++++ b/src/go.mod +@@ -4,7 +4,7 @@ go 1.14 + + require ( + golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d +- golang.org/x/net v0.0.0-20210129194117-4acb7895a057 ++ golang.org/x/net v0.0.0-20211209100217-a5309b321dca + golang.org/x/sys v0.0.0-20200201011859-915c9c3d4ccf // indirect + golang.org/x/text v0.3.3-0.20191031172631-4b67af870c6f // indirect + ) +diff --git a/src/go.sum b/src/go.sum +index 171e083..1ceba05 100644 +--- a/src/go.sum ++++ b/src/go.sum +@@ -2,8 +2,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk + golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d h1:9FCpayM9Egr1baVnV1SX0H87m+XB0B8S0hAMi99X/3U= + golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= + golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +-golang.org/x/net v0.0.0-20210129194117-4acb7895a057 h1:HThQeV5c0Ab/Puir+q6mC97b7+3dfZdsLWMLoBrzo68= +-golang.org/x/net v0.0.0-20210129194117-4acb7895a057/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= ++golang.org/x/net v0.0.0-20211209100217-a5309b321dca h1:UmeWAm8AwB6NA/e4FSaGlK1EKTLXKX3utx4Si+6kfPg= ++golang.org/x/net v0.0.0-20211209100217-a5309b321dca/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= + golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= + golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= + golang.org/x/sys v0.0.0-20200201011859-915c9c3d4ccf h1:+4j7oujXP478CVb/AFvHJmVX5+Pczx2NGts5yirA0oY= +diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go +index 702fd5a..83f2a72 100644 +--- a/src/net/http/h2_bundle.go ++++ b/src/net/http/h2_bundle.go +@@ -4293,7 +4293,15 @@ func (sc *http2serverConn) canonicalHeader(v string) string { + sc.canonHeader = make(map[string]string) + } + cv = CanonicalHeaderKey(v) +- sc.canonHeader[v] = cv ++ // maxCachedCanonicalHeaders is an arbitrarily-chosen limit on the number of ++ // entries in the canonHeader cache. This should be larger than the number ++ // of unique, uncommon header keys likely to be sent by the peer, while not ++ // so high as to permit unreaasonable memory usage if the peer sends an unbounded ++ // number of unique header keys. ++ const maxCachedCanonicalHeaders = 32 ++ if len(sc.canonHeader) < maxCachedCanonicalHeaders { ++ sc.canonHeader[v] = cv ++ } + return cv + } + +diff --git a/src/vendor/modules.txt b/src/vendor/modules.txt +index 669bd9b..1d67183 100644 +--- a/src/vendor/modules.txt ++++ b/src/vendor/modules.txt +@@ -8,7 +8,7 @@ golang.org/x/crypto/curve25519 + golang.org/x/crypto/hkdf + golang.org/x/crypto/internal/subtle + golang.org/x/crypto/poly1305 +-# golang.org/x/net v0.0.0-20210129194117-4acb7895a057 ++# golang.org/x/net v0.0.0-20211209100217-a5309b321dca + ## explicit + golang.org/x/net/dns/dnsmessage + golang.org/x/net/http/httpguts diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2021-44717.patch b/meta/recipes-devtools/go/go-1.14/CVE-2021-44717.patch new file mode 100644 index 0000000000..17cac7a5ba --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2021-44717.patch @@ -0,0 +1,83 @@ +From 9171c664e7af479aa26bc72f2e7cf4e69d8e0a6f Mon Sep 17 00:00:00 2001 +From: Hitendra Prajapati <hprajapati@mvista.com> +Date: Fri, 17 Jun 2022 10:22:47 +0530 +Subject: [PATCH] CVE-2021-44717 + +Upstream-Status: Backport [https://github.com/golang/go/commit/44a3fb49] +CVE: CVE-2021-44717 +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> + +syscall: fix ForkLock spurious close(0) on pipe failure +Pipe (and therefore forkLockPipe) does not make any guarantees +about the state of p after a failed Pipe(p). Avoid that assumption +and the too-clever goto, so that we don't accidentally Close a real fd +if the failed pipe leaves p[0] or p[1] set >= 0. + +Updates #50057 +Fixes CVE-2021-44717 + +Change-Id: Iff8e19a6efbba0c73cc8b13ecfae381c87600bb4 +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1291270 +Reviewed-by: Ian Lance Taylor <iant@google.com> +Reviewed-on: https://go-review.googlesource.com/c/go/+/370514 +Trust: Filippo Valsorda <filippo@golang.org> +Run-TryBot: Filippo Valsorda <filippo@golang.org> +TryBot-Result: Gopher Robot <gobot@golang.org> +Reviewed-by: Alex Rakoczy <alex@golang.org> +--- + src/syscall/exec_unix.go | 20 ++++++-------------- + 1 file changed, 6 insertions(+), 14 deletions(-) + +diff --git a/src/syscall/exec_unix.go b/src/syscall/exec_unix.go +index b3798b6..b73782c 100644 +--- a/src/syscall/exec_unix.go ++++ b/src/syscall/exec_unix.go +@@ -151,9 +151,6 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) + sys = &zeroSysProcAttr + } + +- p[0] = -1 +- p[1] = -1 +- + // Convert args to C form. + argv0p, err := BytePtrFromString(argv0) + if err != nil { +@@ -194,14 +191,17 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) + + // Allocate child status pipe close on exec. + if err = forkExecPipe(p[:]); err != nil { +- goto error ++ ForkLock.Unlock() ++ return 0, err + } + + // Kick off child. + pid, err1 = forkAndExecInChild(argv0p, argvp, envvp, chroot, dir, attr, sys, p[1]) + if err1 != 0 { +- err = Errno(err1) +- goto error ++ Close(p[0]) ++ Close(p[1]) ++ ForkLock.Unlock() ++ return 0, Errno(err1) + } + ForkLock.Unlock() + +@@ -228,14 +228,6 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) + + // Read got EOF, so pipe closed on exec, so exec succeeded. + return pid, nil +- +-error: +- if p[0] >= 0 { +- Close(p[0]) +- Close(p[1]) +- } +- ForkLock.Unlock() +- return 0, err + } + + // Combination of fork and exec, careful to be thread safe. +-- +2.25.1 + diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2022-1962.patch b/meta/recipes-devtools/go/go-1.14/CVE-2022-1962.patch new file mode 100644 index 0000000000..b2ab5d0669 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2022-1962.patch @@ -0,0 +1,357 @@ +From ba8788ebcead55e99e631c6a1157ad7b35535d11 Mon Sep 17 00:00:00 2001 +From: Roland Shoemaker <bracewell@google.com> +Date: Wed, 15 Jun 2022 10:43:05 -0700 +Subject: [PATCH] [release-branch.go1.17] go/parser: limit recursion depth + +Limit nested parsing to 100,000, which prevents stack exhaustion when +parsing deeply nested statements, types, and expressions. Also limit +the scope depth to 1,000 during object resolution. + +Thanks to Juho Nurminen of Mattermost for reporting this issue. + +Fixes #53707 +Updates #53616 +Fixes CVE-2022-1962 + +Change-Id: I4d7b86c1d75d0bf3c7af1fdea91582aa74272c64 +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1491025 +Reviewed-by: Russ Cox <rsc@google.com> +Reviewed-by: Damien Neil <dneil@google.com> +(cherry picked from commit 6a856f08d58e4b6705c0c337d461c540c1235c83) +Reviewed-on: https://go-review.googlesource.com/c/go/+/417070 +Reviewed-by: Heschi Kreinick <heschi@google.com> +TryBot-Result: Gopher Robot <gobot@golang.org> +Run-TryBot: Michael Knyszek <mknyszek@google.com> + +Upstream-Status: Backport [https://github.com/golang/go/commit/ba8788ebcead55e99e631c6a1157ad7b35535d11] +CVE: CVE-2022-1962 +Signed-off-by: Vivek Kumbhar <vkumbhar@mvista.com> +--- + src/go/parser/interface.go | 10 ++- + src/go/parser/parser.go | 48 ++++++++-- + src/go/parser/parser_test.go | 169 +++++++++++++++++++++++++++++++++++ + 3 files changed, 220 insertions(+), 7 deletions(-) + +diff --git a/src/go/parser/interface.go b/src/go/parser/interface.go +index 54f9d7b..537b327 100644 +--- a/src/go/parser/interface.go ++++ b/src/go/parser/interface.go +@@ -92,8 +92,11 @@ func ParseFile(fset *token.FileSet, filename string, src interface{}, mode Mode) + defer func() { + if e := recover(); e != nil { + // resume same panic if it's not a bailout +- if _, ok := e.(bailout); !ok { ++ bail, ok := e.(bailout) ++ if !ok { + panic(e) ++ } else if bail.msg != "" { ++ p.errors.Add(p.file.Position(bail.pos), bail.msg) + } + } + +@@ -188,8 +191,11 @@ func ParseExprFrom(fset *token.FileSet, filename string, src interface{}, mode M + defer func() { + if e := recover(); e != nil { + // resume same panic if it's not a bailout +- if _, ok := e.(bailout); !ok { ++ bail, ok := e.(bailout) ++ if !ok { + panic(e) ++ } else if bail.msg != "" { ++ p.errors.Add(p.file.Position(bail.pos), bail.msg) + } + } + p.errors.Sort() +diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go +index 31a7398..586fe90 100644 +--- a/src/go/parser/parser.go ++++ b/src/go/parser/parser.go +@@ -64,6 +64,10 @@ type parser struct { + unresolved []*ast.Ident // unresolved identifiers + imports []*ast.ImportSpec // list of imports + ++ // nestLev is used to track and limit the recursion depth ++ // during parsing. ++ nestLev int ++ + // Label scopes + // (maintained by open/close LabelScope) + labelScope *ast.Scope // label scope for current function +@@ -236,6 +240,24 @@ func un(p *parser) { + p.printTrace(")") + } + ++// maxNestLev is the deepest we're willing to recurse during parsing ++const maxNestLev int = 1e5 ++ ++func incNestLev(p *parser) *parser { ++ p.nestLev++ ++ if p.nestLev > maxNestLev { ++ p.error(p.pos, "exceeded max nesting depth") ++ panic(bailout{}) ++ } ++ return p ++} ++ ++// decNestLev is used to track nesting depth during parsing to prevent stack exhaustion. ++// It is used along with incNestLev in a similar fashion to how un and trace are used. ++func decNestLev(p *parser) { ++ p.nestLev-- ++} ++ + // Advance to the next token. + func (p *parser) next0() { + // Because of one-token look-ahead, print the previous token +@@ -348,8 +370,12 @@ func (p *parser) next() { + } + } + +-// A bailout panic is raised to indicate early termination. +-type bailout struct{} ++// A bailout panic is raised to indicate early termination. pos and msg are ++// only populated when bailing out of object resolution. ++type bailout struct { ++ pos token.Pos ++ msg string ++} + + func (p *parser) error(pos token.Pos, msg string) { + epos := p.file.Position(pos) +@@ -1030,6 +1056,8 @@ func (p *parser) parseChanType() *ast.ChanType { + + // If the result is an identifier, it is not resolved. + func (p *parser) tryIdentOrType() ast.Expr { ++ defer decNestLev(incNestLev(p)) ++ + switch p.tok { + case token.IDENT: + return p.parseTypeName() +@@ -1609,7 +1637,13 @@ func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr { + } + + x := p.parseUnaryExpr(lhs) +- for { ++ // We track the nesting here rather than at the entry for the function, ++ // since it can iteratively produce a nested output, and we want to ++ // limit how deep a structure we generate. ++ var n int ++ defer func() { p.nestLev -= n }() ++ for n = 1; ; n++ { ++ incNestLev(p) + op, oprec := p.tokPrec() + if oprec < prec1 { + return x +@@ -1628,7 +1662,7 @@ func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr { + // The result may be a type or even a raw type ([...]int). Callers must + // check the result (using checkExpr or checkExprOrType), depending on + // context. +-func (p *parser) parseExpr(lhs bool) ast.Expr { ++func (p *parser) parseExpr(lhs bool) ast.Expr { + if p.trace { + defer un(trace(p, "Expression")) + } +@@ -1899,6 +1933,8 @@ func (p *parser) parseIfHeader() (init ast.Stmt, cond ast.Expr) { + } + + func (p *parser) parseIfStmt() *ast.IfStmt { ++ defer decNestLev(incNestLev(p)) ++ + if p.trace { + defer un(trace(p, "IfStmt")) + } +@@ -2214,6 +2250,8 @@ func (p *parser) parseForStmt() ast.Stmt { + } + + func (p *parser) parseStmt() (s ast.Stmt) { ++ defer decNestLev(incNestLev(p)) ++ + if p.trace { + defer un(trace(p, "Statement")) + } +diff --git a/src/go/parser/parser_test.go b/src/go/parser/parser_test.go +index 25a374e..37a6a2b 100644 +--- a/src/go/parser/parser_test.go ++++ b/src/go/parser/parser_test.go +@@ -10,6 +10,7 @@ import ( + "go/ast" + "go/token" + "os" ++ "runtime" + "strings" + "testing" + ) +@@ -569,3 +570,171 @@ type x int // comment + t.Errorf("got %q, want %q", comment, "// comment") + } + } ++ ++var parseDepthTests = []struct { ++ name string ++ format string ++ // multipler is used when a single statement may result in more than one ++ // change in the depth level, for instance "1+(..." produces a BinaryExpr ++ // followed by a UnaryExpr, which increments the depth twice. The test ++ // case comment explains which nodes are triggering the multiple depth ++ // changes. ++ parseMultiplier int ++ // scope is true if we should also test the statement for the resolver scope ++ // depth limit. ++ scope bool ++ // scopeMultiplier does the same as parseMultiplier, but for the scope ++ // depths. ++ scopeMultiplier int ++}{ ++ // The format expands the part inside « » many times. ++ // A second set of brackets nested inside the first stops the repetition, ++ // so that for example «(«1»)» expands to (((...((((1))))...))). ++ {name: "array", format: "package main; var x «[1]»int"}, ++ {name: "slice", format: "package main; var x «[]»int"}, ++ {name: "struct", format: "package main; var x «struct { X «int» }»", scope: true}, ++ {name: "pointer", format: "package main; var x «*»int"}, ++ {name: "func", format: "package main; var x «func()»int", scope: true}, ++ {name: "chan", format: "package main; var x «chan »int"}, ++ {name: "chan2", format: "package main; var x «<-chan »int"}, ++ {name: "interface", format: "package main; var x «interface { M() «int» }»", scope: true, scopeMultiplier: 2}, // Scopes: InterfaceType, FuncType ++ {name: "map", format: "package main; var x «map[int]»int"}, ++ {name: "slicelit", format: "package main; var x = «[]any{«»}»", parseMultiplier: 2}, // Parser nodes: UnaryExpr, CompositeLit ++ {name: "arraylit", format: "package main; var x = «[1]any{«nil»}»", parseMultiplier: 2}, // Parser nodes: UnaryExpr, CompositeLit ++ {name: "structlit", format: "package main; var x = «struct{x any}{«nil»}»", parseMultiplier: 2}, // Parser nodes: UnaryExpr, CompositeLit ++ {name: "maplit", format: "package main; var x = «map[int]any{1:«nil»}»", parseMultiplier: 2}, // Parser nodes: CompositeLit, KeyValueExpr ++ {name: "dot", format: "package main; var x = «x.»x"}, ++ {name: "index", format: "package main; var x = x«[1]»"}, ++ {name: "slice", format: "package main; var x = x«[1:2]»"}, ++ {name: "slice3", format: "package main; var x = x«[1:2:3]»"}, ++ {name: "dottype", format: "package main; var x = x«.(any)»"}, ++ {name: "callseq", format: "package main; var x = x«()»"}, ++ {name: "methseq", format: "package main; var x = x«.m()»", parseMultiplier: 2}, // Parser nodes: SelectorExpr, CallExpr ++ {name: "binary", format: "package main; var x = «1+»1"}, ++ {name: "binaryparen", format: "package main; var x = «1+(«1»)»", parseMultiplier: 2}, // Parser nodes: BinaryExpr, ParenExpr ++ {name: "unary", format: "package main; var x = «^»1"}, ++ {name: "addr", format: "package main; var x = «& »x"}, ++ {name: "star", format: "package main; var x = «*»x"}, ++ {name: "recv", format: "package main; var x = «<-»x"}, ++ {name: "call", format: "package main; var x = «f(«1»)»", parseMultiplier: 2}, // Parser nodes: Ident, CallExpr ++ {name: "conv", format: "package main; var x = «(*T)(«1»)»", parseMultiplier: 2}, // Parser nodes: ParenExpr, CallExpr ++ {name: "label", format: "package main; func main() { «Label:» }"}, ++ {name: "if", format: "package main; func main() { «if true { «» }»}", parseMultiplier: 2, scope: true, scopeMultiplier: 2}, // Parser nodes: IfStmt, BlockStmt. Scopes: IfStmt, BlockStmt ++ {name: "ifelse", format: "package main; func main() { «if true {} else » {} }", scope: true}, ++ {name: "switch", format: "package main; func main() { «switch { default: «» }»}", scope: true, scopeMultiplier: 2}, // Scopes: TypeSwitchStmt, CaseClause ++ {name: "typeswitch", format: "package main; func main() { «switch x.(type) { default: «» }» }", scope: true, scopeMultiplier: 2}, // Scopes: TypeSwitchStmt, CaseClause ++ {name: "for0", format: "package main; func main() { «for { «» }» }", scope: true, scopeMultiplier: 2}, // Scopes: ForStmt, BlockStmt ++ {name: "for1", format: "package main; func main() { «for x { «» }» }", scope: true, scopeMultiplier: 2}, // Scopes: ForStmt, BlockStmt ++ {name: "for3", format: "package main; func main() { «for f(); g(); h() { «» }» }", scope: true, scopeMultiplier: 2}, // Scopes: ForStmt, BlockStmt ++ {name: "forrange0", format: "package main; func main() { «for range x { «» }» }", scope: true, scopeMultiplier: 2}, // Scopes: RangeStmt, BlockStmt ++ {name: "forrange1", format: "package main; func main() { «for x = range z { «» }» }", scope: true, scopeMultiplier: 2}, // Scopes: RangeStmt, BlockStmt ++ {name: "forrange2", format: "package main; func main() { «for x, y = range z { «» }» }", scope: true, scopeMultiplier: 2}, // Scopes: RangeStmt, BlockStmt ++ {name: "go", format: "package main; func main() { «go func() { «» }()» }", parseMultiplier: 2, scope: true}, // Parser nodes: GoStmt, FuncLit ++ {name: "defer", format: "package main; func main() { «defer func() { «» }()» }", parseMultiplier: 2, scope: true}, // Parser nodes: DeferStmt, FuncLit ++ {name: "select", format: "package main; func main() { «select { default: «» }» }", scope: true}, ++} ++ ++// split splits pre«mid»post into pre, mid, post. ++// If the string does not have that form, split returns x, "", "". ++func split(x string) (pre, mid, post string) { ++ start, end := strings.Index(x, "«"), strings.LastIndex(x, "»") ++ if start < 0 || end < 0 { ++ return x, "", "" ++ } ++ return x[:start], x[start+len("«") : end], x[end+len("»"):] ++} ++ ++func TestParseDepthLimit(t *testing.T) { ++ if runtime.GOARCH == "wasm" { ++ t.Skip("causes call stack exhaustion on js/wasm") ++ } ++ for _, tt := range parseDepthTests { ++ for _, size := range []string{"small", "big"} { ++ t.Run(tt.name+"/"+size, func(t *testing.T) { ++ n := maxNestLev + 1 ++ if tt.parseMultiplier > 0 { ++ n /= tt.parseMultiplier ++ } ++ if size == "small" { ++ // Decrease the number of statements by 10, in order to check ++ // that we do not fail when under the limit. 10 is used to ++ // provide some wiggle room for cases where the surrounding ++ // scaffolding syntax adds some noise to the depth that changes ++ // on a per testcase basis. ++ n -= 10 ++ } ++ ++ pre, mid, post := split(tt.format) ++ if strings.Contains(mid, "«") { ++ left, base, right := split(mid) ++ mid = strings.Repeat(left, n) + base + strings.Repeat(right, n) ++ } else { ++ mid = strings.Repeat(mid, n) ++ } ++ input := pre + mid + post ++ ++ fset := token.NewFileSet() ++ _, err := ParseFile(fset, "", input, ParseComments|SkipObjectResolution) ++ if size == "small" { ++ if err != nil { ++ t.Errorf("ParseFile(...): %v (want success)", err) ++ } ++ } else { ++ expected := "exceeded max nesting depth" ++ if err == nil || !strings.HasSuffix(err.Error(), expected) { ++ t.Errorf("ParseFile(...) = _, %v, want %q", err, expected) ++ } ++ } ++ }) ++ } ++ } ++} ++ ++func TestScopeDepthLimit(t *testing.T) { ++ if runtime.GOARCH == "wasm" { ++ t.Skip("causes call stack exhaustion on js/wasm") ++ } ++ for _, tt := range parseDepthTests { ++ if !tt.scope { ++ continue ++ } ++ for _, size := range []string{"small", "big"} { ++ t.Run(tt.name+"/"+size, func(t *testing.T) { ++ n := maxScopeDepth + 1 ++ if tt.scopeMultiplier > 0 { ++ n /= tt.scopeMultiplier ++ } ++ if size == "small" { ++ // Decrease the number of statements by 10, in order to check ++ // that we do not fail when under the limit. 10 is used to ++ // provide some wiggle room for cases where the surrounding ++ // scaffolding syntax adds some noise to the depth that changes ++ // on a per testcase basis. ++ n -= 10 ++ } ++ ++ pre, mid, post := split(tt.format) ++ if strings.Contains(mid, "«") { ++ left, base, right := split(mid) ++ mid = strings.Repeat(left, n) + base + strings.Repeat(right, n) ++ } else { ++ mid = strings.Repeat(mid, n) ++ } ++ input := pre + mid + post ++ ++ fset := token.NewFileSet() ++ _, err := ParseFile(fset, "", input, DeclarationErrors) ++ if size == "small" { ++ if err != nil { ++ t.Errorf("ParseFile(...): %v (want success)", err) ++ } ++ } else { ++ expected := "exceeded max scope depth during object resolution" ++ if err == nil || !strings.HasSuffix(err.Error(), expected) { ++ t.Errorf("ParseFile(...) = _, %v, want %q", err, expected) ++ } ++ } ++ }) ++ } ++ } ++} +-- +2.30.2 + diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2022-23772.patch b/meta/recipes-devtools/go/go-1.14/CVE-2022-23772.patch new file mode 100644 index 0000000000..f0daee3624 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2022-23772.patch @@ -0,0 +1,50 @@ +From 70882eedccac803ddcf1c3215e0ae8fd59847e39 Mon Sep 17 00:00:00 2001 +From: Katie Hockman <katie@golang.org> +Date: Sat, 26 Feb 2022 20:03:38 +0000 +Subject: [PATCH] [release-branch.go1.16] math/big: prevent overflow in + (*Rat).SetString + +Credit to rsc@ for the original patch. + +Thanks to the OSS-Fuzz project for discovering this +issue and to Emmanuel Odeke (@odeke_et) for reporting it. + +Updates #50699 +Fixes #50700 +Fixes CVE-2022-23772 +--- + src/math/big/ratconv.go | 5 +++++ + src/math/big/ratconv_test.go | 1 + + 2 files changed, 6 insertions(+) + +diff --git a/src/math/big/ratconv.go b/src/math/big/ratconv.go +index 941139e..e8cbdbe 100644 +--- a/src/math/big/ratconv.go ++++ b/src/math/big/ratconv.go +@@ -168,6 +168,11 @@ func (z *Rat) SetString(s string) (*Rat, bool) { + n := exp5 + if n < 0 { + n = -n ++ if n < 0 { ++ // This can occur if -n overflows. -(-1 << 63) would become ++ // -1 << 63, which is still negative. ++ return nil, false ++ } + } + pow5 := z.b.abs.expNN(natFive, nat(nil).setWord(Word(n)), nil) // use underlying array of z.b.abs + if exp5 > 0 { +diff --git a/src/math/big/ratconv_test.go b/src/math/big/ratconv_test.go +index ba0d1ba..b820df4 100644 +--- a/src/math/big/ratconv_test.go ++++ b/src/math/big/ratconv_test.go +@@ -104,6 +104,7 @@ var setStringTests = []StringTest{ + {in: "4/3/"}, + {in: "4/3."}, + {in: "4/"}, ++ {in: "13e-9223372036854775808"}, // CVE-2022-23772 + + // valid + {"0", "0", true}, +-- +2.17.1 + diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2022-23806.patch b/meta/recipes-devtools/go/go-1.14/CVE-2022-23806.patch new file mode 100644 index 0000000000..772acdcbf6 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2022-23806.patch @@ -0,0 +1,142 @@ +From 5b376a209d1c61e10847e062d78c4b1aa90dff0c Mon Sep 17 00:00:00 2001 +From: Filippo Valsorda <filippo@golang.org> +Date: Sat, 26 Feb 2022 10:40:57 +0000 +Subject: [PATCH] crypto/elliptic: make IsOnCurve return false for invalid + + field elements + +Updates #50974 +Fixes #50977 +Fixes CVE-2022-23806 + +Signed-off-by: Minjae Kim <flowergom@gmail.com> + +--- + src/crypto/elliptic/elliptic.go | 6 +++ + src/crypto/elliptic/elliptic_test.go | 81 ++++++++++++++++++++++++++++ + src/crypto/elliptic/p224.go | 6 +++ + 3 files changed, 93 insertions(+) + +diff --git a/src/crypto/elliptic/elliptic.go b/src/crypto/elliptic/elliptic.go +index e2f71cd..bd574a4 100644 +--- a/src/crypto/elliptic/elliptic.go ++++ b/src/crypto/elliptic/elliptic.go +@@ -53,6 +53,12 @@ func (curve *CurveParams) Params() *CurveParams { + } + + func (curve *CurveParams) IsOnCurve(x, y *big.Int) bool { ++ ++ if x.Sign() < 0 || x.Cmp(curve.P) >= 0 || ++ y.Sign() < 0 || y.Cmp(curve.P) >= 0 { ++ return false ++ } ++ + // y² = x³ - 3x + b + y2 := new(big.Int).Mul(y, y) + y2.Mod(y2, curve.P) +diff --git a/src/crypto/elliptic/elliptic_test.go b/src/crypto/elliptic/elliptic_test.go +index 09c5483..b13a620 100644 +--- a/src/crypto/elliptic/elliptic_test.go ++++ b/src/crypto/elliptic/elliptic_test.go +@@ -628,3 +628,84 @@ func TestUnmarshalToLargeCoordinates(t *testing.T) { + t.Errorf("Unmarshal accepts invalid Y coordinate") + } + } ++ ++func testAllCurves(t *testing.T, f func(*testing.T, Curve)) { ++ tests := []struct { ++ name string ++ curve Curve ++ }{ ++ {"P256", P256()}, ++ {"P256/Params", P256().Params()}, ++ {"P224", P224()}, ++ {"P224/Params", P224().Params()}, ++ {"P384", P384()}, ++ {"P384/Params", P384().Params()}, ++ {"P521", P521()}, ++ {"P521/Params", P521().Params()}, ++ } ++ if testing.Short() { ++ tests = tests[:1] ++ } ++ for _, test := range tests { ++ curve := test.curve ++ t.Run(test.name, func(t *testing.T) { ++ t.Parallel() ++ f(t, curve) ++ }) ++ } ++} ++ ++// TestInvalidCoordinates tests big.Int values that are not valid field elements ++// (negative or bigger than P). They are expected to return false from ++// IsOnCurve, all other behavior is undefined. ++func TestInvalidCoordinates(t *testing.T) { ++ testAllCurves(t, testInvalidCoordinates) ++} ++ ++func testInvalidCoordinates(t *testing.T, curve Curve) { ++ checkIsOnCurveFalse := func(name string, x, y *big.Int) { ++ if curve.IsOnCurve(x, y) { ++ t.Errorf("IsOnCurve(%s) unexpectedly returned true", name) ++ } ++ } ++ ++ p := curve.Params().P ++ _, x, y, _ := GenerateKey(curve, rand.Reader) ++ xx, yy := new(big.Int), new(big.Int) ++ ++ // Check if the sign is getting dropped. ++ xx.Neg(x) ++ checkIsOnCurveFalse("-x, y", xx, y) ++ yy.Neg(y) ++ checkIsOnCurveFalse("x, -y", x, yy) ++ ++ // Check if negative values are reduced modulo P. ++ xx.Sub(x, p) ++ checkIsOnCurveFalse("x-P, y", xx, y) ++ yy.Sub(y, p) ++ checkIsOnCurveFalse("x, y-P", x, yy) ++ ++ // Check if positive values are reduced modulo P. ++ xx.Add(x, p) ++ checkIsOnCurveFalse("x+P, y", xx, y) ++ yy.Add(y, p) ++ checkIsOnCurveFalse("x, y+P", x, yy) ++ ++ // Check if the overflow is dropped. ++ xx.Add(x, new(big.Int).Lsh(big.NewInt(1), 535)) ++ checkIsOnCurveFalse("x+2⁵³⁵, y", xx, y) ++ yy.Add(y, new(big.Int).Lsh(big.NewInt(1), 535)) ++ checkIsOnCurveFalse("x, y+2⁵³⁵", x, yy) ++ ++ // Check if P is treated like zero (if possible). ++ // y^2 = x^3 - 3x + B ++ // y = mod_sqrt(x^3 - 3x + B) ++ // y = mod_sqrt(B) if x = 0 ++ // If there is no modsqrt, there is no point with x = 0, can't test x = P. ++ if yy := new(big.Int).ModSqrt(curve.Params().B, p); yy != nil { ++ if !curve.IsOnCurve(big.NewInt(0), yy) { ++ t.Fatal("(0, mod_sqrt(B)) is not on the curve?") ++ } ++ checkIsOnCurveFalse("P, y", p, yy) ++ } ++} +diff --git a/src/crypto/elliptic/p224.go b/src/crypto/elliptic/p224.go +index 8c76021..f1bfd7e 100644 +--- a/src/crypto/elliptic/p224.go ++++ b/src/crypto/elliptic/p224.go +@@ -48,6 +48,12 @@ func (curve p224Curve) Params() *CurveParams { + } + + func (curve p224Curve) IsOnCurve(bigX, bigY *big.Int) bool { ++ ++ if bigX.Sign() < 0 || bigX.Cmp(curve.P) >= 0 || ++ bigY.Sign() < 0 || bigY.Cmp(curve.P) >= 0 { ++ return false ++ } ++ + var x, y p224FieldElement + p224FromBig(&x, bigX) + p224FromBig(&y, bigY) diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2022-24675.patch b/meta/recipes-devtools/go/go-1.14/CVE-2022-24675.patch new file mode 100644 index 0000000000..4bc012be21 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2022-24675.patch @@ -0,0 +1,271 @@ +From 1eb931d60a24501a9668e5cb4647593e19115507 Mon Sep 17 00:00:00 2001 +From: Hitendra Prajapati <hprajapati@mvista.com> +Date: Fri, 17 Jun 2022 12:22:53 +0530 +Subject: [PATCH] CVE-2022-24675 + +Upstream-Status: Backport [https://go-review.googlesource.com/c/go/+/399816/] +CVE: CVE-2022-24675 +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> +--- + src/encoding/pem/pem.go | 174 +++++++++++++++-------------------- + src/encoding/pem/pem_test.go | 28 +++++- + 2 files changed, 101 insertions(+), 101 deletions(-) + +diff --git a/src/encoding/pem/pem.go b/src/encoding/pem/pem.go +index a7272da..1bee1c1 100644 +--- a/src/encoding/pem/pem.go ++++ b/src/encoding/pem/pem.go +@@ -87,123 +87,97 @@ func Decode(data []byte) (p *Block, rest []byte) { + // pemStart begins with a newline. However, at the very beginning of + // the byte array, we'll accept the start string without it. + rest = data +- if bytes.HasPrefix(data, pemStart[1:]) { +- rest = rest[len(pemStart)-1 : len(data)] +- } else if i := bytes.Index(data, pemStart); i >= 0 { +- rest = rest[i+len(pemStart) : len(data)] +- } else { +- return nil, data +- } +- +- typeLine, rest := getLine(rest) +- if !bytes.HasSuffix(typeLine, pemEndOfLine) { +- return decodeError(data, rest) +- } +- typeLine = typeLine[0 : len(typeLine)-len(pemEndOfLine)] +- +- p = &Block{ +- Headers: make(map[string]string), +- Type: string(typeLine), +- } +- + for { +- // This loop terminates because getLine's second result is +- // always smaller than its argument. +- if len(rest) == 0 { ++ if bytes.HasPrefix(rest, pemStart[1:]) { ++ rest = rest[len(pemStart)-1:] ++ } else if i := bytes.Index(rest, pemStart); i >= 0 { ++ rest = rest[i+len(pemStart) : len(rest)] ++ } else { + return nil, data + } +- line, next := getLine(rest) + +- i := bytes.IndexByte(line, ':') +- if i == -1 { +- break ++ var typeLine []byte ++ typeLine, rest = getLine(rest) ++ if !bytes.HasSuffix(typeLine, pemEndOfLine) { ++ continue + } ++ typeLine = typeLine[0 : len(typeLine)-len(pemEndOfLine)] + +- // TODO(agl): need to cope with values that spread across lines. +- key, val := line[:i], line[i+1:] +- key = bytes.TrimSpace(key) +- val = bytes.TrimSpace(val) +- p.Headers[string(key)] = string(val) +- rest = next +- } ++ p = &Block{ ++ Headers: make(map[string]string), ++ Type: string(typeLine), ++ } + +- var endIndex, endTrailerIndex int ++ for { ++ // This loop terminates because getLine's second result is ++ // always smaller than its argument. ++ if len(rest) == 0 { ++ return nil, data ++ } ++ line, next := getLine(rest) + +- // If there were no headers, the END line might occur +- // immediately, without a leading newline. +- if len(p.Headers) == 0 && bytes.HasPrefix(rest, pemEnd[1:]) { +- endIndex = 0 +- endTrailerIndex = len(pemEnd) - 1 +- } else { +- endIndex = bytes.Index(rest, pemEnd) +- endTrailerIndex = endIndex + len(pemEnd) +- } ++ i := bytes.IndexByte(line, ':') ++ if i == -1 { ++ break ++ } + +- if endIndex < 0 { +- return decodeError(data, rest) +- } ++ // TODO(agl): need to cope with values that spread across lines. ++ key, val := line[:i], line[i+1:] ++ key = bytes.TrimSpace(key) ++ val = bytes.TrimSpace(val) ++ p.Headers[string(key)] = string(val) ++ rest = next ++ } + +- // After the "-----" of the ending line, there should be the same type +- // and then a final five dashes. +- endTrailer := rest[endTrailerIndex:] +- endTrailerLen := len(typeLine) + len(pemEndOfLine) +- if len(endTrailer) < endTrailerLen { +- return decodeError(data, rest) +- } ++ var endIndex, endTrailerIndex int + +- restOfEndLine := endTrailer[endTrailerLen:] +- endTrailer = endTrailer[:endTrailerLen] +- if !bytes.HasPrefix(endTrailer, typeLine) || +- !bytes.HasSuffix(endTrailer, pemEndOfLine) { +- return decodeError(data, rest) +- } ++ // If there were no headers, the END line might occur ++ // immediately, without a leading newline. ++ if len(p.Headers) == 0 && bytes.HasPrefix(rest, pemEnd[1:]) { ++ endIndex = 0 ++ endTrailerIndex = len(pemEnd) - 1 ++ } else { ++ endIndex = bytes.Index(rest, pemEnd) ++ endTrailerIndex = endIndex + len(pemEnd) ++ } + +- // The line must end with only whitespace. +- if s, _ := getLine(restOfEndLine); len(s) != 0 { +- return decodeError(data, rest) +- } ++ if endIndex < 0 { ++ continue ++ } + +- base64Data := removeSpacesAndTabs(rest[:endIndex]) +- p.Bytes = make([]byte, base64.StdEncoding.DecodedLen(len(base64Data))) +- n, err := base64.StdEncoding.Decode(p.Bytes, base64Data) +- if err != nil { +- return decodeError(data, rest) +- } +- p.Bytes = p.Bytes[:n] ++ // After the "-----" of the ending line, there should be the same type ++ // and then a final five dashes. ++ endTrailer := rest[endTrailerIndex:] ++ endTrailerLen := len(typeLine) + len(pemEndOfLine) ++ if len(endTrailer) < endTrailerLen { ++ continue ++ } ++ ++ restOfEndLine := endTrailer[endTrailerLen:] ++ endTrailer = endTrailer[:endTrailerLen] ++ if !bytes.HasPrefix(endTrailer, typeLine) || ++ !bytes.HasSuffix(endTrailer, pemEndOfLine) { ++ continue ++ } + +- // the -1 is because we might have only matched pemEnd without the +- // leading newline if the PEM block was empty. +- _, rest = getLine(rest[endIndex+len(pemEnd)-1:]) ++ // The line must end with only whitespace. ++ if s, _ := getLine(restOfEndLine); len(s) != 0 { ++ continue ++ } + +- return +-} ++ base64Data := removeSpacesAndTabs(rest[:endIndex]) ++ p.Bytes = make([]byte, base64.StdEncoding.DecodedLen(len(base64Data))) ++ n, err := base64.StdEncoding.Decode(p.Bytes, base64Data) ++ if err != nil { ++ continue ++ } ++ p.Bytes = p.Bytes[:n] + +-func decodeError(data, rest []byte) (*Block, []byte) { +- // If we get here then we have rejected a likely looking, but +- // ultimately invalid PEM block. We need to start over from a new +- // position. We have consumed the preamble line and will have consumed +- // any lines which could be header lines. However, a valid preamble +- // line is not a valid header line, therefore we cannot have consumed +- // the preamble line for the any subsequent block. Thus, we will always +- // find any valid block, no matter what bytes precede it. +- // +- // For example, if the input is +- // +- // -----BEGIN MALFORMED BLOCK----- +- // junk that may look like header lines +- // or data lines, but no END line +- // +- // -----BEGIN ACTUAL BLOCK----- +- // realdata +- // -----END ACTUAL BLOCK----- +- // +- // we've failed to parse using the first BEGIN line +- // and now will try again, using the second BEGIN line. +- p, rest := Decode(rest) +- if p == nil { +- rest = data ++ // the -1 is because we might have only matched pemEnd without the ++ // leading newline if the PEM block was empty. ++ _, rest = getLine(rest[endIndex+len(pemEnd)-1:]) ++ return p, rest + } +- return p, rest + } + + const pemLineLength = 64 +diff --git a/src/encoding/pem/pem_test.go b/src/encoding/pem/pem_test.go +index 8515b46..4485581 100644 +--- a/src/encoding/pem/pem_test.go ++++ b/src/encoding/pem/pem_test.go +@@ -107,6 +107,12 @@ const pemMissingEndingSpace = ` + dGVzdA== + -----ENDBAR-----` + ++const pemMissingEndLine = ` ++-----BEGIN FOO----- ++Header: 1` ++ ++var pemRepeatingBegin = strings.Repeat("-----BEGIN \n", 10) ++ + var badPEMTests = []struct { + name string + input string +@@ -131,14 +137,34 @@ var badPEMTests = []struct { + "missing ending space", + pemMissingEndingSpace, + }, ++ { ++ "repeating begin", ++ pemRepeatingBegin, ++ }, ++ { ++ "missing end line", ++ pemMissingEndLine, ++ }, + } + + func TestBadDecode(t *testing.T) { + for _, test := range badPEMTests { +- result, _ := Decode([]byte(test.input)) ++ result, rest := Decode([]byte(test.input)) + if result != nil { + t.Errorf("unexpected success while parsing %q", test.name) + } ++ if string(rest) != test.input { ++ t.Errorf("unexpected rest: %q; want = %q", rest, test.input) ++ } ++ } ++} ++ ++func TestCVE202224675(t *testing.T) { ++ // Prior to CVE-2022-24675, this input would cause a stack overflow. ++ input := []byte(strings.Repeat("-----BEGIN \n", 10000000)) ++ result, rest := Decode(input) ++ if result != nil || !reflect.DeepEqual(rest, input) { ++ t.Errorf("Encode of %#v decoded as %#v", input, rest) + } + } + +-- +2.25.1 + diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2022-24921.patch b/meta/recipes-devtools/go/go-1.14/CVE-2022-24921.patch new file mode 100644 index 0000000000..e4270d8a75 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2022-24921.patch @@ -0,0 +1,198 @@ +From ba99f699d26483ea1045f47c760e9be30799e311 Mon Sep 17 00:00:00 2001 +From: Russ Cox <rsc@golang.org> +Date: Wed, 2 Feb 2022 16:41:32 -0500 +Subject: [PATCH] regexp/syntax: reject very deeply nested regexps in Parse +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Upstream-Status: Backport [https://github.com/golang/go/commit/2b65cde5868d8245ef8a0b8eba1e361440252d3b] +CVE: CVE-2022-24921 +Signed-off-by: Ralph Siemsen <ralph.siemsen@linaro.org + + +The regexp code assumes it can recurse over the structure of +a regexp safely. Go's growable stacks make that reasonable +for all plausible regexps, but implausible ones can reach the +“infinite recursion?” stack limit. + +This CL limits the depth of any parsed regexp to 1000. +That is, the depth of the parse tree is required to be ≤ 1000. +Regexps that require deeper parse trees will return ErrInternalError. +A future CL will change the error to ErrInvalidDepth, +but using ErrInternalError for now avoids introducing new API +in point releases when this is backported. + +Fixes #51112. +Fixes #51117. + +Change-Id: I97d2cd82195946eb43a4ea8561f5b95f91fb14c5 +Reviewed-on: https://go-review.googlesource.com/c/go/+/384616 +Trust: Russ Cox <rsc@golang.org> +Run-TryBot: Russ Cox <rsc@golang.org> +Reviewed-by: Ian Lance Taylor <iant@golang.org> +Reviewed-on: https://go-review.googlesource.com/c/go/+/384855 +--- + src/regexp/syntax/parse.go | 72 ++++++++++++++++++++++++++++++++- + src/regexp/syntax/parse_test.go | 7 ++++ + 2 files changed, 77 insertions(+), 2 deletions(-) + +diff --git a/src/regexp/syntax/parse.go b/src/regexp/syntax/parse.go +index 8c6d43a..55bd20d 100644 +--- a/src/regexp/syntax/parse.go ++++ b/src/regexp/syntax/parse.go +@@ -76,13 +76,29 @@ const ( + opVerticalBar + ) + ++// maxHeight is the maximum height of a regexp parse tree. ++// It is somewhat arbitrarily chosen, but the idea is to be large enough ++// that no one will actually hit in real use but at the same time small enough ++// that recursion on the Regexp tree will not hit the 1GB Go stack limit. ++// The maximum amount of stack for a single recursive frame is probably ++// closer to 1kB, so this could potentially be raised, but it seems unlikely ++// that people have regexps nested even this deeply. ++// We ran a test on Google's C++ code base and turned up only ++// a single use case with depth > 100; it had depth 128. ++// Using depth 1000 should be plenty of margin. ++// As an optimization, we don't even bother calculating heights ++// until we've allocated at least maxHeight Regexp structures. ++const maxHeight = 1000 ++ + type parser struct { + flags Flags // parse mode flags + stack []*Regexp // stack of parsed expressions + free *Regexp + numCap int // number of capturing groups seen + wholeRegexp string +- tmpClass []rune // temporary char class work space ++ tmpClass []rune // temporary char class work space ++ numRegexp int // number of regexps allocated ++ height map[*Regexp]int // regexp height for height limit check + } + + func (p *parser) newRegexp(op Op) *Regexp { +@@ -92,16 +108,52 @@ func (p *parser) newRegexp(op Op) *Regexp { + *re = Regexp{} + } else { + re = new(Regexp) ++ p.numRegexp++ + } + re.Op = op + return re + } + + func (p *parser) reuse(re *Regexp) { ++ if p.height != nil { ++ delete(p.height, re) ++ } + re.Sub0[0] = p.free + p.free = re + } + ++func (p *parser) checkHeight(re *Regexp) { ++ if p.numRegexp < maxHeight { ++ return ++ } ++ if p.height == nil { ++ p.height = make(map[*Regexp]int) ++ for _, re := range p.stack { ++ p.checkHeight(re) ++ } ++ } ++ if p.calcHeight(re, true) > maxHeight { ++ panic(ErrInternalError) ++ } ++} ++ ++func (p *parser) calcHeight(re *Regexp, force bool) int { ++ if !force { ++ if h, ok := p.height[re]; ok { ++ return h ++ } ++ } ++ h := 1 ++ for _, sub := range re.Sub { ++ hsub := p.calcHeight(sub, false) ++ if h < 1+hsub { ++ h = 1 + hsub ++ } ++ } ++ p.height[re] = h ++ return h ++} ++ + // Parse stack manipulation. + + // push pushes the regexp re onto the parse stack and returns the regexp. +@@ -137,6 +189,7 @@ func (p *parser) push(re *Regexp) *Regexp { + } + + p.stack = append(p.stack, re) ++ p.checkHeight(re) + return re + } + +@@ -252,6 +305,7 @@ func (p *parser) repeat(op Op, min, max int, before, after, lastRepeat string) ( + re.Sub = re.Sub0[:1] + re.Sub[0] = sub + p.stack[n-1] = re ++ p.checkHeight(re) + + if op == OpRepeat && (min >= 2 || max >= 2) && !repeatIsValid(re, 1000) { + return "", &Error{ErrInvalidRepeatSize, before[:len(before)-len(after)]} +@@ -699,6 +753,21 @@ func literalRegexp(s string, flags Flags) *Regexp { + // Flags, and returns a regular expression parse tree. The syntax is + // described in the top-level comment. + func Parse(s string, flags Flags) (*Regexp, error) { ++ return parse(s, flags) ++} ++ ++func parse(s string, flags Flags) (_ *Regexp, err error) { ++ defer func() { ++ switch r := recover(); r { ++ default: ++ panic(r) ++ case nil: ++ // ok ++ case ErrInternalError: ++ err = &Error{Code: ErrInternalError, Expr: s} ++ } ++ }() ++ + if flags&Literal != 0 { + // Trivial parser for literal string. + if err := checkUTF8(s); err != nil { +@@ -710,7 +779,6 @@ func Parse(s string, flags Flags) (*Regexp, error) { + // Otherwise, must do real work. + var ( + p parser +- err error + c rune + op Op + lastRepeat string +diff --git a/src/regexp/syntax/parse_test.go b/src/regexp/syntax/parse_test.go +index 5581ba1..1ef6d8a 100644 +--- a/src/regexp/syntax/parse_test.go ++++ b/src/regexp/syntax/parse_test.go +@@ -207,6 +207,11 @@ var parseTests = []parseTest{ + // Valid repetitions. + {`((((((((((x{2}){2}){2}){2}){2}){2}){2}){2}){2}))`, ``}, + {`((((((((((x{1}){2}){2}){2}){2}){2}){2}){2}){2}){2})`, ``}, ++ ++ // Valid nesting. ++ {strings.Repeat("(", 999) + strings.Repeat(")", 999), ``}, ++ {strings.Repeat("(?:", 999) + strings.Repeat(")*", 999), ``}, ++ {"(" + strings.Repeat("|", 12345) + ")", ``}, // not nested at all + } + + const testFlags = MatchNL | PerlX | UnicodeGroups +@@ -482,6 +487,8 @@ var invalidRegexps = []string{ + `a{100000}`, + `a{100000,}`, + "((((((((((x{2}){2}){2}){2}){2}){2}){2}){2}){2}){2})", ++ strings.Repeat("(", 1000) + strings.Repeat(")", 1000), ++ strings.Repeat("(?:", 1000) + strings.Repeat(")*", 1000), + `\Q\E*`, + } + diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2022-27664.patch b/meta/recipes-devtools/go/go-1.14/CVE-2022-27664.patch new file mode 100644 index 0000000000..238c3eac5b --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2022-27664.patch @@ -0,0 +1,68 @@ +From 48c9076dcfc2dc894842ff758c8cfae7957c9565 Mon Sep 17 00:00:00 2001 +From: Hitendra Prajapati <hprajapati@mvista.com> +Date: Thu, 29 Sep 2022 17:06:18 +0530 +Subject: [PATCH] CVE-2022-27664 + +Upstream-Status: Backport [https://github.com/golang/go/commit/5bc9106458fc07851ac324a4157132a91b1f3479] +CVE: CVE-2022-27664 +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> +--- + src/net/http/h2_bundle.go | 21 +++++++++++++-------- + 1 file changed, 13 insertions(+), 8 deletions(-) + +diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go +index 65d851d..83f2a72 100644 +--- a/src/net/http/h2_bundle.go ++++ b/src/net/http/h2_bundle.go +@@ -3254,10 +3254,11 @@ var ( + // name (key). See httpguts.ValidHeaderName for the base rules. + // + // Further, http2 says: +-// "Just as in HTTP/1.x, header field names are strings of ASCII +-// characters that are compared in a case-insensitive +-// fashion. However, header field names MUST be converted to +-// lowercase prior to their encoding in HTTP/2. " ++// ++// "Just as in HTTP/1.x, header field names are strings of ASCII ++// characters that are compared in a case-insensitive ++// fashion. However, header field names MUST be converted to ++// lowercase prior to their encoding in HTTP/2. " + func http2validWireHeaderFieldName(v string) bool { + if len(v) == 0 { + return false +@@ -3446,8 +3447,8 @@ func (s *http2sorter) SortStrings(ss []string) { + // validPseudoPath reports whether v is a valid :path pseudo-header + // value. It must be either: + // +-// *) a non-empty string starting with '/' +-// *) the string '*', for OPTIONS requests. ++// *) a non-empty string starting with '/' ++// *) the string '*', for OPTIONS requests. + // + // For now this is only used a quick check for deciding when to clean + // up Opaque URLs before sending requests from the Transport. +@@ -4897,6 +4898,9 @@ func (sc *http2serverConn) startGracefulShutdownInternal() { + func (sc *http2serverConn) goAway(code http2ErrCode) { + sc.serveG.check() + if sc.inGoAway { ++ if sc.goAwayCode == http2ErrCodeNo { ++ sc.goAwayCode = code ++ } + return + } + sc.inGoAway = true +@@ -6091,8 +6095,9 @@ func (rws *http2responseWriterState) writeChunk(p []byte) (n int, err error) { + // prior to the headers being written. If the set of trailers is fixed + // or known before the header is written, the normal Go trailers mechanism + // is preferred: +-// https://golang.org/pkg/net/http/#ResponseWriter +-// https://golang.org/pkg/net/http/#example_ResponseWriter_trailers ++// ++// https://golang.org/pkg/net/http/#ResponseWriter ++// https://golang.org/pkg/net/http/#example_ResponseWriter_trailers + const http2TrailerPrefix = "Trailer:" + + // promoteUndeclaredTrailers permits http.Handlers to set trailers +-- +2.25.1 + diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2022-28131.patch b/meta/recipes-devtools/go/go-1.14/CVE-2022-28131.patch new file mode 100644 index 0000000000..8afa292144 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2022-28131.patch @@ -0,0 +1,104 @@ +From 8136eb2e5c316a51d0da710fbd0504cbbefee526 Mon Sep 17 00:00:00 2001 +From: Roland Shoemaker <roland@golang.org> +Date: Mon, 28 Mar 2022 18:41:26 -0700 +Subject: [PATCH] encoding/xml: use iterative Skip, rather than recursive + +Upstream-Status: Backport [https://github.com/golang/go/commit/58facfbe7db2fbb9afed794b281a70bdb12a60ae] +CVE: CVE-2022-28131 +Signed-off-by: Ralph Siemsen <ralph.siemsen@linaro.org> + + +Prevents exhausting the stack limit in _incredibly_ deeply nested +structures. + +Fixes #53711 +Updates #53614 +Fixes CVE-2022-28131 + +Change-Id: I47db4595ce10cecc29fbd06afce7b299868599e6 +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1419912 +Reviewed-by: Julie Qiu <julieqiu@google.com> +Reviewed-by: Damien Neil <dneil@google.com> +(cherry picked from commit 9278cb78443d2b4deb24cbb5b61c9ba5ac688d49) +Reviewed-on: https://go-review.googlesource.com/c/go/+/417068 +TryBot-Result: Gopher Robot <gobot@golang.org> +Reviewed-by: Heschi Kreinick <heschi@google.com> +Run-TryBot: Michael Knyszek <mknyszek@google.com> +--- + src/encoding/xml/read.go | 15 ++++++++------- + src/encoding/xml/read_test.go | 18 ++++++++++++++++++ + 2 files changed, 26 insertions(+), 7 deletions(-) + +diff --git a/src/encoding/xml/read.go b/src/encoding/xml/read.go +index 4ffed80..3fac859 100644 +--- a/src/encoding/xml/read.go ++++ b/src/encoding/xml/read.go +@@ -743,12 +743,12 @@ Loop: + } + + // Skip reads tokens until it has consumed the end element +-// matching the most recent start element already consumed. +-// It recurs if it encounters a start element, so it can be used to +-// skip nested structures. ++// matching the most recent start element already consumed, ++// skipping nested structures. + // It returns nil if it finds an end element matching the start + // element; otherwise it returns an error describing the problem. + func (d *Decoder) Skip() error { ++ var depth int64 + for { + tok, err := d.Token() + if err != nil { +@@ -756,11 +756,12 @@ func (d *Decoder) Skip() error { + } + switch tok.(type) { + case StartElement: +- if err := d.Skip(); err != nil { +- return err +- } ++ depth++ + case EndElement: +- return nil ++ if depth == 0 { ++ return nil ++ } ++ depth-- + } + } + } +diff --git a/src/encoding/xml/read_test.go b/src/encoding/xml/read_test.go +index 6a20b1a..7a621a5 100644 +--- a/src/encoding/xml/read_test.go ++++ b/src/encoding/xml/read_test.go +@@ -5,9 +5,11 @@ + package xml + + import ( ++ "bytes" + "errors" + "io" + "reflect" ++ "runtime" + "strings" + "testing" + "time" +@@ -1093,3 +1095,19 @@ func TestCVE202228131(t *testing.T) { + t.Fatalf("Unmarshal unexpected error: got %q, want %q", err, errExeceededMaxUnmarshalDepth) + } + } ++ ++func TestCVE202230633(t *testing.T) { ++ if runtime.GOARCH == "wasm" { ++ t.Skip("causes memory exhaustion on js/wasm") ++ } ++ defer func() { ++ p := recover() ++ if p != nil { ++ t.Fatal("Unmarshal panicked") ++ } ++ }() ++ var example struct { ++ Things []string ++ } ++ Unmarshal(bytes.Repeat([]byte("<a>"), 17_000_000), &example) ++} diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2022-28327.patch b/meta/recipes-devtools/go/go-1.14/CVE-2022-28327.patch new file mode 100644 index 0000000000..6361deec7d --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2022-28327.patch @@ -0,0 +1,36 @@ +From 34d9ab78568d63d8097911237897b188bdaba9c2 Mon Sep 17 00:00:00 2001 +From: Filippo Valsorda <filippo@golang.org> +Date: Thu, 31 Mar 2022 12:31:58 -0400 +Subject: [PATCH] crypto/elliptic: tolerate zero-padded scalars in generic + P-256 + +Upstream-Status: Backport [https://github.com/golang/go/commit/7139e8b024604ab168b51b99c6e8168257a5bf58] +CVE: CVE-2022-28327 +Signed-off-by: Ralph Siemsen <ralph.siemsen@linaro.org> + + +Updates #52075 +Fixes #52076 +Fixes CVE-2022-28327 + +Change-Id: I595a7514c9a0aa1b9c76aedfc2307e1124271f27 +Reviewed-on: https://go-review.googlesource.com/c/go/+/397136 +Trust: Filippo Valsorda <filippo@golang.org> +Reviewed-by: Julie Qiu <julie@golang.org> +--- + src/crypto/elliptic/p256.go | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/crypto/elliptic/p256.go b/src/crypto/elliptic/p256.go +index c23e414..787e3e7 100644 +--- a/src/crypto/elliptic/p256.go ++++ b/src/crypto/elliptic/p256.go +@@ -51,7 +51,7 @@ func p256GetScalar(out *[32]byte, in []byte) { + n := new(big.Int).SetBytes(in) + var scalarBytes []byte + +- if n.Cmp(p256Params.N) >= 0 { ++ if n.Cmp(p256Params.N) >= 0 || len(in) > len(out) { + n.Mod(n, p256Params.N) + scalarBytes = n.Bytes() + } else { diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2022-2879.patch b/meta/recipes-devtools/go/go-1.14/CVE-2022-2879.patch new file mode 100644 index 0000000000..ea04a82d16 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2022-2879.patch @@ -0,0 +1,111 @@ +From 9d339f1d0f53c4116a7cb4acfa895f31a07212ee Mon Sep 17 00:00:00 2001 +From: Damien Neil <dneil@google.com> +Date: Fri, 2 Sep 2022 20:45:18 -0700 +Subject: [PATCH] archive/tar: limit size of headers + +Set a 1MiB limit on special file blocks (PAX headers, GNU long names, +GNU link names), to avoid reading arbitrarily large amounts of data +into memory. + +Thanks to Adam Korczynski (ADA Logics) and OSS-Fuzz for reporting +this issue. + +Fixes CVE-2022-2879 +Updates #54853 +Fixes #55926 + +Change-Id: I85136d6ff1e0af101a112190e027987ab4335680 +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1565555 +Reviewed-by: Tatiana Bradley <tatianabradley@google.com> +Run-TryBot: Roland Shoemaker <bracewell@google.com> +Reviewed-by: Roland Shoemaker <bracewell@google.com> +(cherry picked from commit 6ee768cef6b82adf7a90dcf367a1699ef694f3b2) +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1591053 +Reviewed-by: Julie Qiu <julieqiu@google.com> +Reviewed-by: Damien Neil <dneil@google.com> +Reviewed-on: https://go-review.googlesource.com/c/go/+/438498 +TryBot-Result: Gopher Robot <gobot@golang.org> +Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> +Reviewed-by: Carlos Amedee <carlos@golang.org> +Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org> +Run-TryBot: Carlos Amedee <carlos@golang.org> + +Upstream-Status: Backport [https://github.com/golang/go/commit/0a723816cd2] +CVE: CVE-2022-2879 +Signed-off-by: Sunil Kumar <sukumar@mvista.com> +--- + src/archive/tar/format.go | 4 ++++ + src/archive/tar/reader.go | 14 ++++++++++++-- + src/archive/tar/writer.go | 3 +++ + 3 files changed, 19 insertions(+), 2 deletions(-) + +diff --git a/src/archive/tar/format.go b/src/archive/tar/format.go +index cfe24a5..6642364 100644 +--- a/src/archive/tar/format.go ++++ b/src/archive/tar/format.go +@@ -143,6 +143,10 @@ const ( + blockSize = 512 // Size of each block in a tar stream + nameSize = 100 // Max length of the name field in USTAR format + prefixSize = 155 // Max length of the prefix field in USTAR format ++ ++ // Max length of a special file (PAX header, GNU long name or link). ++ // This matches the limit used by libarchive. ++ maxSpecialFileSize = 1 << 20 + ) + + // blockPadding computes the number of bytes needed to pad offset up to the +diff --git a/src/archive/tar/reader.go b/src/archive/tar/reader.go +index 4f9135b..e996595 100644 +--- a/src/archive/tar/reader.go ++++ b/src/archive/tar/reader.go +@@ -104,7 +104,7 @@ func (tr *Reader) next() (*Header, error) { + continue // This is a meta header affecting the next header + case TypeGNULongName, TypeGNULongLink: + format.mayOnlyBe(FormatGNU) +- realname, err := ioutil.ReadAll(tr) ++ realname, err := readSpecialFile(tr) + if err != nil { + return nil, err + } +@@ -294,7 +294,7 @@ func mergePAX(hdr *Header, paxHdrs map[string]string) (err error) { + // parsePAX parses PAX headers. + // If an extended header (type 'x') is invalid, ErrHeader is returned + func parsePAX(r io.Reader) (map[string]string, error) { +- buf, err := ioutil.ReadAll(r) ++ buf, err := readSpecialFile(r) + if err != nil { + return nil, err + } +@@ -827,6 +827,16 @@ func tryReadFull(r io.Reader, b []byte) (n int, err error) { + return n, err + } + ++// readSpecialFile is like ioutil.ReadAll except it returns ++// ErrFieldTooLong if more than maxSpecialFileSize is read. ++func readSpecialFile(r io.Reader) ([]byte, error) { ++ buf, err := ioutil.ReadAll(io.LimitReader(r, maxSpecialFileSize+1)) ++ if len(buf) > maxSpecialFileSize { ++ return nil, ErrFieldTooLong ++ } ++ return buf, err ++} ++ + // discard skips n bytes in r, reporting an error if unable to do so. + func discard(r io.Reader, n int64) error { + // If possible, Seek to the last byte before the end of the data section. +diff --git a/src/archive/tar/writer.go b/src/archive/tar/writer.go +index e80498d..893eac0 100644 +--- a/src/archive/tar/writer.go ++++ b/src/archive/tar/writer.go +@@ -199,6 +199,9 @@ func (tw *Writer) writePAXHeader(hdr *Header, paxHdrs map[string]string) error { + flag = TypeXHeader + } + data := buf.String() ++ if len(data) > maxSpecialFileSize { ++ return ErrFieldTooLong ++ } + if err := tw.writeRawFile(name, data, flag, FormatPAX); err != nil || isGlobal { + return err // Global headers return here + } +-- +2.7.4 diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2022-2880.patch b/meta/recipes-devtools/go/go-1.14/CVE-2022-2880.patch new file mode 100644 index 0000000000..8376dc45ba --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2022-2880.patch @@ -0,0 +1,164 @@ +From 753e3f8da191c2ac400407d83c70f46900769417 Mon Sep 17 00:00:00 2001 +From: Hitendra Prajapati <hprajapati@mvista.com> +Date: Thu, 27 Oct 2022 12:22:41 +0530 +Subject: [PATCH] CVE-2022-2880 + +Upstream-Status: Backport [https://github.com/golang/go/commit/9d2c73a9fd69e45876509bb3bdb2af99bf77da1e] +CVE: CVE-2022-2880 +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> + +net/http/httputil: avoid query parameter + +Query parameter smuggling occurs when a proxy's interpretation +of query parameters differs from that of a downstream server. +Change ReverseProxy to avoid forwarding ignored query parameters. + +Remove unparsable query parameters from the outbound request + + * if req.Form != nil after calling ReverseProxy.Director; and + * before calling ReverseProxy.Rewrite. + +This change preserves the existing behavior of forwarding the +raw query untouched if a Director hook does not parse the query +by calling Request.ParseForm (possibly indirectly). +--- + src/net/http/httputil/reverseproxy.go | 36 +++++++++++ + src/net/http/httputil/reverseproxy_test.go | 74 ++++++++++++++++++++++ + 2 files changed, 110 insertions(+) + +diff --git a/src/net/http/httputil/reverseproxy.go b/src/net/http/httputil/reverseproxy.go +index 2072a5f..c6fb873 100644 +--- a/src/net/http/httputil/reverseproxy.go ++++ b/src/net/http/httputil/reverseproxy.go +@@ -212,6 +212,9 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { + } + + p.Director(outreq) ++ if outreq.Form != nil { ++ outreq.URL.RawQuery = cleanQueryParams(outreq.URL.RawQuery) ++ } + outreq.Close = false + + reqUpType := upgradeType(outreq.Header) +@@ -561,3 +564,36 @@ func (c switchProtocolCopier) copyToBackend(errc chan<- error) { + _, err := io.Copy(c.backend, c.user) + errc <- err + } ++ ++func cleanQueryParams(s string) string { ++ reencode := func(s string) string { ++ v, _ := url.ParseQuery(s) ++ return v.Encode() ++ } ++ for i := 0; i < len(s); { ++ switch s[i] { ++ case ';': ++ return reencode(s) ++ case '%': ++ if i+2 >= len(s) || !ishex(s[i+1]) || !ishex(s[i+2]) { ++ return reencode(s) ++ } ++ i += 3 ++ default: ++ i++ ++ } ++ } ++ return s ++} ++ ++func ishex(c byte) bool { ++ switch { ++ case '0' <= c && c <= '9': ++ return true ++ case 'a' <= c && c <= 'f': ++ return true ++ case 'A' <= c && c <= 'F': ++ return true ++ } ++ return false ++} +diff --git a/src/net/http/httputil/reverseproxy_test.go b/src/net/http/httputil/reverseproxy_test.go +index 9a7223a..bc87a3b 100644 +--- a/src/net/http/httputil/reverseproxy_test.go ++++ b/src/net/http/httputil/reverseproxy_test.go +@@ -1269,3 +1269,77 @@ func TestSingleJoinSlash(t *testing.T) { + } + } + } ++ ++const ( ++ testWantsCleanQuery = true ++ testWantsRawQuery = false ++) ++ ++func TestReverseProxyQueryParameterSmugglingDirectorDoesNotParseForm(t *testing.T) { ++ testReverseProxyQueryParameterSmuggling(t, testWantsRawQuery, func(u *url.URL) *ReverseProxy { ++ proxyHandler := NewSingleHostReverseProxy(u) ++ oldDirector := proxyHandler.Director ++ proxyHandler.Director = func(r *http.Request) { ++ oldDirector(r) ++ } ++ return proxyHandler ++ }) ++} ++ ++func TestReverseProxyQueryParameterSmugglingDirectorParsesForm(t *testing.T) { ++ testReverseProxyQueryParameterSmuggling(t, testWantsCleanQuery, func(u *url.URL) *ReverseProxy { ++ proxyHandler := NewSingleHostReverseProxy(u) ++ oldDirector := proxyHandler.Director ++ proxyHandler.Director = func(r *http.Request) { ++ // Parsing the form causes ReverseProxy to remove unparsable ++ // query parameters before forwarding. ++ r.FormValue("a") ++ oldDirector(r) ++ } ++ return proxyHandler ++ }) ++} ++ ++func testReverseProxyQueryParameterSmuggling(t *testing.T, wantCleanQuery bool, newProxy func(*url.URL) *ReverseProxy) { ++ const content = "response_content" ++ backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ++ w.Write([]byte(r.URL.RawQuery)) ++ })) ++ defer backend.Close() ++ backendURL, err := url.Parse(backend.URL) ++ if err != nil { ++ t.Fatal(err) ++ } ++ proxyHandler := newProxy(backendURL) ++ frontend := httptest.NewServer(proxyHandler) ++ defer frontend.Close() ++ ++ // Don't spam output with logs of queries containing semicolons. ++ backend.Config.ErrorLog = log.New(io.Discard, "", 0) ++ frontend.Config.ErrorLog = log.New(io.Discard, "", 0) ++ ++ for _, test := range []struct { ++ rawQuery string ++ cleanQuery string ++ }{{ ++ rawQuery: "a=1&a=2;b=3", ++ cleanQuery: "a=1", ++ }, { ++ rawQuery: "a=1&a=%zz&b=3", ++ cleanQuery: "a=1&b=3", ++ }} { ++ res, err := frontend.Client().Get(frontend.URL + "?" + test.rawQuery) ++ if err != nil { ++ t.Fatalf("Get: %v", err) ++ } ++ defer res.Body.Close() ++ body, _ := io.ReadAll(res.Body) ++ wantQuery := test.rawQuery ++ if wantCleanQuery { ++ wantQuery = test.cleanQuery ++ } ++ if got, want := string(body), wantQuery; got != want { ++ t.Errorf("proxy forwarded raw query %q as %q, want %q", test.rawQuery, got, want) ++ } ++ } ++} +-- +2.25.1 + diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2022-30629.patch b/meta/recipes-devtools/go/go-1.14/CVE-2022-30629.patch new file mode 100644 index 0000000000..47313a547f --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2022-30629.patch @@ -0,0 +1,47 @@ +From 8d0bbb5a6280c2cf951241ec7f6579c90d38df57 Mon Sep 17 00:00:00 2001 +From: Hitendra Prajapati <hprajapati@mvista.com> +Date: Thu, 25 Aug 2022 10:55:08 +0530 +Subject: [PATCH] CVE-2022-30629 + +Upstream-Status: Backport [https://github.com/golang/go/commit/c15a8e2dbb5ac376a6ed890735341b812d6b965c] +CVE: CVE-2022-30629 +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> +--- + src/crypto/tls/handshake_server_tls13.go | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/src/crypto/tls/handshake_server_tls13.go b/src/crypto/tls/handshake_server_tls13.go +index 5432145..d91797e 100644 +--- a/src/crypto/tls/handshake_server_tls13.go ++++ b/src/crypto/tls/handshake_server_tls13.go +@@ -9,6 +9,7 @@ import ( + "crypto" + "crypto/hmac" + "crypto/rsa" ++ "encoding/binary" + "errors" + "hash" + "io" +@@ -742,6 +743,19 @@ func (hs *serverHandshakeStateTLS13) sendSessionTickets() error { + } + m.lifetime = uint32(maxSessionTicketLifetime / time.Second) + ++ // ticket_age_add is a random 32-bit value. See RFC 8446, section 4.6.1 ++ // The value is not stored anywhere; we never need to check the ticket age ++ // because 0-RTT is not supported. ++ ageAdd := make([]byte, 4) ++ _, err = hs.c.config.rand().Read(ageAdd) ++ if err != nil { ++ return err ++ } ++ m.ageAdd = binary.LittleEndian.Uint32(ageAdd) ++ ++ // ticket_nonce, which must be unique per connection, is always left at ++ // zero because we only ever send one ticket per connection. ++ + if _, err := c.writeRecord(recordTypeHandshake, m.marshal()); err != nil { + return err + } +-- +2.25.1 + diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2022-30631.patch b/meta/recipes-devtools/go/go-1.14/CVE-2022-30631.patch new file mode 100644 index 0000000000..5dcfd27f16 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2022-30631.patch @@ -0,0 +1,116 @@ +From d10fc3a84e3344f2421c1dd3046faa50709ab4d5 Mon Sep 17 00:00:00 2001 +From: Hitendra Prajapati <hprajapati@mvista.com> +Date: Thu, 25 Aug 2022 11:01:21 +0530 +Subject: [PATCH] CVE-2022-30631 + +Upstream-Status: Backport [https://github.com/golang/go/commit/0117dee7dccbbd7803d88f65a2ce8bd686219ad3] +CVE: CVE-2022-30631 +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> +--- + src/compress/gzip/gunzip.go | 60 +++++++++++++++----------------- + src/compress/gzip/gunzip_test.go | 16 +++++++++ + 2 files changed, 45 insertions(+), 31 deletions(-) + +diff --git a/src/compress/gzip/gunzip.go b/src/compress/gzip/gunzip.go +index 924bce1..237b2b9 100644 +--- a/src/compress/gzip/gunzip.go ++++ b/src/compress/gzip/gunzip.go +@@ -248,42 +248,40 @@ func (z *Reader) Read(p []byte) (n int, err error) { + return 0, z.err + } + +- n, z.err = z.decompressor.Read(p) +- z.digest = crc32.Update(z.digest, crc32.IEEETable, p[:n]) +- z.size += uint32(n) +- if z.err != io.EOF { +- // In the normal case we return here. +- return n, z.err +- } ++ for n == 0 { ++ n, z.err = z.decompressor.Read(p) ++ z.digest = crc32.Update(z.digest, crc32.IEEETable, p[:n]) ++ z.size += uint32(n) ++ if z.err != io.EOF { ++ // In the normal case we return here. ++ return n, z.err ++ } + +- // Finished file; check checksum and size. +- if _, err := io.ReadFull(z.r, z.buf[:8]); err != nil { +- z.err = noEOF(err) +- return n, z.err +- } +- digest := le.Uint32(z.buf[:4]) +- size := le.Uint32(z.buf[4:8]) +- if digest != z.digest || size != z.size { +- z.err = ErrChecksum +- return n, z.err +- } +- z.digest, z.size = 0, 0 ++ // Finished file; check checksum and size. ++ if _, err := io.ReadFull(z.r, z.buf[:8]); err != nil { ++ z.err = noEOF(err) ++ return n, z.err ++ } ++ digest := le.Uint32(z.buf[:4]) ++ size := le.Uint32(z.buf[4:8]) ++ if digest != z.digest || size != z.size { ++ z.err = ErrChecksum ++ return n, z.err ++ } ++ z.digest, z.size = 0, 0 + +- // File is ok; check if there is another. +- if !z.multistream { +- return n, io.EOF +- } +- z.err = nil // Remove io.EOF ++ // File is ok; check if there is another. ++ if !z.multistream { ++ return n, io.EOF ++ } ++ z.err = nil // Remove io.EOF + +- if _, z.err = z.readHeader(); z.err != nil { +- return n, z.err ++ if _, z.err = z.readHeader(); z.err != nil { ++ return n, z.err ++ } + } + +- // Read from next file, if necessary. +- if n > 0 { +- return n, nil +- } +- return z.Read(p) ++ return n, nil + } + + // Close closes the Reader. It does not close the underlying io.Reader. +diff --git a/src/compress/gzip/gunzip_test.go b/src/compress/gzip/gunzip_test.go +index 1b01404..95220ae 100644 +--- a/src/compress/gzip/gunzip_test.go ++++ b/src/compress/gzip/gunzip_test.go +@@ -516,3 +516,19 @@ func TestTruncatedStreams(t *testing.T) { + } + } + } ++ ++func TestCVE202230631(t *testing.T) { ++ var empty = []byte{0x1f, 0x8b, 0x08, 0x00, 0xa7, 0x8f, 0x43, 0x62, 0x00, ++ 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} ++ r := bytes.NewReader(bytes.Repeat(empty, 4e6)) ++ z, err := NewReader(r) ++ if err != nil { ++ t.Fatalf("NewReader: got %v, want nil", err) ++ } ++ // Prior to CVE-2022-30631 fix, this would cause an unrecoverable panic due ++ // to stack exhaustion. ++ _, err = z.Read(make([]byte, 10)) ++ if err != io.EOF { ++ t.Errorf("Reader.Read: got %v, want %v", err, io.EOF) ++ } ++} +-- +2.25.1 + diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2022-30632.patch b/meta/recipes-devtools/go/go-1.14/CVE-2022-30632.patch new file mode 100644 index 0000000000..c54ef56a0e --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2022-30632.patch @@ -0,0 +1,71 @@ +From 35d1dfe9746029aea9027b405c75555d41ffd2f8 Mon Sep 17 00:00:00 2001 +From: Hitendra Prajapati <hprajapati@mvista.com> +Date: Thu, 25 Aug 2022 13:12:40 +0530 +Subject: [PATCH] CVE-2022-30632 + +Upstream-Status: Backport [https://github.com/golang/go/commit/76f8b7304d1f7c25834e2a0cc9e88c55276c47df] +CVE: CVE-2022-30632 +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> +--- + src/path/filepath/match.go | 16 +++++++++++++++- + src/path/filepath/match_test.go | 10 ++++++++++ + 2 files changed, 25 insertions(+), 1 deletion(-) + +diff --git a/src/path/filepath/match.go b/src/path/filepath/match.go +index 46badb5..ba68daa 100644 +--- a/src/path/filepath/match.go ++++ b/src/path/filepath/match.go +@@ -232,6 +232,20 @@ func getEsc(chunk string) (r rune, nchunk string, err error) { + // The only possible returned error is ErrBadPattern, when pattern + // is malformed. + func Glob(pattern string) (matches []string, err error) { ++ return globWithLimit(pattern, 0) ++} ++ ++func globWithLimit(pattern string, depth int) (matches []string, err error) { ++ // This limit is used prevent stack exhaustion issues. See CVE-2022-30632. ++ const pathSeparatorsLimit = 10000 ++ if depth == pathSeparatorsLimit { ++ return nil, ErrBadPattern ++ } ++ ++ // Check pattern is well-formed. ++ if _, err := Match(pattern, ""); err != nil { ++ return nil, err ++ } + if !hasMeta(pattern) { + if _, err = os.Lstat(pattern); err != nil { + return nil, nil +@@ -257,7 +271,7 @@ func Glob(pattern string) (matches []string, err error) { + } + + var m []string +- m, err = Glob(dir) ++ m, err = globWithLimit(dir, depth+1) + if err != nil { + return + } +diff --git a/src/path/filepath/match_test.go b/src/path/filepath/match_test.go +index b865762..c37c812 100644 +--- a/src/path/filepath/match_test.go ++++ b/src/path/filepath/match_test.go +@@ -154,6 +154,16 @@ func TestGlob(t *testing.T) { + } + } + ++func TestCVE202230632(t *testing.T) { ++ // Prior to CVE-2022-30632, this would cause a stack exhaustion given a ++ // large number of separators (more than 4,000,000). There is now a limit ++ // of 10,000. ++ _, err := Glob("/*" + strings.Repeat("/", 10001)) ++ if err != ErrBadPattern { ++ t.Fatalf("Glob returned err=%v, want ErrBadPattern", err) ++ } ++} ++ + func TestGlobError(t *testing.T) { + _, err := Glob("[]") + if err == nil { +-- +2.25.1 + diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2022-30633.patch b/meta/recipes-devtools/go/go-1.14/CVE-2022-30633.patch new file mode 100644 index 0000000000..c16cb5f50c --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2022-30633.patch @@ -0,0 +1,131 @@ +From ab6e2ffdcab0501bcc2de4b196c1c18ae2301d4b Mon Sep 17 00:00:00 2001 +From: Hitendra Prajapati <hprajapati@mvista.com> +Date: Thu, 25 Aug 2022 13:29:55 +0530 +Subject: [PATCH] CVE-2022-30633 + +Upstream-Status: Backport [https://github.com/golang/go/commit/2678d0c957193dceef336c969a9da74dd716a827] +CVE: CVE-2022-30633 +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> +--- + src/encoding/xml/read.go | 27 +++++++++++++++++++-------- + src/encoding/xml/read_test.go | 14 ++++++++++++++ + 2 files changed, 33 insertions(+), 8 deletions(-) + +diff --git a/src/encoding/xml/read.go b/src/encoding/xml/read.go +index 10a60ee..4ffed80 100644 +--- a/src/encoding/xml/read.go ++++ b/src/encoding/xml/read.go +@@ -148,7 +148,7 @@ func (d *Decoder) DecodeElement(v interface{}, start *StartElement) error { + if val.Kind() != reflect.Ptr { + return errors.New("non-pointer passed to Unmarshal") + } +- return d.unmarshal(val.Elem(), start) ++ return d.unmarshal(val.Elem(), start, 0) + } + + // An UnmarshalError represents an error in the unmarshaling process. +@@ -304,8 +304,15 @@ var ( + textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() + ) + ++const maxUnmarshalDepth = 10000 ++ ++var errExeceededMaxUnmarshalDepth = errors.New("exceeded max depth") ++ + // Unmarshal a single XML element into val. +-func (d *Decoder) unmarshal(val reflect.Value, start *StartElement) error { ++func (d *Decoder) unmarshal(val reflect.Value, start *StartElement, depth int) error { ++ if depth >= maxUnmarshalDepth { ++ return errExeceededMaxUnmarshalDepth ++ } + // Find start element if we need it. + if start == nil { + for { +@@ -398,7 +405,7 @@ func (d *Decoder) unmarshal(val reflect.Value, start *StartElement) error { + v.Set(reflect.Append(val, reflect.Zero(v.Type().Elem()))) + + // Recur to read element into slice. +- if err := d.unmarshal(v.Index(n), start); err != nil { ++ if err := d.unmarshal(v.Index(n), start, depth+1); err != nil { + v.SetLen(n) + return err + } +@@ -521,13 +528,15 @@ Loop: + case StartElement: + consumed := false + if sv.IsValid() { +- consumed, err = d.unmarshalPath(tinfo, sv, nil, &t) ++ // unmarshalPath can call unmarshal, so we need to pass the depth through so that ++ // we can continue to enforce the maximum recusion limit. ++ consumed, err = d.unmarshalPath(tinfo, sv, nil, &t, depth) + if err != nil { + return err + } + if !consumed && saveAny.IsValid() { + consumed = true +- if err := d.unmarshal(saveAny, &t); err != nil { ++ if err := d.unmarshal(saveAny, &t, depth+1); err != nil { + return err + } + } +@@ -672,7 +681,7 @@ func copyValue(dst reflect.Value, src []byte) (err error) { + // The consumed result tells whether XML elements have been consumed + // from the Decoder until start's matching end element, or if it's + // still untouched because start is uninteresting for sv's fields. +-func (d *Decoder) unmarshalPath(tinfo *typeInfo, sv reflect.Value, parents []string, start *StartElement) (consumed bool, err error) { ++func (d *Decoder) unmarshalPath(tinfo *typeInfo, sv reflect.Value, parents []string, start *StartElement, depth int) (consumed bool, err error) { + recurse := false + Loop: + for i := range tinfo.fields { +@@ -687,7 +696,7 @@ Loop: + } + if len(finfo.parents) == len(parents) && finfo.name == start.Name.Local { + // It's a perfect match, unmarshal the field. +- return true, d.unmarshal(finfo.value(sv), start) ++ return true, d.unmarshal(finfo.value(sv), start, depth+1) + } + if len(finfo.parents) > len(parents) && finfo.parents[len(parents)] == start.Name.Local { + // It's a prefix for the field. Break and recurse +@@ -716,7 +725,9 @@ Loop: + } + switch t := tok.(type) { + case StartElement: +- consumed2, err := d.unmarshalPath(tinfo, sv, parents, &t) ++ // the recursion depth of unmarshalPath is limited to the path length specified ++ // by the struct field tag, so we don't increment the depth here. ++ consumed2, err := d.unmarshalPath(tinfo, sv, parents, &t, depth) + if err != nil { + return true, err + } +diff --git a/src/encoding/xml/read_test.go b/src/encoding/xml/read_test.go +index 8c2e70f..6a20b1a 100644 +--- a/src/encoding/xml/read_test.go ++++ b/src/encoding/xml/read_test.go +@@ -5,6 +5,7 @@ + package xml + + import ( ++ "errors" + "io" + "reflect" + "strings" +@@ -1079,3 +1080,16 @@ func TestUnmarshalWhitespaceAttrs(t *testing.T) { + t.Fatalf("whitespace attrs: Unmarshal:\nhave: %#+v\nwant: %#+v", v, want) + } + } ++ ++func TestCVE202228131(t *testing.T) { ++ type nested struct { ++ Parent *nested `xml:",any"` ++ } ++ var n nested ++ err := Unmarshal(bytes.Repeat([]byte("<a>"), maxUnmarshalDepth+1), &n) ++ if err == nil { ++ t.Fatal("Unmarshal did not fail") ++ } else if !errors.Is(err, errExeceededMaxUnmarshalDepth) { ++ t.Fatalf("Unmarshal unexpected error: got %q, want %q", err, errExeceededMaxUnmarshalDepth) ++ } ++} +-- +2.25.1 + diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2022-30635.patch b/meta/recipes-devtools/go/go-1.14/CVE-2022-30635.patch new file mode 100644 index 0000000000..73959f70fa --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2022-30635.patch @@ -0,0 +1,120 @@ +From fdd4316737ed5681689a1f40802ffa0805e5b11c Mon Sep 17 00:00:00 2001 +From: Hitendra Prajapati <hprajapati@mvista.com> +Date: Fri, 26 Aug 2022 12:17:05 +0530 +Subject: [PATCH] CVE-2022-30635 + +Upstream-Status: Backport [https://github.com/golang/go/commit/cd54600b866db0ad068ab8df06c7f5f6cb55c9b3] +CVE-2022-30635 +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> +--- + src/encoding/gob/decode.go | 19 ++++++++++++------- + src/encoding/gob/gobencdec_test.go | 24 ++++++++++++++++++++++++ + 2 files changed, 36 insertions(+), 7 deletions(-) + +diff --git a/src/encoding/gob/decode.go b/src/encoding/gob/decode.go +index d2f6c74..0e0ec75 100644 +--- a/src/encoding/gob/decode.go ++++ b/src/encoding/gob/decode.go +@@ -871,8 +871,13 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg + return &op + } + ++var maxIgnoreNestingDepth = 10000 ++ + // decIgnoreOpFor returns the decoding op for a field that has no destination. +-func (dec *Decoder) decIgnoreOpFor(wireId typeId, inProgress map[typeId]*decOp) *decOp { ++func (dec *Decoder) decIgnoreOpFor(wireId typeId, inProgress map[typeId]*decOp, depth int) *decOp { ++ if depth > maxIgnoreNestingDepth { ++ error_(errors.New("invalid nesting depth")) ++ } + // If this type is already in progress, it's a recursive type (e.g. map[string]*T). + // Return the pointer to the op we're already building. + if opPtr := inProgress[wireId]; opPtr != nil { +@@ -896,7 +901,7 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId, inProgress map[typeId]*decOp) + errorf("bad data: undefined type %s", wireId.string()) + case wire.ArrayT != nil: + elemId := wire.ArrayT.Elem +- elemOp := dec.decIgnoreOpFor(elemId, inProgress) ++ elemOp := dec.decIgnoreOpFor(elemId, inProgress, depth+1) + op = func(i *decInstr, state *decoderState, value reflect.Value) { + state.dec.ignoreArray(state, *elemOp, wire.ArrayT.Len) + } +@@ -904,15 +909,15 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId, inProgress map[typeId]*decOp) + case wire.MapT != nil: + keyId := dec.wireType[wireId].MapT.Key + elemId := dec.wireType[wireId].MapT.Elem +- keyOp := dec.decIgnoreOpFor(keyId, inProgress) +- elemOp := dec.decIgnoreOpFor(elemId, inProgress) ++ keyOp := dec.decIgnoreOpFor(keyId, inProgress, depth+1) ++ elemOp := dec.decIgnoreOpFor(elemId, inProgress, depth+1) + op = func(i *decInstr, state *decoderState, value reflect.Value) { + state.dec.ignoreMap(state, *keyOp, *elemOp) + } + + case wire.SliceT != nil: + elemId := wire.SliceT.Elem +- elemOp := dec.decIgnoreOpFor(elemId, inProgress) ++ elemOp := dec.decIgnoreOpFor(elemId, inProgress, depth+1) + op = func(i *decInstr, state *decoderState, value reflect.Value) { + state.dec.ignoreSlice(state, *elemOp) + } +@@ -1073,7 +1078,7 @@ func (dec *Decoder) compileSingle(remoteId typeId, ut *userTypeInfo) (engine *de + func (dec *Decoder) compileIgnoreSingle(remoteId typeId) *decEngine { + engine := new(decEngine) + engine.instr = make([]decInstr, 1) // one item +- op := dec.decIgnoreOpFor(remoteId, make(map[typeId]*decOp)) ++ op := dec.decIgnoreOpFor(remoteId, make(map[typeId]*decOp), 0) + ovfl := overflow(dec.typeString(remoteId)) + engine.instr[0] = decInstr{*op, 0, nil, ovfl} + engine.numInstr = 1 +@@ -1118,7 +1123,7 @@ func (dec *Decoder) compileDec(remoteId typeId, ut *userTypeInfo) (engine *decEn + localField, present := srt.FieldByName(wireField.Name) + // TODO(r): anonymous names + if !present || !isExported(wireField.Name) { +- op := dec.decIgnoreOpFor(wireField.Id, make(map[typeId]*decOp)) ++ op := dec.decIgnoreOpFor(wireField.Id, make(map[typeId]*decOp), 0) + engine.instr[fieldnum] = decInstr{*op, fieldnum, nil, ovfl} + continue + } +diff --git a/src/encoding/gob/gobencdec_test.go b/src/encoding/gob/gobencdec_test.go +index 6d2c8db..1b52ecc 100644 +--- a/src/encoding/gob/gobencdec_test.go ++++ b/src/encoding/gob/gobencdec_test.go +@@ -12,6 +12,7 @@ import ( + "fmt" + "io" + "net" ++ "reflect" + "strings" + "testing" + "time" +@@ -796,3 +797,26 @@ func TestNetIP(t *testing.T) { + t.Errorf("decoded to %v, want 1.2.3.4", ip.String()) + } + } ++ ++func TestIngoreDepthLimit(t *testing.T) { ++ // We don't test the actual depth limit because it requires building an ++ // extremely large message, which takes quite a while. ++ oldNestingDepth := maxIgnoreNestingDepth ++ maxIgnoreNestingDepth = 100 ++ defer func() { maxIgnoreNestingDepth = oldNestingDepth }() ++ b := new(bytes.Buffer) ++ enc := NewEncoder(b) ++ typ := reflect.TypeOf(int(0)) ++ nested := reflect.ArrayOf(1, typ) ++ for i := 0; i < 100; i++ { ++ nested = reflect.ArrayOf(1, nested) ++ } ++ badStruct := reflect.New(reflect.StructOf([]reflect.StructField{{Name: "F", Type: nested}})) ++ enc.Encode(badStruct.Interface()) ++ dec := NewDecoder(b) ++ var output struct{ Hello int } ++ expectedErr := "invalid nesting depth" ++ if err := dec.Decode(&output); err == nil || err.Error() != expectedErr { ++ t.Errorf("Decode didn't fail with depth limit of 100: want %q, got %q", expectedErr, err) ++ } ++} +-- +2.25.1 + diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2022-32148.patch b/meta/recipes-devtools/go/go-1.14/CVE-2022-32148.patch new file mode 100644 index 0000000000..aab98e99fd --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2022-32148.patch @@ -0,0 +1,49 @@ +From 0fe3adec199e8cd2c101933f75d8cd617de70350 Mon Sep 17 00:00:00 2001 +From: Hitendra Prajapati <hprajapati@mvista.com> +Date: Fri, 26 Aug 2022 12:48:13 +0530 +Subject: [PATCH] CVE-2022-32148 + +Upstream-Status: Backport [https://github.com/golang/go/commit/ed2f33e1a7e0d18f61bd56f7ee067331d612c27e] +CVE: CVE-2022-32148 +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> +--- + src/net/http/header.go | 6 ++++++ + src/net/http/header_test.go | 5 +++++ + 2 files changed, 11 insertions(+) + +diff --git a/src/net/http/header.go b/src/net/http/header.go +index b9b5391..221f613 100644 +--- a/src/net/http/header.go ++++ b/src/net/http/header.go +@@ -100,6 +100,12 @@ func (h Header) Clone() Header { + sv := make([]string, nv) // shared backing array for headers' values + h2 := make(Header, len(h)) + for k, vv := range h { ++ if vv == nil { ++ // Preserve nil values. ReverseProxy distinguishes ++ // between nil and zero-length header values. ++ h2[k] = nil ++ continue ++ } + n := copy(sv, vv) + h2[k] = sv[:n:n] + sv = sv[n:] +diff --git a/src/net/http/header_test.go b/src/net/http/header_test.go +index 4789362..80c0035 100644 +--- a/src/net/http/header_test.go ++++ b/src/net/http/header_test.go +@@ -235,6 +235,11 @@ func TestCloneOrMakeHeader(t *testing.T) { + in: Header{"foo": {"bar"}}, + want: Header{"foo": {"bar"}}, + }, ++ { ++ name: "nil value", ++ in: Header{"foo": nil}, ++ want: Header{"foo": nil}, ++ }, + } + + for _, tt := range tests { +-- +2.25.1 + diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2022-32189.patch b/meta/recipes-devtools/go/go-1.14/CVE-2022-32189.patch new file mode 100644 index 0000000000..15fda7de1b --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2022-32189.patch @@ -0,0 +1,113 @@ +From 027e7e1578d3d7614f7586eff3894b83d9709e14 Mon Sep 17 00:00:00 2001 +From: Hitendra Prajapati <hprajapati@mvista.com> +Date: Mon, 29 Aug 2022 10:08:34 +0530 +Subject: [PATCH] CVE-2022-32189 + +Upstream-Status: Backport [https://github.com/golang/go/commit/703c8ab7e5ba75c95553d4e249309297abad7102] +CVE: CVE-2022-32189 +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> +--- + src/math/big/floatmarsh.go | 7 +++++++ + src/math/big/floatmarsh_test.go | 12 ++++++++++++ + src/math/big/ratmarsh.go | 6 ++++++ + src/math/big/ratmarsh_test.go | 12 ++++++++++++ + 4 files changed, 37 insertions(+) + +diff --git a/src/math/big/floatmarsh.go b/src/math/big/floatmarsh.go +index d1c1dab..990e085 100644 +--- a/src/math/big/floatmarsh.go ++++ b/src/math/big/floatmarsh.go +@@ -8,6 +8,7 @@ package big + + import ( + "encoding/binary" ++ "errors" + "fmt" + ) + +@@ -67,6 +68,9 @@ func (z *Float) GobDecode(buf []byte) error { + *z = Float{} + return nil + } ++ if len(buf) < 6 { ++ return errors.New("Float.GobDecode: buffer too small") ++ } + + if buf[0] != floatGobVersion { + return fmt.Errorf("Float.GobDecode: encoding version %d not supported", buf[0]) +@@ -83,6 +87,9 @@ func (z *Float) GobDecode(buf []byte) error { + z.prec = binary.BigEndian.Uint32(buf[2:]) + + if z.form == finite { ++ if len(buf) < 10 { ++ return errors.New("Float.GobDecode: buffer too small for finite form float") ++ } + z.exp = int32(binary.BigEndian.Uint32(buf[6:])) + z.mant = z.mant.setBytes(buf[10:]) + } +diff --git a/src/math/big/floatmarsh_test.go b/src/math/big/floatmarsh_test.go +index c056d78..401f45a 100644 +--- a/src/math/big/floatmarsh_test.go ++++ b/src/math/big/floatmarsh_test.go +@@ -137,3 +137,15 @@ func TestFloatJSONEncoding(t *testing.T) { + } + } + } ++ ++func TestFloatGobDecodeShortBuffer(t *testing.T) { ++ for _, tc := range [][]byte{ ++ []byte{0x1, 0x0, 0x0, 0x0}, ++ []byte{0x1, 0xfa, 0x0, 0x0, 0x0, 0x0}, ++ } { ++ err := NewFloat(0).GobDecode(tc) ++ if err == nil { ++ t.Error("expected GobDecode to return error for malformed input") ++ } ++ } ++} +diff --git a/src/math/big/ratmarsh.go b/src/math/big/ratmarsh.go +index fbc7b60..56102e8 100644 +--- a/src/math/big/ratmarsh.go ++++ b/src/math/big/ratmarsh.go +@@ -45,12 +45,18 @@ func (z *Rat) GobDecode(buf []byte) error { + *z = Rat{} + return nil + } ++ if len(buf) < 5 { ++ return errors.New("Rat.GobDecode: buffer too small") ++ } + b := buf[0] + if b>>1 != ratGobVersion { + return fmt.Errorf("Rat.GobDecode: encoding version %d not supported", b>>1) + } + const j = 1 + 4 + i := j + binary.BigEndian.Uint32(buf[j-4:j]) ++ if len(buf) < int(i) { ++ return errors.New("Rat.GobDecode: buffer too small") ++ } + z.a.neg = b&1 != 0 + z.a.abs = z.a.abs.setBytes(buf[j:i]) + z.b.abs = z.b.abs.setBytes(buf[i:]) +diff --git a/src/math/big/ratmarsh_test.go b/src/math/big/ratmarsh_test.go +index 351d109..55a9878 100644 +--- a/src/math/big/ratmarsh_test.go ++++ b/src/math/big/ratmarsh_test.go +@@ -123,3 +123,15 @@ func TestRatXMLEncoding(t *testing.T) { + } + } + } ++ ++func TestRatGobDecodeShortBuffer(t *testing.T) { ++ for _, tc := range [][]byte{ ++ []byte{0x2}, ++ []byte{0x2, 0x0, 0x0, 0x0, 0xff}, ++ } { ++ err := NewRat(1, 2).GobDecode(tc) ++ if err == nil { ++ t.Error("expected GobDecode to return error for malformed input") ++ } ++ } ++} +-- +2.25.1 + diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2022-41715.patch b/meta/recipes-devtools/go/go-1.14/CVE-2022-41715.patch new file mode 100644 index 0000000000..fac0ebe94c --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2022-41715.patch @@ -0,0 +1,271 @@ +From e9017c2416ad0ef642f5e0c2eab2dbf3cba4d997 Mon Sep 17 00:00:00 2001 +From: Russ Cox <rsc@golang.org> +Date: Wed, 28 Sep 2022 11:18:51 -0400 +Subject: [PATCH] [release-branch.go1.18] regexp: limit size of parsed regexps + +Set a 128 MB limit on the amount of space used by []syntax.Inst +in the compiled form corresponding to a given regexp. + +Also set a 128 MB limit on the rune storage in the *syntax.Regexp +tree itself. + +Thanks to Adam Korczynski (ADA Logics) and OSS-Fuzz for reporting this issue. + +Fixes CVE-2022-41715. +Updates #55949. +Fixes #55950. + +Change-Id: Ia656baed81564436368cf950e1c5409752f28e1b +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1592136 +TryBot-Result: Security TryBots <security-trybots@go-security-trybots.iam.gserviceaccount.com> +Reviewed-by: Damien Neil <dneil@google.com> +Run-TryBot: Roland Shoemaker <bracewell@google.com> +Reviewed-by: Julie Qiu <julieqiu@google.com> +Reviewed-on: https://go-review.googlesource.com/c/go/+/438501 +Run-TryBot: Carlos Amedee <carlos@golang.org> +Reviewed-by: Carlos Amedee <carlos@golang.org> +Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> +TryBot-Result: Gopher Robot <gobot@golang.org> +Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org> + +Upstream-Status: Backport [https://github.com/golang/go/commit/e9017c2416ad0ef642f5e0c2eab2dbf3cba4d997] +CVE: CVE-2022-41715 +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> + +--- + src/regexp/syntax/parse.go | 145 ++++++++++++++++++++++++++++++-- + src/regexp/syntax/parse_test.go | 13 +-- + 2 files changed, 148 insertions(+), 10 deletions(-) + +diff --git a/src/regexp/syntax/parse.go b/src/regexp/syntax/parse.go +index 55bd20d..60491d5 100644 +--- a/src/regexp/syntax/parse.go ++++ b/src/regexp/syntax/parse.go +@@ -90,15 +90,49 @@ const ( + // until we've allocated at least maxHeight Regexp structures. + const maxHeight = 1000 + ++// maxSize is the maximum size of a compiled regexp in Insts. ++// It too is somewhat arbitrarily chosen, but the idea is to be large enough ++// to allow significant regexps while at the same time small enough that ++// the compiled form will not take up too much memory. ++// 128 MB is enough for a 3.3 million Inst structures, which roughly ++// corresponds to a 3.3 MB regexp. ++const ( ++ maxSize = 128 << 20 / instSize ++ instSize = 5 * 8 // byte, 2 uint32, slice is 5 64-bit words ++) ++ ++// maxRunes is the maximum number of runes allowed in a regexp tree ++// counting the runes in all the nodes. ++// Ignoring character classes p.numRunes is always less than the length of the regexp. ++// Character classes can make it much larger: each \pL adds 1292 runes. ++// 128 MB is enough for 32M runes, which is over 26k \pL instances. ++// Note that repetitions do not make copies of the rune slices, ++// so \pL{1000} is only one rune slice, not 1000. ++// We could keep a cache of character classes we've seen, ++// so that all the \pL we see use the same rune list, ++// but that doesn't remove the problem entirely: ++// consider something like [\pL01234][\pL01235][\pL01236]...[\pL^&*()]. ++// And because the Rune slice is exposed directly in the Regexp, ++// there is not an opportunity to change the representation to allow ++// partial sharing between different character classes. ++// So the limit is the best we can do. ++const ( ++ maxRunes = 128 << 20 / runeSize ++ runeSize = 4 // rune is int32 ++) ++ + type parser struct { + flags Flags // parse mode flags + stack []*Regexp // stack of parsed expressions + free *Regexp + numCap int // number of capturing groups seen + wholeRegexp string +- tmpClass []rune // temporary char class work space +- numRegexp int // number of regexps allocated +- height map[*Regexp]int // regexp height for height limit check ++ tmpClass []rune // temporary char class work space ++ numRegexp int // number of regexps allocated ++ numRunes int // number of runes in char classes ++ repeats int64 // product of all repetitions seen ++ height map[*Regexp]int // regexp height, for height limit check ++ size map[*Regexp]int64 // regexp compiled size, for size limit check + } + + func (p *parser) newRegexp(op Op) *Regexp { +@@ -122,6 +156,104 @@ func (p *parser) reuse(re *Regexp) { + p.free = re + } + ++func (p *parser) checkLimits(re *Regexp) { ++ if p.numRunes > maxRunes { ++ panic(ErrInternalError) ++ } ++ p.checkSize(re) ++ p.checkHeight(re) ++} ++ ++func (p *parser) checkSize(re *Regexp) { ++ if p.size == nil { ++ // We haven't started tracking size yet. ++ // Do a relatively cheap check to see if we need to start. ++ // Maintain the product of all the repeats we've seen ++ // and don't track if the total number of regexp nodes ++ // we've seen times the repeat product is in budget. ++ if p.repeats == 0 { ++ p.repeats = 1 ++ } ++ if re.Op == OpRepeat { ++ n := re.Max ++ if n == -1 { ++ n = re.Min ++ } ++ if n <= 0 { ++ n = 1 ++ } ++ if int64(n) > maxSize/p.repeats { ++ p.repeats = maxSize ++ } else { ++ p.repeats *= int64(n) ++ } ++ } ++ if int64(p.numRegexp) < maxSize/p.repeats { ++ return ++ } ++ ++ // We need to start tracking size. ++ // Make the map and belatedly populate it ++ // with info about everything we've constructed so far. ++ p.size = make(map[*Regexp]int64) ++ for _, re := range p.stack { ++ p.checkSize(re) ++ } ++ } ++ ++ if p.calcSize(re, true) > maxSize { ++ panic(ErrInternalError) ++ } ++} ++ ++func (p *parser) calcSize(re *Regexp, force bool) int64 { ++ if !force { ++ if size, ok := p.size[re]; ok { ++ return size ++ } ++ } ++ ++ var size int64 ++ switch re.Op { ++ case OpLiteral: ++ size = int64(len(re.Rune)) ++ case OpCapture, OpStar: ++ // star can be 1+ or 2+; assume 2 pessimistically ++ size = 2 + p.calcSize(re.Sub[0], false) ++ case OpPlus, OpQuest: ++ size = 1 + p.calcSize(re.Sub[0], false) ++ case OpConcat: ++ for _, sub := range re.Sub { ++ size += p.calcSize(sub, false) ++ } ++ case OpAlternate: ++ for _, sub := range re.Sub { ++ size += p.calcSize(sub, false) ++ } ++ if len(re.Sub) > 1 { ++ size += int64(len(re.Sub)) - 1 ++ } ++ case OpRepeat: ++ sub := p.calcSize(re.Sub[0], false) ++ if re.Max == -1 { ++ if re.Min == 0 { ++ size = 2 + sub // x* ++ } else { ++ size = 1 + int64(re.Min)*sub // xxx+ ++ } ++ break ++ } ++ // x{2,5} = xx(x(x(x)?)?)? ++ size = int64(re.Max)*sub + int64(re.Max-re.Min) ++ } ++ ++ if size < 1 { ++ size = 1 ++ } ++ p.size[re] = size ++ return size ++} ++ + func (p *parser) checkHeight(re *Regexp) { + if p.numRegexp < maxHeight { + return +@@ -158,6 +290,7 @@ func (p *parser) calcHeight(re *Regexp, force bool) int { + + // push pushes the regexp re onto the parse stack and returns the regexp. + func (p *parser) push(re *Regexp) *Regexp { ++ p.numRunes += len(re.Rune) + if re.Op == OpCharClass && len(re.Rune) == 2 && re.Rune[0] == re.Rune[1] { + // Single rune. + if p.maybeConcat(re.Rune[0], p.flags&^FoldCase) { +@@ -189,7 +322,7 @@ func (p *parser) push(re *Regexp) *Regexp { + } + + p.stack = append(p.stack, re) +- p.checkHeight(re) ++ p.checkLimits(re) + return re + } + +@@ -305,7 +438,7 @@ func (p *parser) repeat(op Op, min, max int, before, after, lastRepeat string) ( + re.Sub = re.Sub0[:1] + re.Sub[0] = sub + p.stack[n-1] = re +- p.checkHeight(re) ++ p.checkLimits(re) + + if op == OpRepeat && (min >= 2 || max >= 2) && !repeatIsValid(re, 1000) { + return "", &Error{ErrInvalidRepeatSize, before[:len(before)-len(after)]} +@@ -509,6 +642,7 @@ func (p *parser) factor(sub []*Regexp) []*Regexp { + + for j := start; j < i; j++ { + sub[j] = p.removeLeadingString(sub[j], len(str)) ++ p.checkLimits(sub[j]) + } + suffix := p.collapse(sub[start:i], OpAlternate) // recurse + +@@ -566,6 +700,7 @@ func (p *parser) factor(sub []*Regexp) []*Regexp { + for j := start; j < i; j++ { + reuse := j != start // prefix came from sub[start] + sub[j] = p.removeLeadingRegexp(sub[j], reuse) ++ p.checkLimits(sub[j]) + } + suffix := p.collapse(sub[start:i], OpAlternate) // recurse + +diff --git a/src/regexp/syntax/parse_test.go b/src/regexp/syntax/parse_test.go +index 1ef6d8a..67e3c56 100644 +--- a/src/regexp/syntax/parse_test.go ++++ b/src/regexp/syntax/parse_test.go +@@ -484,12 +484,15 @@ var invalidRegexps = []string{ + `(?P<>a)`, + `[a-Z]`, + `(?i)[a-Z]`, +- `a{100000}`, +- `a{100000,}`, +- "((((((((((x{2}){2}){2}){2}){2}){2}){2}){2}){2}){2})", +- strings.Repeat("(", 1000) + strings.Repeat(")", 1000), +- strings.Repeat("(?:", 1000) + strings.Repeat(")*", 1000), + `\Q\E*`, ++ `a{100000}`, // too much repetition ++ `a{100000,}`, // too much repetition ++ "((((((((((x{2}){2}){2}){2}){2}){2}){2}){2}){2}){2})", // too much repetition ++ strings.Repeat("(", 1000) + strings.Repeat(")", 1000), // too deep ++ strings.Repeat("(?:", 1000) + strings.Repeat(")*", 1000), // too deep ++ "(" + strings.Repeat("(xx?)", 1000) + "){1000}", // too long ++ strings.Repeat("(xx?){1000}", 1000), // too long ++ strings.Repeat(`\pL`, 27000), // too many runes + } + + var onlyPerl = []string{ +-- +2.25.1 + diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2022-41717.patch b/meta/recipes-devtools/go/go-1.14/CVE-2022-41717.patch new file mode 100644 index 0000000000..8bf22ee4d4 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2022-41717.patch @@ -0,0 +1,75 @@ +From 618120c165669c00a1606505defea6ca755cdc27 Mon Sep 17 00:00:00 2001 +From: Damien Neil <dneil@google.com> +Date: Wed, 30 Nov 2022 16:46:33 -0500 +Subject: [PATCH] [release-branch.go1.19] net/http: update bundled + golang.org/x/net/http2 + +Disable cmd/internal/moddeps test, since this update includes PRIVATE +track fixes. + +For #56350. +For #57009. +Fixes CVE-2022-41717. + +Change-Id: I5c6ce546add81f361dcf0d5123fa4eaaf8f0a03b +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1663835 +Reviewed-by: Tatiana Bradley <tatianabradley@google.com> +Reviewed-by: Julie Qiu <julieqiu@google.com> +Reviewed-on: https://go-review.googlesource.com/c/go/+/455363 +TryBot-Result: Gopher Robot <gobot@golang.org> +Run-TryBot: Jenny Rakoczy <jenny@golang.org> +Reviewed-by: Michael Pratt <mpratt@google.com> + +Upstream-Status: Backport [https://github.com/golang/go/commit/618120c165669c00a1606505defea6ca755cdc27] +CVE-2022-41717 +Signed-off-by: Vivek Kumbhar <vkumbhar@mvista.com> +--- + src/net/http/h2_bundle.go | 18 +++++++++++------- + 1 file changed, 11 insertions(+), 7 deletions(-) + +diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go +index 83f2a72..cc03a62 100644 +--- a/src/net/http/h2_bundle.go ++++ b/src/net/http/h2_bundle.go +@@ -4096,6 +4096,7 @@ type http2serverConn struct { + headerTableSize uint32 + peerMaxHeaderListSize uint32 // zero means unknown (default) + canonHeader map[string]string // http2-lower-case -> Go-Canonical-Case ++ canonHeaderKeysSize int // canonHeader keys size in bytes + writingFrame bool // started writing a frame (on serve goroutine or separate) + writingFrameAsync bool // started a frame on its own goroutine but haven't heard back on wroteFrameCh + needsFrameFlush bool // last frame write wasn't a flush +@@ -4278,6 +4279,13 @@ func (sc *http2serverConn) condlogf(err error, format string, args ...interface{ + } + } + ++// maxCachedCanonicalHeadersKeysSize is an arbitrarily-chosen limit on the size ++// of the entries in the canonHeader cache. ++// This should be larger than the size of unique, uncommon header keys likely to ++// be sent by the peer, while not so high as to permit unreasonable memory usage ++// if the peer sends an unbounded number of unique header keys. ++const http2maxCachedCanonicalHeadersKeysSize = 2048 ++ + func (sc *http2serverConn) canonicalHeader(v string) string { + sc.serveG.check() + http2buildCommonHeaderMapsOnce() +@@ -4293,14 +4301,10 @@ func (sc *http2serverConn) canonicalHeader(v string) string { + sc.canonHeader = make(map[string]string) + } + cv = CanonicalHeaderKey(v) +- // maxCachedCanonicalHeaders is an arbitrarily-chosen limit on the number of +- // entries in the canonHeader cache. This should be larger than the number +- // of unique, uncommon header keys likely to be sent by the peer, while not +- // so high as to permit unreaasonable memory usage if the peer sends an unbounded +- // number of unique header keys. +- const maxCachedCanonicalHeaders = 32 +- if len(sc.canonHeader) < maxCachedCanonicalHeaders { ++ size := 100 + len(v)*2 // 100 bytes of map overhead + key + value ++ if sc.canonHeaderKeysSize+size <= http2maxCachedCanonicalHeadersKeysSize { + sc.canonHeader[v] = cv ++ sc.canonHeaderKeysSize += size + } + return cv + } +-- +2.30.2 diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2022-41722-1.patch b/meta/recipes-devtools/go/go-1.14/CVE-2022-41722-1.patch new file mode 100644 index 0000000000..f5bffd7a0b --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2022-41722-1.patch @@ -0,0 +1,53 @@ +From 94e0c36694fb044e81381d112fef3692de7cdf52 Mon Sep 17 00:00:00 2001 +From: Yasuhiro Matsumoto <mattn.jp@gmail.com> +Date: Fri, 22 Apr 2022 10:07:51 +0900 +Subject: [PATCH 1/2] path/filepath: do not remove prefix "." when following + path contains ":". + +Fixes #52476 + +Change-Id: I9eb72ac7dbccd6322d060291f31831dc389eb9bb +Reviewed-on: https://go-review.googlesource.com/c/go/+/401595 +Auto-Submit: Ian Lance Taylor <iant@google.com> +Reviewed-by: Alex Brainman <alex.brainman@gmail.com> +Run-TryBot: Ian Lance Taylor <iant@google.com> +Reviewed-by: Ian Lance Taylor <iant@google.com> +Reviewed-by: Damien Neil <dneil@google.com> +TryBot-Result: Gopher Robot <gobot@golang.org> + +Upstream-Status: Backport from https://github.com/golang/go/commit/9cd1818a7d019c02fa4898b3e45a323e35033290 +CVE: CVE-2022-41722 +Signed-off-by: Shubham Kulkarni <skulkarni@mvista.com> +--- + src/path/filepath/path.go | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/src/path/filepath/path.go b/src/path/filepath/path.go +index 26f1833..92dc090 100644 +--- a/src/path/filepath/path.go ++++ b/src/path/filepath/path.go +@@ -116,9 +116,21 @@ func Clean(path string) string { + case os.IsPathSeparator(path[r]): + // empty path element + r++ +- case path[r] == '.' && (r+1 == n || os.IsPathSeparator(path[r+1])): ++ case path[r] == '.' && r+1 == n: + // . element + r++ ++ case path[r] == '.' && os.IsPathSeparator(path[r+1]): ++ // ./ element ++ r++ ++ ++ for r < len(path) && os.IsPathSeparator(path[r]) { ++ r++ ++ } ++ if out.w == 0 && volumeNameLen(path[r:]) > 0 { ++ // When joining prefix "." and an absolute path on Windows, ++ // the prefix should not be removed. ++ out.append('.') ++ } + case path[r] == '.' && path[r+1] == '.' && (r+2 == n || os.IsPathSeparator(path[r+2])): + // .. element: remove to last separator + r += 2 +-- +2.7.4 diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2022-41722-2.patch b/meta/recipes-devtools/go/go-1.14/CVE-2022-41722-2.patch new file mode 100644 index 0000000000..e1f7a55581 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2022-41722-2.patch @@ -0,0 +1,104 @@ +From b8803cb711ae163b8e67897deb6cf8c49702227c Mon Sep 17 00:00:00 2001 +From: Damien Neil <dneil@google.com> +Date: Mon, 12 Dec 2022 16:43:37 -0800 +Subject: [PATCH 2/2] path/filepath: do not Clean("a/../c:/b") into c:\b on + Windows + +Do not permit Clean to convert a relative path into one starting +with a drive reference. This change causes Clean to insert a . +path element at the start of a path when the original path does not +start with a volume name, and the first path element would contain +a colon. + +This may introduce a spurious but harmless . path element under +some circumstances. For example, Clean("a/../b:/../c") becomes `.\c`. + +This reverts CL 401595, since the change here supersedes the one +in that CL. + +Thanks to RyotaK (https://twitter.com/ryotkak) for reporting this issue. + +Updates #57274 +Fixes #57276 +Fixes CVE-2022-41722 + +Change-Id: I837446285a03aa74c79d7642720e01f354c2ca17 +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1675249 +Reviewed-by: Roland Shoemaker <bracewell@google.com> +Run-TryBot: Damien Neil <dneil@google.com> +Reviewed-by: Julie Qiu <julieqiu@google.com> +TryBot-Result: Security TryBots <security-trybots@go-security-trybots.iam.gserviceaccount.com> +(cherry picked from commit 8ca37f4813ef2f64600c92b83f17c9f3ca6c03a5) +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1728944 +Run-TryBot: Roland Shoemaker <bracewell@google.com> +Reviewed-by: Tatiana Bradley <tatianabradley@google.com> +Reviewed-by: Damien Neil <dneil@google.com> +Reviewed-on: https://go-review.googlesource.com/c/go/+/468119 +Reviewed-by: Than McIntosh <thanm@google.com> +Run-TryBot: Michael Pratt <mpratt@google.com> +TryBot-Result: Gopher Robot <gobot@golang.org> +Auto-Submit: Michael Pratt <mpratt@google.com> + +Upstream-Status: Backport from https://github.com/golang/go/commit/bdf07c2e168baf736e4c057279ca12a4d674f18c +CVE: CVE-2022-41722 +Signed-off-by: Shubham Kulkarni <skulkarni@mvista.com> +--- + src/path/filepath/path.go | 27 ++++++++++++++------------- + 1 file changed, 14 insertions(+), 13 deletions(-) + +diff --git a/src/path/filepath/path.go b/src/path/filepath/path.go +index 92dc090..f0f095e 100644 +--- a/src/path/filepath/path.go ++++ b/src/path/filepath/path.go +@@ -14,6 +14,7 @@ package filepath + import ( + "errors" + "os" ++ "runtime" + "sort" + "strings" + ) +@@ -116,21 +117,9 @@ func Clean(path string) string { + case os.IsPathSeparator(path[r]): + // empty path element + r++ +- case path[r] == '.' && r+1 == n: ++ case path[r] == '.' && (r+1 == n || os.IsPathSeparator(path[r+1])): + // . element + r++ +- case path[r] == '.' && os.IsPathSeparator(path[r+1]): +- // ./ element +- r++ +- +- for r < len(path) && os.IsPathSeparator(path[r]) { +- r++ +- } +- if out.w == 0 && volumeNameLen(path[r:]) > 0 { +- // When joining prefix "." and an absolute path on Windows, +- // the prefix should not be removed. +- out.append('.') +- } + case path[r] == '.' && path[r+1] == '.' && (r+2 == n || os.IsPathSeparator(path[r+2])): + // .. element: remove to last separator + r += 2 +@@ -156,6 +145,18 @@ func Clean(path string) string { + if rooted && out.w != 1 || !rooted && out.w != 0 { + out.append(Separator) + } ++ // If a ':' appears in the path element at the start of a Windows path, ++ // insert a .\ at the beginning to avoid converting relative paths ++ // like a/../c: into c:. ++ if runtime.GOOS == "windows" && out.w == 0 && out.volLen == 0 && r != 0 { ++ for i := r; i < n && !os.IsPathSeparator(path[i]); i++ { ++ if path[i] == ':' { ++ out.append('.') ++ out.append(Separator) ++ break ++ } ++ } ++ } + // copy element + for ; r < n && !os.IsPathSeparator(path[r]); r++ { + out.append(path[r]) +-- +2.7.4 diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2022-41723.patch b/meta/recipes-devtools/go/go-1.14/CVE-2022-41723.patch new file mode 100644 index 0000000000..a93fa31dcd --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2022-41723.patch @@ -0,0 +1,156 @@ +From 451766789f646617157c725e20c955d4a9a70d4e Mon Sep 17 00:00:00 2001 +From: Roland Shoemaker <bracewell@google.com> +Date: Mon, 6 Feb 2023 10:03:44 -0800 +Subject: [PATCH] net/http: update bundled golang.org/x/net/http2 + +Disable cmd/internal/moddeps test, since this update includes PRIVATE +track fixes. + +Fixes CVE-2022-41723 +Fixes #58355 +Updates #57855 + +Change-Id: Ie870562a6f6e44e4e8f57db6a0dde1a41a2b090c +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1728939 +Reviewed-by: Damien Neil <dneil@google.com> +Reviewed-by: Julie Qiu <julieqiu@google.com> +Reviewed-by: Tatiana Bradley <tatianabradley@google.com> +Run-TryBot: Roland Shoemaker <bracewell@google.com> +Reviewed-on: https://go-review.googlesource.com/c/go/+/468118 +TryBot-Result: Gopher Robot <gobot@golang.org> +Run-TryBot: Michael Pratt <mpratt@google.com> +Auto-Submit: Michael Pratt <mpratt@google.com> +Reviewed-by: Than McIntosh <thanm@google.com> + +Upstream-Status: Backport [https://github.com/golang/go/commit/5c3e11bd0b5c0a86e5beffcd4339b86a902b21c3] +CVE: CVE-2022-41723 +Signed-off-by: Shubham Kulkarni <skulkarni@mvista.com> +--- + src/vendor/golang.org/x/net/http2/hpack/hpack.go | 79 +++++++++++++++--------- + 1 file changed, 49 insertions(+), 30 deletions(-) + +diff --git a/src/vendor/golang.org/x/net/http2/hpack/hpack.go b/src/vendor/golang.org/x/net/http2/hpack/hpack.go +index 85f18a2..02e80e3 100644 +--- a/src/vendor/golang.org/x/net/http2/hpack/hpack.go ++++ b/src/vendor/golang.org/x/net/http2/hpack/hpack.go +@@ -359,6 +359,7 @@ func (d *Decoder) parseFieldLiteral(n uint8, it indexType) error { + + var hf HeaderField + wantStr := d.emitEnabled || it.indexed() ++ var undecodedName undecodedString + if nameIdx > 0 { + ihf, ok := d.at(nameIdx) + if !ok { +@@ -366,15 +367,27 @@ func (d *Decoder) parseFieldLiteral(n uint8, it indexType) error { + } + hf.Name = ihf.Name + } else { +- hf.Name, buf, err = d.readString(buf, wantStr) ++ undecodedName, buf, err = d.readString(buf) + if err != nil { + return err + } + } +- hf.Value, buf, err = d.readString(buf, wantStr) ++ undecodedValue, buf, err := d.readString(buf) + if err != nil { + return err + } ++ if wantStr { ++ if nameIdx <= 0 { ++ hf.Name, err = d.decodeString(undecodedName) ++ if err != nil { ++ return err ++ } ++ } ++ hf.Value, err = d.decodeString(undecodedValue) ++ if err != nil { ++ return err ++ } ++ } + d.buf = buf + if it.indexed() { + d.dynTab.add(hf) +@@ -459,46 +472,52 @@ func readVarInt(n byte, p []byte) (i uint64, remain []byte, err error) { + return 0, origP, errNeedMore + } + +-// readString decodes an hpack string from p. ++// readString reads an hpack string from p. + // +-// wantStr is whether s will be used. If false, decompression and +-// []byte->string garbage are skipped if s will be ignored +-// anyway. This does mean that huffman decoding errors for non-indexed +-// strings past the MAX_HEADER_LIST_SIZE are ignored, but the server +-// is returning an error anyway, and because they're not indexed, the error +-// won't affect the decoding state. +-func (d *Decoder) readString(p []byte, wantStr bool) (s string, remain []byte, err error) { ++// It returns a reference to the encoded string data to permit deferring decode costs ++// until after the caller verifies all data is present. ++func (d *Decoder) readString(p []byte) (u undecodedString, remain []byte, err error) { + if len(p) == 0 { +- return "", p, errNeedMore ++ return u, p, errNeedMore + } + isHuff := p[0]&128 != 0 + strLen, p, err := readVarInt(7, p) + if err != nil { +- return "", p, err ++ return u, p, err + } + if d.maxStrLen != 0 && strLen > uint64(d.maxStrLen) { +- return "", nil, ErrStringLength ++ // Returning an error here means Huffman decoding errors ++ // for non-indexed strings past the maximum string length ++ // are ignored, but the server is returning an error anyway ++ // and because the string is not indexed the error will not ++ // affect the decoding state. ++ return u, nil, ErrStringLength + } + if uint64(len(p)) < strLen { +- return "", p, errNeedMore +- } +- if !isHuff { +- if wantStr { +- s = string(p[:strLen]) +- } +- return s, p[strLen:], nil ++ return u, p, errNeedMore + } ++ u.isHuff = isHuff ++ u.b = p[:strLen] ++ return u, p[strLen:], nil ++} + +- if wantStr { +- buf := bufPool.Get().(*bytes.Buffer) +- buf.Reset() // don't trust others +- defer bufPool.Put(buf) +- if err := huffmanDecode(buf, d.maxStrLen, p[:strLen]); err != nil { +- buf.Reset() +- return "", nil, err +- } ++type undecodedString struct { ++ isHuff bool ++ b []byte ++} ++ ++func (d *Decoder) decodeString(u undecodedString) (string, error) { ++ if !u.isHuff { ++ return string(u.b), nil ++ } ++ buf := bufPool.Get().(*bytes.Buffer) ++ buf.Reset() // don't trust others ++ var s string ++ err := huffmanDecode(buf, d.maxStrLen, u.b) ++ if err == nil { + s = buf.String() +- buf.Reset() // be nice to GC + } +- return s, p[strLen:], nil ++ buf.Reset() // be nice to GC ++ bufPool.Put(buf) ++ return s, err + } +-- +2.7.4 diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2022-41725-pre1.patch b/meta/recipes-devtools/go/go-1.14/CVE-2022-41725-pre1.patch new file mode 100644 index 0000000000..37ebc41947 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2022-41725-pre1.patch @@ -0,0 +1,85 @@ +From 874b3132a84cf76da6a48978826c04c380a37a50 Mon Sep 17 00:00:00 2001 +From: avivklas <avivklas@gmail.com> +Date: Fri, 7 Aug 2020 21:50:12 +0300 +Subject: [PATCH] mime/multipart: return overflow errors in Reader.ReadForm + +Updates Reader.ReadForm to check for overflow errors that may +result from a leeway addition of 10MiB to the input argument +maxMemory. + +Fixes #40430 + +Change-Id: I510b8966c95c51d04695ba9d08fcfe005fd11a5d +Reviewed-on: https://go-review.googlesource.com/c/go/+/247477 +Run-TryBot: Emmanuel Odeke <emm.odeke@gmail.com> +Trust: Cuong Manh Le <cuong.manhle.vn@gmail.com> +Trust: Emmanuel Odeke <emm.odeke@gmail.com> +TryBot-Result: Go Bot <gobot@golang.org> +Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com> + +Upstream-Status: Backport [https://github.com/golang/go/commit/874b3132a84cf76da6a48978826c04c380a37a50] +CVE: CVE-2022-41725 #Dependency Patch1 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + src/mime/multipart/formdata.go | 4 ++++ + src/mime/multipart/formdata_test.go | 18 ++++++++++++++++++ + 2 files changed, 22 insertions(+) + +diff --git a/src/mime/multipart/formdata.go b/src/mime/multipart/formdata.go +index 832d0ad693666..4eb31012941ac 100644 +--- a/src/mime/multipart/formdata.go ++++ b/src/mime/multipart/formdata.go +@@ -7,6 +7,7 @@ package multipart + import ( + "bytes" + "errors" ++ "fmt" + "io" + "io/ioutil" + "net/textproto" +@@ -41,6 +42,9 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { + + // Reserve an additional 10 MB for non-file parts. + maxValueBytes := maxMemory + int64(10<<20) ++ if maxValueBytes <= 0 { ++ return nil, fmt.Errorf("multipart: integer overflow from maxMemory(%d) + 10MiB for non-file parts", maxMemory) ++ } + for { + p, err := r.NextPart() + if err == io.EOF { +diff --git a/src/mime/multipart/formdata_test.go b/src/mime/multipart/formdata_test.go +index 7d756c8c244a0..7112e0d3727fe 100644 +--- a/src/mime/multipart/formdata_test.go ++++ b/src/mime/multipart/formdata_test.go +@@ -7,6 +7,7 @@ package multipart + import ( + "bytes" + "io" ++ "math" + "os" + "strings" + "testing" +@@ -52,6 +53,23 @@ func TestReadFormWithNamelessFile(t *testing.T) { + } + } + ++// Issue 40430: Ensure that we report integer overflows in additions of maxMemory, ++// instead of silently and subtly failing without indication. ++func TestReadFormMaxMemoryOverflow(t *testing.T) { ++ b := strings.NewReader(strings.ReplaceAll(messageWithTextContentType, "\n", "\r\n")) ++ r := NewReader(b, boundary) ++ f, err := r.ReadForm(math.MaxInt64) ++ if err == nil { ++ t.Fatal("Unexpected a non-nil error") ++ } ++ if f != nil { ++ t.Fatalf("Unexpected returned a non-nil form: %v\n", f) ++ } ++ if g, w := err.Error(), "integer overflow from maxMemory"; !strings.Contains(g, w) { ++ t.Errorf(`Error mismatch\n%q\ndid not contain\n%q`, g, w) ++ } ++} ++ + func TestReadFormWithTextContentType(t *testing.T) { + // From https://github.com/golang/go/issues/24041 + b := strings.NewReader(strings.ReplaceAll(messageWithTextContentType, "\n", "\r\n")) diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2022-41725-pre2.patch b/meta/recipes-devtools/go/go-1.14/CVE-2022-41725-pre2.patch new file mode 100644 index 0000000000..b951ee893e --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2022-41725-pre2.patch @@ -0,0 +1,97 @@ +From 4e5a313524da62600eb59dbf98624cfe946456f8 Mon Sep 17 00:00:00 2001 +From: Emmanuel T Odeke <emmanuel@orijtech.com> +Date: Tue, 20 Oct 2020 04:11:12 -0700 +Subject: [PATCH] net/http: test that ParseMultipartForm catches overflows + +Tests that if the combination of: +* HTTP multipart file payload size +* ParseMultipartForm's maxMemory parameter +* the internal leeway buffer size of 10MiB + +overflows, then we'll report an overflow instead of silently +passing. + +Reapplies and fixes CL 254977, which was reverted in CL 263658. + +The prior test lacked a res.Body.Close(), so fixed that and +added a leaked Transport check to verify correctness. + +Updates 40430. + +Change-Id: I3c0f7ef43d621f6eb00f07755f04f9f36c51f98f +Reviewed-on: https://go-review.googlesource.com/c/go/+/263817 +Run-TryBot: Emmanuel Odeke <emm.odeke@gmail.com> +TryBot-Result: Go Bot <gobot@golang.org> +Reviewed-by: Bryan C. Mills <bcmills@google.com> +Trust: Damien Neil <dneil@google.com> + +Upstream-Status: Backport [https://github.com/golang/go/commit/4e5a313524da62600eb59dbf98624cfe946456f8] +CVE: CVE-2022-41725 #Dependency Patch2 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + src/net/http/request_test.go | 45 ++++++++++++++++++++++++++++++++++++ + 1 file changed, 45 insertions(+) + +diff --git a/src/net/http/request_test.go b/src/net/http/request_test.go +index b4ef472e71229..19526b9ad791a 100644 +--- a/src/net/http/request_test.go ++++ b/src/net/http/request_test.go +@@ -13,6 +13,7 @@ import ( + "fmt" + "io" + "io/ioutil" ++ "math" + "mime/multipart" + . "net/http" + "net/http/httptest" +@@ -245,6 +246,50 @@ func TestParseMultipartForm(t *testing.T) { + } + } + ++// Issue #40430: Test that if maxMemory for ParseMultipartForm when combined with ++// the payload size and the internal leeway buffer size of 10MiB overflows, that we ++// correctly return an error. ++func TestMaxInt64ForMultipartFormMaxMemoryOverflow(t *testing.T) { ++ defer afterTest(t) ++ ++ payloadSize := 1 << 10 ++ cst := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) { ++ // The combination of: ++ // MaxInt64 + payloadSize + (internal spare of 10MiB) ++ // triggers the overflow. See issue https://golang.org/issue/40430/ ++ if err := req.ParseMultipartForm(math.MaxInt64); err != nil { ++ Error(rw, err.Error(), StatusBadRequest) ++ return ++ } ++ })) ++ defer cst.Close() ++ fBuf := new(bytes.Buffer) ++ mw := multipart.NewWriter(fBuf) ++ mf, err := mw.CreateFormFile("file", "myfile.txt") ++ if err != nil { ++ t.Fatal(err) ++ } ++ if _, err := mf.Write(bytes.Repeat([]byte("abc"), payloadSize)); err != nil { ++ t.Fatal(err) ++ } ++ if err := mw.Close(); err != nil { ++ t.Fatal(err) ++ } ++ req, err := NewRequest("POST", cst.URL, fBuf) ++ if err != nil { ++ t.Fatal(err) ++ } ++ req.Header.Set("Content-Type", mw.FormDataContentType()) ++ res, err := cst.Client().Do(req) ++ if err != nil { ++ t.Fatal(err) ++ } ++ res.Body.Close() ++ if g, w := res.StatusCode, StatusBadRequest; g != w { ++ t.Fatalf("Status code mismatch: got %d, want %d", g, w) ++ } ++} ++ + func TestRedirect_h1(t *testing.T) { testRedirect(t, h1Mode) } + func TestRedirect_h2(t *testing.T) { testRedirect(t, h2Mode) } + func testRedirect(t *testing.T, h2 bool) { diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2022-41725-pre3.patch b/meta/recipes-devtools/go/go-1.14/CVE-2022-41725-pre3.patch new file mode 100644 index 0000000000..767225b888 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2022-41725-pre3.patch @@ -0,0 +1,98 @@ +From 5246fa5e75b129a7dbd9722aa4de0cbaf7ceae43 Mon Sep 17 00:00:00 2001 +From: Russ Cox <rsc@golang.org> +Date: Thu, 3 Dec 2020 09:45:07 -0500 +Subject: [PATCH] mime/multipart: handle ReadForm(math.MaxInt64) better + +Returning an error about integer overflow is needlessly pedantic. +The meaning of ReadForm(MaxInt64) is easily understood +(accept a lot of data) and can be implemented. + +Fixes #40430. + +Change-Id: I8a522033dd9a2f9ad31dd2ad82cf08d553736ab9 +Reviewed-on: https://go-review.googlesource.com/c/go/+/275112 +Trust: Russ Cox <rsc@golang.org> +Run-TryBot: Russ Cox <rsc@golang.org> +TryBot-Result: Go Bot <gobot@golang.org> +Reviewed-by: Ian Lance Taylor <iant@golang.org> + +Upstream-Status: Backport [https://github.com/golang/go/commit/5246fa5e75b129a7dbd9722aa4de0cbaf7ceae43] +CVE: CVE-2022-41725 #Dependency Patch3 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + src/mime/multipart/formdata.go | 8 ++++++-- + src/mime/multipart/formdata_test.go | 14 +++++--------- + src/net/http/request_test.go | 2 +- + 3 files changed, 12 insertions(+), 12 deletions(-) + +diff --git a/src/mime/multipart/formdata.go b/src/mime/multipart/formdata.go +index 4eb31012941ac..9c42ea8c023b5 100644 +--- a/src/mime/multipart/formdata.go ++++ b/src/mime/multipart/formdata.go +@@ -7,9 +7,9 @@ package multipart + import ( + "bytes" + "errors" +- "fmt" + "io" + "io/ioutil" ++ "math" + "net/textproto" + "os" + ) +@@ -43,7 +43,11 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { + // Reserve an additional 10 MB for non-file parts. + maxValueBytes := maxMemory + int64(10<<20) + if maxValueBytes <= 0 { +- return nil, fmt.Errorf("multipart: integer overflow from maxMemory(%d) + 10MiB for non-file parts", maxMemory) ++ if maxMemory < 0 { ++ maxValueBytes = 0 ++ } else { ++ maxValueBytes = math.MaxInt64 ++ } + } + for { + p, err := r.NextPart() +diff --git a/src/mime/multipart/formdata_test.go b/src/mime/multipart/formdata_test.go +index 7112e0d3727fe..e3a3a3eae8e15 100644 +--- a/src/mime/multipart/formdata_test.go ++++ b/src/mime/multipart/formdata_test.go +@@ -53,20 +53,16 @@ func TestReadFormWithNamelessFile(t *testing.T) { + } + } + +-// Issue 40430: Ensure that we report integer overflows in additions of maxMemory, +-// instead of silently and subtly failing without indication. ++// Issue 40430: Handle ReadForm(math.MaxInt64) + func TestReadFormMaxMemoryOverflow(t *testing.T) { + b := strings.NewReader(strings.ReplaceAll(messageWithTextContentType, "\n", "\r\n")) + r := NewReader(b, boundary) + f, err := r.ReadForm(math.MaxInt64) +- if err == nil { +- t.Fatal("Unexpected a non-nil error") +- } +- if f != nil { +- t.Fatalf("Unexpected returned a non-nil form: %v\n", f) ++ if err != nil { ++ t.Fatalf("ReadForm(MaxInt64): %v", err) + } +- if g, w := err.Error(), "integer overflow from maxMemory"; !strings.Contains(g, w) { +- t.Errorf(`Error mismatch\n%q\ndid not contain\n%q`, g, w) ++ if f == nil { ++ t.Fatal("ReadForm(MaxInt64): missing form") + } + } + +diff --git a/src/net/http/request_test.go b/src/net/http/request_test.go +index 19526b9ad791a..689498e19d5dd 100644 +--- a/src/net/http/request_test.go ++++ b/src/net/http/request_test.go +@@ -285,7 +285,7 @@ func TestMaxInt64ForMultipartFormMaxMemoryOverflow(t *testing.T) { + t.Fatal(err) + } + res.Body.Close() +- if g, w := res.StatusCode, StatusBadRequest; g != w { ++ if g, w := res.StatusCode, StatusOK; g != w { + t.Fatalf("Status code mismatch: got %d, want %d", g, w) + } + } diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2022-41725.patch b/meta/recipes-devtools/go/go-1.14/CVE-2022-41725.patch new file mode 100644 index 0000000000..5f80c62b0b --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2022-41725.patch @@ -0,0 +1,660 @@ +From 5c55ac9bf1e5f779220294c843526536605f42ab Mon Sep 17 00:00:00 2001 +From: Damien Neil <dneil@google.com> +Date: Wed, 25 Jan 2023 09:27:01 -0800 +Subject: [PATCH] [release-branch.go1.19] mime/multipart: limit memory/inode consumption of ReadForm + +Reader.ReadForm is documented as storing "up to maxMemory bytes + 10MB" +in memory. Parsed forms can consume substantially more memory than +this limit, since ReadForm does not account for map entry overhead +and MIME headers. + +In addition, while the amount of disk memory consumed by ReadForm can +be constrained by limiting the size of the parsed input, ReadForm will +create one temporary file per form part stored on disk, potentially +consuming a large number of inodes. + +Update ReadForm's memory accounting to include part names, +MIME headers, and map entry overhead. + +Update ReadForm to store all on-disk file parts in a single +temporary file. + +Files returned by FileHeader.Open are documented as having a concrete +type of *os.File when a file is stored on disk. The change to use a +single temporary file for all parts means that this is no longer the +case when a form contains more than a single file part stored on disk. + +The previous behavior of storing each file part in a separate disk +file may be reenabled with GODEBUG=multipartfiles=distinct. + +Update Reader.NextPart and Reader.NextRawPart to set a 10MiB cap +on the size of MIME headers. + +Thanks to Jakob Ackermann (@das7pad) for reporting this issue. + +Updates #58006 +Fixes #58362 +Fixes CVE-2022-41725 + +Change-Id: Ibd780a6c4c83ac8bcfd3cbe344f042e9940f2eab +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1714276 +Reviewed-by: Julie Qiu <julieqiu@google.com> +TryBot-Result: Security TryBots <security-trybots@go-security-trybots.iam.gserviceaccount.com> +Reviewed-by: Roland Shoemaker <bracewell@google.com> +Run-TryBot: Damien Neil <dneil@google.com> +(cherry picked from commit ed4664330edcd91b24914c9371c377c132dbce8c) +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1728949 +Reviewed-by: Tatiana Bradley <tatianabradley@google.com> +Run-TryBot: Roland Shoemaker <bracewell@google.com> +Reviewed-by: Damien Neil <dneil@google.com> +Reviewed-on: https://go-review.googlesource.com/c/go/+/468116 +TryBot-Result: Gopher Robot <gobot@golang.org> +Reviewed-by: Than McIntosh <thanm@google.com> +Run-TryBot: Michael Pratt <mpratt@google.com> +Auto-Submit: Michael Pratt <mpratt@google.com> + +Upstream-Status: Backport [https://github.com/golang/go/commit/5c55ac9bf1e5f779220294c843526536605f42ab] +CVE: CVE-2022-41725 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + src/mime/multipart/formdata.go | 132 ++++++++++++++++++++----- + src/mime/multipart/formdata_test.go | 140 ++++++++++++++++++++++++++- + src/mime/multipart/multipart.go | 25 +++-- + src/mime/multipart/readmimeheader.go | 14 +++ + src/net/http/request_test.go | 2 +- + src/net/textproto/reader.go | 27 ++++++ + 6 files changed, 303 insertions(+), 37 deletions(-) + create mode 100644 src/mime/multipart/readmimeheader.go + +diff --git a/src/mime/multipart/formdata.go b/src/mime/multipart/formdata.go +index 9c42ea8..1eeb340 100644 +--- a/src/mime/multipart/formdata.go ++++ b/src/mime/multipart/formdata.go +@@ -7,6 +7,7 @@ package multipart + import ( + "bytes" + "errors" ++ "internal/godebug" + "io" + "io/ioutil" + "math" +@@ -34,23 +35,58 @@ func (r *Reader) ReadForm(maxMemory int64) (*Form, error) { + + func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { + form := &Form{make(map[string][]string), make(map[string][]*FileHeader)} ++ var ( ++ file *os.File ++ fileOff int64 ++ ) ++ numDiskFiles := 0 ++ multipartFiles := godebug.Get("multipartfiles") ++ combineFiles := multipartFiles != "distinct" + defer func() { ++ if file != nil { ++ if cerr := file.Close(); err == nil { ++ err = cerr ++ } ++ } ++ if combineFiles && numDiskFiles > 1 { ++ for _, fhs := range form.File { ++ for _, fh := range fhs { ++ fh.tmpshared = true ++ } ++ } ++ } + if err != nil { + form.RemoveAll() ++ if file != nil { ++ os.Remove(file.Name()) ++ } + } + }() + +- // Reserve an additional 10 MB for non-file parts. +- maxValueBytes := maxMemory + int64(10<<20) +- if maxValueBytes <= 0 { ++ // maxFileMemoryBytes is the maximum bytes of file data we will store in memory. ++ // Data past this limit is written to disk. ++ // This limit strictly applies to content, not metadata (filenames, MIME headers, etc.), ++ // since metadata is always stored in memory, not disk. ++ // ++ // maxMemoryBytes is the maximum bytes we will store in memory, including file content, ++ // non-file part values, metdata, and map entry overhead. ++ // ++ // We reserve an additional 10 MB in maxMemoryBytes for non-file data. ++ // ++ // The relationship between these parameters, as well as the overly-large and ++ // unconfigurable 10 MB added on to maxMemory, is unfortunate but difficult to change ++ // within the constraints of the API as documented. ++ maxFileMemoryBytes := maxMemory ++ maxMemoryBytes := maxMemory + int64(10<<20) ++ if maxMemoryBytes <= 0 { + if maxMemory < 0 { +- maxValueBytes = 0 ++ maxMemoryBytes = 0 + } else { +- maxValueBytes = math.MaxInt64 ++ maxMemoryBytes = math.MaxInt64 + } + } + for { +- p, err := r.NextPart() ++ p, err := r.nextPart(false, maxMemoryBytes) + if err == io.EOF { + break + } +@@ -64,16 +100,27 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { + } + filename := p.FileName() + ++ // Multiple values for the same key (one map entry, longer slice) are cheaper ++ // than the same number of values for different keys (many map entries), but ++ // using a consistent per-value cost for overhead is simpler. ++ maxMemoryBytes -= int64(len(name)) ++ maxMemoryBytes -= 100 // map overhead ++ if maxMemoryBytes < 0 { ++ // We can't actually take this path, since nextPart would already have ++ // rejected the MIME headers for being too large. Check anyway. ++ return nil, ErrMessageTooLarge ++ } ++ + var b bytes.Buffer + + if filename == "" { + // value, store as string in memory +- n, err := io.CopyN(&b, p, maxValueBytes+1) ++ n, err := io.CopyN(&b, p, maxMemoryBytes+1) + if err != nil && err != io.EOF { + return nil, err + } +- maxValueBytes -= n +- if maxValueBytes < 0 { ++ maxMemoryBytes -= n ++ if maxMemoryBytes < 0 { + return nil, ErrMessageTooLarge + } + form.Value[name] = append(form.Value[name], b.String()) +@@ -81,35 +128,45 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { + } + + // file, store in memory or on disk ++ maxMemoryBytes -= mimeHeaderSize(p.Header) ++ if maxMemoryBytes < 0 { ++ return nil, ErrMessageTooLarge ++ } + fh := &FileHeader{ + Filename: filename, + Header: p.Header, + } +- n, err := io.CopyN(&b, p, maxMemory+1) ++ n, err := io.CopyN(&b, p, maxFileMemoryBytes+1) + if err != nil && err != io.EOF { + return nil, err + } +- if n > maxMemory { +- // too big, write to disk and flush buffer +- file, err := ioutil.TempFile("", "multipart-") +- if err != nil { +- return nil, err ++ if n > maxFileMemoryBytes { ++ if file == nil { ++ file, err = ioutil.TempFile(r.tempDir, "multipart-") ++ if err != nil { ++ return nil, err ++ } + } ++ numDiskFiles++ + size, err := io.Copy(file, io.MultiReader(&b, p)) +- if cerr := file.Close(); err == nil { +- err = cerr +- } + if err != nil { +- os.Remove(file.Name()) + return nil, err + } + fh.tmpfile = file.Name() + fh.Size = size ++ fh.tmpoff = fileOff ++ fileOff += size ++ if !combineFiles { ++ if err := file.Close(); err != nil { ++ return nil, err ++ } ++ file = nil ++ } + } else { + fh.content = b.Bytes() + fh.Size = int64(len(fh.content)) +- maxMemory -= n +- maxValueBytes -= n ++ maxFileMemoryBytes -= n ++ maxMemoryBytes -= n + } + form.File[name] = append(form.File[name], fh) + } +@@ -117,6 +174,17 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { + return form, nil + } + ++func mimeHeaderSize(h textproto.MIMEHeader) (size int64) { ++ for k, vs := range h { ++ size += int64(len(k)) ++ size += 100 // map entry overhead ++ for _, v := range vs { ++ size += int64(len(v)) ++ } ++ } ++ return size ++} ++ + // Form is a parsed multipart form. + // Its File parts are stored either in memory or on disk, + // and are accessible via the *FileHeader's Open method. +@@ -134,7 +202,7 @@ func (f *Form) RemoveAll() error { + for _, fh := range fhs { + if fh.tmpfile != "" { + e := os.Remove(fh.tmpfile) +- if e != nil && err == nil { ++ if e != nil && !errors.Is(e, os.ErrNotExist) && err == nil { + err = e + } + } +@@ -149,15 +217,25 @@ type FileHeader struct { + Header textproto.MIMEHeader + Size int64 + +- content []byte +- tmpfile string ++ content []byte ++ tmpfile string ++ tmpoff int64 ++ tmpshared bool + } + + // Open opens and returns the FileHeader's associated File. + func (fh *FileHeader) Open() (File, error) { + if b := fh.content; b != nil { + r := io.NewSectionReader(bytes.NewReader(b), 0, int64(len(b))) +- return sectionReadCloser{r}, nil ++ return sectionReadCloser{r, nil}, nil ++ } ++ if fh.tmpshared { ++ f, err := os.Open(fh.tmpfile) ++ if err != nil { ++ return nil, err ++ } ++ r := io.NewSectionReader(f, fh.tmpoff, fh.Size) ++ return sectionReadCloser{r, f}, nil + } + return os.Open(fh.tmpfile) + } +@@ -176,8 +254,12 @@ type File interface { + + type sectionReadCloser struct { + *io.SectionReader ++ io.Closer + } + + func (rc sectionReadCloser) Close() error { ++ if rc.Closer != nil { ++ return rc.Closer.Close() ++ } + return nil + } +diff --git a/src/mime/multipart/formdata_test.go b/src/mime/multipart/formdata_test.go +index e3a3a3e..5cded71 100644 +--- a/src/mime/multipart/formdata_test.go ++++ b/src/mime/multipart/formdata_test.go +@@ -6,8 +6,10 @@ package multipart + + import ( + "bytes" ++ "fmt" + "io" + "math" ++ "net/textproto" + "os" + "strings" + "testing" +@@ -208,8 +210,8 @@ Content-Disposition: form-data; name="largetext" + maxMemory int64 + err error + }{ +- {"smaller", 50, nil}, +- {"exact-fit", 25, nil}, ++ {"smaller", 50 + int64(len("largetext")) + 100, nil}, ++ {"exact-fit", 25 + int64(len("largetext")) + 100, nil}, + {"too-large", 0, ErrMessageTooLarge}, + } + for _, tc := range testCases { +@@ -224,7 +226,7 @@ Content-Disposition: form-data; name="largetext" + defer f.RemoveAll() + } + if tc.err != err { +- t.Fatalf("ReadForm error - got: %v; expected: %v", tc.err, err) ++ t.Fatalf("ReadForm error - got: %v; expected: %v", err, tc.err) + } + if err == nil { + if g := f.Value["largetext"][0]; g != largeTextValue { +@@ -234,3 +236,135 @@ Content-Disposition: form-data; name="largetext" + }) + } + } ++ ++// TestReadForm_MetadataTooLarge verifies that we account for the size of field names, ++// MIME headers, and map entry overhead while limiting the memory consumption of parsed forms. ++func TestReadForm_MetadataTooLarge(t *testing.T) { ++ for _, test := range []struct { ++ name string ++ f func(*Writer) ++ }{{ ++ name: "large name", ++ f: func(fw *Writer) { ++ name := strings.Repeat("a", 10<<20) ++ w, _ := fw.CreateFormField(name) ++ w.Write([]byte("value")) ++ }, ++ }, { ++ name: "large MIME header", ++ f: func(fw *Writer) { ++ h := make(textproto.MIMEHeader) ++ h.Set("Content-Disposition", `form-data; name="a"`) ++ h.Set("X-Foo", strings.Repeat("a", 10<<20)) ++ w, _ := fw.CreatePart(h) ++ w.Write([]byte("value")) ++ }, ++ }, { ++ name: "many parts", ++ f: func(fw *Writer) { ++ for i := 0; i < 110000; i++ { ++ w, _ := fw.CreateFormField("f") ++ w.Write([]byte("v")) ++ } ++ }, ++ }} { ++ t.Run(test.name, func(t *testing.T) { ++ var buf bytes.Buffer ++ fw := NewWriter(&buf) ++ test.f(fw) ++ if err := fw.Close(); err != nil { ++ t.Fatal(err) ++ } ++ fr := NewReader(&buf, fw.Boundary()) ++ _, err := fr.ReadForm(0) ++ if err != ErrMessageTooLarge { ++ t.Errorf("fr.ReadForm() = %v, want ErrMessageTooLarge", err) ++ } ++ }) ++ } ++} ++ ++// TestReadForm_ManyFiles_Combined tests that a multipart form containing many files only ++// results in a single on-disk file. ++func TestReadForm_ManyFiles_Combined(t *testing.T) { ++ const distinct = false ++ testReadFormManyFiles(t, distinct) ++} ++ ++// TestReadForm_ManyFiles_Distinct tests that setting GODEBUG=multipartfiles=distinct ++// results in every file in a multipart form being placed in a distinct on-disk file. ++func TestReadForm_ManyFiles_Distinct(t *testing.T) { ++ t.Setenv("GODEBUG", "multipartfiles=distinct") ++ const distinct = true ++ testReadFormManyFiles(t, distinct) ++} ++ ++func testReadFormManyFiles(t *testing.T, distinct bool) { ++ var buf bytes.Buffer ++ fw := NewWriter(&buf) ++ const numFiles = 10 ++ for i := 0; i < numFiles; i++ { ++ name := fmt.Sprint(i) ++ w, err := fw.CreateFormFile(name, name) ++ if err != nil { ++ t.Fatal(err) ++ } ++ w.Write([]byte(name)) ++ } ++ if err := fw.Close(); err != nil { ++ t.Fatal(err) ++ } ++ fr := NewReader(&buf, fw.Boundary()) ++ fr.tempDir = t.TempDir() ++ form, err := fr.ReadForm(0) ++ if err != nil { ++ t.Fatal(err) ++ } ++ for i := 0; i < numFiles; i++ { ++ name := fmt.Sprint(i) ++ if got := len(form.File[name]); got != 1 { ++ t.Fatalf("form.File[%q] has %v entries, want 1", name, got) ++ } ++ fh := form.File[name][0] ++ file, err := fh.Open() ++ if err != nil { ++ t.Fatalf("form.File[%q].Open() = %v", name, err) ++ } ++ if distinct { ++ if _, ok := file.(*os.File); !ok { ++ t.Fatalf("form.File[%q].Open: %T, want *os.File", name, file) ++ } ++ } ++ got, err := io.ReadAll(file) ++ file.Close() ++ if string(got) != name || err != nil { ++ t.Fatalf("read form.File[%q]: %q, %v; want %q, nil", name, string(got), err, name) ++ } ++ } ++ dir, err := os.Open(fr.tempDir) ++ if err != nil { ++ t.Fatal(err) ++ } ++ defer dir.Close() ++ names, err := dir.Readdirnames(0) ++ if err != nil { ++ t.Fatal(err) ++ } ++ wantNames := 1 ++ if distinct { ++ wantNames = numFiles ++ } ++ if len(names) != wantNames { ++ t.Fatalf("temp dir contains %v files; want 1", len(names)) ++ } ++ if err := form.RemoveAll(); err != nil { ++ t.Fatalf("form.RemoveAll() = %v", err) ++ } ++ names, err = dir.Readdirnames(0) ++ if err != nil { ++ t.Fatal(err) ++ } ++ if len(names) != 0 { ++ t.Fatalf("temp dir contains %v files; want 0", len(names)) ++ } ++} +diff --git a/src/mime/multipart/multipart.go b/src/mime/multipart/multipart.go +index 1750300..958cef8 100644 +--- a/src/mime/multipart/multipart.go ++++ b/src/mime/multipart/multipart.go +@@ -121,12 +121,12 @@ func (r *stickyErrorReader) Read(p []byte) (n int, _ error) { + return n, r.err + } + +-func newPart(mr *Reader, rawPart bool) (*Part, error) { ++func newPart(mr *Reader, rawPart bool, maxMIMEHeaderSize int64) (*Part, error) { + bp := &Part{ + Header: make(map[string][]string), + mr: mr, + } +- if err := bp.populateHeaders(); err != nil { ++ if err := bp.populateHeaders(maxMIMEHeaderSize); err != nil { + return nil, err + } + bp.r = partReader{bp} +@@ -142,12 +142,16 @@ func newPart(mr *Reader, rawPart bool) (*Part, error) { + return bp, nil + } + +-func (bp *Part) populateHeaders() error { ++func (bp *Part) populateHeaders(maxMIMEHeaderSize int64) error { + r := textproto.NewReader(bp.mr.bufReader) +- header, err := r.ReadMIMEHeader() ++ header, err := readMIMEHeader(r, maxMIMEHeaderSize) + if err == nil { + bp.Header = header + } ++ // TODO: Add a distinguishable error to net/textproto. ++ if err != nil && err.Error() == "message too large" { ++ err = ErrMessageTooLarge ++ } + return err + } + +@@ -287,6 +291,7 @@ func (p *Part) Close() error { + // isn't supported. + type Reader struct { + bufReader *bufio.Reader ++ tempDir string // used in tests + + currentPart *Part + partsRead int +@@ -297,6 +302,10 @@ type Reader struct { + dashBoundary []byte // "--boundary" + } + ++// maxMIMEHeaderSize is the maximum size of a MIME header we will parse, ++// including header keys, values, and map overhead. ++const maxMIMEHeaderSize = 10 << 20 ++ + // NextPart returns the next part in the multipart or an error. + // When there are no more parts, the error io.EOF is returned. + // +@@ -304,7 +313,7 @@ type Reader struct { + // has a value of "quoted-printable", that header is instead + // hidden and the body is transparently decoded during Read calls. + func (r *Reader) NextPart() (*Part, error) { +- return r.nextPart(false) ++ return r.nextPart(false, maxMIMEHeaderSize) + } + + // NextRawPart returns the next part in the multipart or an error. +@@ -313,10 +322,10 @@ func (r *Reader) NextPart() (*Part, error) { + // Unlike NextPart, it does not have special handling for + // "Content-Transfer-Encoding: quoted-printable". + func (r *Reader) NextRawPart() (*Part, error) { +- return r.nextPart(true) ++ return r.nextPart(true, maxMIMEHeaderSize) + } + +-func (r *Reader) nextPart(rawPart bool) (*Part, error) { ++func (r *Reader) nextPart(rawPart bool, maxMIMEHeaderSize int64) (*Part, error) { + if r.currentPart != nil { + r.currentPart.Close() + } +@@ -341,7 +350,7 @@ func (r *Reader) nextPart(rawPart bool) (*Part, error) { + + if r.isBoundaryDelimiterLine(line) { + r.partsRead++ +- bp, err := newPart(r, rawPart) ++ bp, err := newPart(r, rawPart, maxMIMEHeaderSize) + if err != nil { + return nil, err + } +diff --git a/src/mime/multipart/readmimeheader.go b/src/mime/multipart/readmimeheader.go +new file mode 100644 +index 0000000..6836928 +--- /dev/null ++++ b/src/mime/multipart/readmimeheader.go +@@ -0,0 +1,14 @@ ++// Copyright 2023 The Go Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style ++// license that can be found in the LICENSE file. ++package multipart ++ ++import ( ++ "net/textproto" ++ _ "unsafe" // for go:linkname ++) ++ ++// readMIMEHeader is defined in package net/textproto. ++// ++//go:linkname readMIMEHeader net/textproto.readMIMEHeader ++func readMIMEHeader(r *textproto.Reader, lim int64) (textproto.MIMEHeader, error) +diff --git a/src/net/http/request_test.go b/src/net/http/request_test.go +index 94133ee..170d3f5 100644 +--- a/src/net/http/request_test.go ++++ b/src/net/http/request_test.go +@@ -962,7 +962,7 @@ func testMissingFile(t *testing.T, req *Request) { + t.Errorf("FormFile file = %v, want nil", f) + } + if fh != nil { +- t.Errorf("FormFile file header = %q, want nil", fh) ++ t.Errorf("FormFile file header = %v, want nil", fh) + } + if err != ErrMissingFile { + t.Errorf("FormFile err = %q, want ErrMissingFile", err) +diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go +index f63f5ec..96553fb 100644 +--- a/src/net/textproto/reader.go ++++ b/src/net/textproto/reader.go +@@ -7,9 +7,11 @@ package textproto + import ( + "bufio" + "bytes" ++ "errors" + "fmt" + "io" + "io/ioutil" ++ "math" + "strconv" + "strings" + "sync" +@@ -482,6 +484,12 @@ func (r *Reader) ReadDotLines() ([]string, error) { + // } + // + func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) { ++ return readMIMEHeader(r, math.MaxInt64) ++} ++ ++// readMIMEHeader is a version of ReadMIMEHeader which takes a limit on the header size. ++// It is called by the mime/multipart package. ++func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) { + // Avoid lots of small slice allocations later by allocating one + // large one ahead of time which we'll cut up into smaller + // slices. If this isn't big enough later, we allocate small ones. +@@ -525,6 +533,15 @@ func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) { + continue + } + ++ // backport 5c55ac9bf1e5f779220294c843526536605f42ab ++ // ++ // value is computed as ++ // value := string(bytes.TrimLeft(v, " \t")) ++ // ++ // in the original patch from 1.19. This relies on ++ // 'v' which does not exist in 1.14. We leave the ++ // 1.14 method unchanged. ++ + // Skip initial spaces in value. + i++ // skip colon + for i < len(kv) && (kv[i] == ' ' || kv[i] == '\t') { +@@ -533,6 +550,16 @@ func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) { + value := string(kv[i:]) + + vv := m[key] ++ if vv == nil { ++ lim -= int64(len(key)) ++ lim -= 100 // map entry overhead ++ } ++ lim -= int64(len(value)) ++ if lim < 0 { ++ // TODO: This should be a distinguishable error (ErrMessageTooLarge) ++ // to allow mime/multipart to detect it. ++ return m, errors.New("message too large") ++ } + if vv == nil && len(strs) > 0 { + // More than likely this will be a single-element key. + // Most headers aren't multi-valued. +-- +2.25.1 + diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-24534.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-24534.patch new file mode 100644 index 0000000000..d50db04bed --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-24534.patch @@ -0,0 +1,200 @@ +From d6759e7a059f4208f07aa781402841d7ddaaef96 Mon Sep 17 00:00:00 2001 +From: Damien Neil <dneil@google.com> +Date: Fri, 10 Mar 2023 14:21:05 -0800 +Subject: [PATCH] [release-branch.go1.19] net/textproto: avoid overpredicting + the number of MIME header keys + +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802452 +Run-TryBot: Damien Neil <dneil@google.com> +Reviewed-by: Roland Shoemaker <bracewell@google.com> +Reviewed-by: Julie Qiu <julieqiu@google.com> +(cherry picked from commit f739f080a72fd5b06d35c8e244165159645e2ed6) +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802393 +Reviewed-by: Damien Neil <dneil@google.com> +Run-TryBot: Roland Shoemaker <bracewell@google.com> +Change-Id: I675451438d619a9130360c56daf529559004903f +Reviewed-on: https://go-review.googlesource.com/c/go/+/481982 +Run-TryBot: Michael Knyszek <mknyszek@google.com> +TryBot-Result: Gopher Robot <gobot@golang.org> +Reviewed-by: Matthew Dempsky <mdempsky@google.com> +Auto-Submit: Michael Knyszek <mknyszek@google.com> + +Upstream-Status: Backport [https://github.com/golang/go/commit/d6759e7a059f4208f07aa781402841d7ddaaef96] +CVE: CVE-2023-24534 +Signed-off-by: Vivek Kumbhar <vkumbhar@mvista.com> +--- + src/bytes/bytes.go | 13 +++++++ + src/net/textproto/reader.go | 31 +++++++++++------ + src/net/textproto/reader_test.go | 59 ++++++++++++++++++++++++++++++++ + 3 files changed, 92 insertions(+), 11 deletions(-) + +diff --git a/src/bytes/bytes.go b/src/bytes/bytes.go +index e872cc2..1f0d760 100644 +--- a/src/bytes/bytes.go ++++ b/src/bytes/bytes.go +@@ -1078,6 +1078,19 @@ func Index(s, sep []byte) int { + return -1 + } + ++// Cut slices s around the first instance of sep, ++// returning the text before and after sep. ++// The found result reports whether sep appears in s. ++// If sep does not appear in s, cut returns s, nil, false. ++// ++// Cut returns slices of the original slice s, not copies. ++func Cut(s, sep []byte) (before, after []byte, found bool) { ++ if i := Index(s, sep); i >= 0 { ++ return s[:i], s[i+len(sep):], true ++ } ++ return s, nil, false ++} ++ + func indexRabinKarp(s, sep []byte) int { + // Rabin-Karp search + hashsep, pow := hashStr(sep) +diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go +index a505da9..8d547fe 100644 +--- a/src/net/textproto/reader.go ++++ b/src/net/textproto/reader.go +@@ -486,8 +487,11 @@ func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) { + // large one ahead of time which we'll cut up into smaller + // slices. If this isn't big enough later, we allocate small ones. + var strs []string +- hint := r.upcomingHeaderNewlines() ++ hint := r.upcomingHeaderKeys() + if hint > 0 { ++ if hint > 1000 { ++ hint = 1000 // set a cap to avoid overallocation ++ } + strs = make([]string, hint) + } + +@@ -562,9 +566,11 @@ func mustHaveFieldNameColon(line []byte) error { + return nil + } + +-// upcomingHeaderNewlines returns an approximation of the number of newlines ++var nl = []byte("\n") ++ ++// upcomingHeaderKeys returns an approximation of the number of keys + // that will be in this header. If it gets confused, it returns 0. +-func (r *Reader) upcomingHeaderNewlines() (n int) { ++func (r *Reader) upcomingHeaderKeys() (n int) { + // Try to determine the 'hint' size. + r.R.Peek(1) // force a buffer load if empty + s := r.R.Buffered() +@@ -572,17 +578,20 @@ func (r *Reader) upcomingHeaderNewlines() (n int) { + return + } + peek, _ := r.R.Peek(s) +- for len(peek) > 0 { +- i := bytes.IndexByte(peek, '\n') +- if i < 3 { +- // Not present (-1) or found within the next few bytes, +- // implying we're at the end ("\r\n\r\n" or "\n\n") +- return ++ for len(peek) > 0 && n < 1000 { ++ var line []byte ++ line, peek, _ = bytes.Cut(peek, nl) ++ if len(line) == 0 || (len(line) == 1 && line[0] == '\r') { ++ // Blank line separating headers from the body. ++ break ++ } ++ if line[0] == ' ' || line[0] == '\t' { ++ // Folded continuation of the previous line. ++ continue + } + n++ +- peek = peek[i+1:] + } +- return ++ return n + } + + // CanonicalMIMEHeaderKey returns the canonical format of the +diff --git a/src/net/textproto/reader_test.go b/src/net/textproto/reader_test.go +index 3124d43..3ae0de1 100644 +--- a/src/net/textproto/reader_test.go ++++ b/src/net/textproto/reader_test.go +@@ -9,6 +9,7 @@ import ( + "bytes" + "io" + "reflect" ++ "runtime" + "strings" + "testing" + ) +@@ -127,6 +128,42 @@ func TestReadMIMEHeaderSingle(t *testing.T) { + } + } + ++// TestReaderUpcomingHeaderKeys is testing an internal function, but it's very ++// difficult to test well via the external API. ++func TestReaderUpcomingHeaderKeys(t *testing.T) { ++ for _, test := range []struct { ++ input string ++ want int ++ }{{ ++ input: "", ++ want: 0, ++ }, { ++ input: "A: v", ++ want: 1, ++ }, { ++ input: "A: v\r\nB: v\r\n", ++ want: 2, ++ }, { ++ input: "A: v\nB: v\n", ++ want: 2, ++ }, { ++ input: "A: v\r\n continued\r\n still continued\r\nB: v\r\n\r\n", ++ want: 2, ++ }, { ++ input: "A: v\r\n\r\nB: v\r\nC: v\r\n", ++ want: 1, ++ }, { ++ input: "A: v" + strings.Repeat("\n", 1000), ++ want: 1, ++ }} { ++ r := reader(test.input) ++ got := r.upcomingHeaderKeys() ++ if test.want != got { ++ t.Fatalf("upcomingHeaderKeys(%q): %v; want %v", test.input, got, test.want) ++ } ++ } ++} ++ + func TestReadMIMEHeaderNoKey(t *testing.T) { + r := reader(": bar\ntest-1: 1\n\n") + m, err := r.ReadMIMEHeader() +@@ -223,6 +260,28 @@ func TestReadMIMEHeaderTrimContinued(t *testing.T) { + } + } + ++// Test that reading a header doesn't overallocate. Issue 58975. ++func TestReadMIMEHeaderAllocations(t *testing.T) { ++ var totalAlloc uint64 ++ const count = 200 ++ for i := 0; i < count; i++ { ++ r := reader("A: b\r\n\r\n" + strings.Repeat("\n", 4096)) ++ var m1, m2 runtime.MemStats ++ runtime.ReadMemStats(&m1) ++ _, err := r.ReadMIMEHeader() ++ if err != nil { ++ t.Fatalf("ReadMIMEHeader: %v", err) ++ } ++ runtime.ReadMemStats(&m2) ++ totalAlloc += m2.TotalAlloc - m1.TotalAlloc ++ } ++ // 32k is large and we actually allocate substantially less, ++ // but prior to the fix for #58975 we allocated ~400k in this case. ++ if got, want := totalAlloc/count, uint64(32768); got > want { ++ t.Fatalf("ReadMIMEHeader allocated %v bytes, want < %v", got, want) ++ } ++} ++ + type readResponseTest struct { + in string + inCode int +-- +2.25.1 diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-24536_1.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-24536_1.patch new file mode 100644 index 0000000000..39e1304fbd --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-24536_1.patch @@ -0,0 +1,134 @@ +From ef41a4e2face45e580c5836eaebd51629fc23f15 Mon Sep 17 00:00:00 2001 +From: Damien Neil <dneil@google.com> +Date: Thu, 16 Mar 2023 14:18:04 -0700 +Subject: [PATCH] [release-branch.go1.19] mime/multipart: avoid excessive copy + buffer allocations in ReadForm + +When copying form data to disk with io.Copy, +allocate only one copy buffer and reuse it rather than +creating two buffers per file (one from io.multiReader.WriteTo, +and a second one from os.File.ReadFrom). + +Thanks to Jakob Ackermann (@das7pad) for reporting this issue. + +For CVE-2023-24536 +For #59153 +For #59269 + +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802453 +Run-TryBot: Damien Neil <dneil@google.com> +Reviewed-by: Julie Qiu <julieqiu@google.com> +Reviewed-by: Roland Shoemaker <bracewell@google.com> +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802395 +Run-TryBot: Roland Shoemaker <bracewell@google.com> +Reviewed-by: Damien Neil <dneil@google.com> +Change-Id: Ie405470c92abffed3356913b37d813e982c96c8b +Reviewed-on: https://go-review.googlesource.com/c/go/+/481983 +Run-TryBot: Michael Knyszek <mknyszek@google.com> +TryBot-Result: Gopher Robot <gobot@golang.org> +Auto-Submit: Michael Knyszek <mknyszek@google.com> +Reviewed-by: Matthew Dempsky <mdempsky@google.com> + +Upstream-Status: Backport [https://github.com/golang/go/commit/ef41a4e2face45e580c5836eaebd51629fc23f15] +CVE: CVE-2023-24536 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + src/mime/multipart/formdata.go | 15 +++++++-- + src/mime/multipart/formdata_test.go | 49 +++++++++++++++++++++++++++++ + 2 files changed, 61 insertions(+), 3 deletions(-) + +diff --git a/src/mime/multipart/formdata.go b/src/mime/multipart/formdata.go +index a7d4ca97f0484..975dcb6b26db4 100644 +--- a/src/mime/multipart/formdata.go ++++ b/src/mime/multipart/formdata.go +@@ -84,6 +84,7 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { + maxMemoryBytes = math.MaxInt64 + } + } ++ var copyBuf []byte + for { + p, err := r.nextPart(false, maxMemoryBytes) + if err == io.EOF { +@@ -147,14 +148,22 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { + } + } + numDiskFiles++ +- size, err := io.Copy(file, io.MultiReader(&b, p)) ++ if _, err := file.Write(b.Bytes()); err != nil { ++ return nil, err ++ } ++ if copyBuf == nil { ++ copyBuf = make([]byte, 32*1024) // same buffer size as io.Copy uses ++ } ++ // os.File.ReadFrom will allocate its own copy buffer if we let io.Copy use it. ++ type writerOnly struct{ io.Writer } ++ remainingSize, err := io.CopyBuffer(writerOnly{file}, p, copyBuf) + if err != nil { + return nil, err + } + fh.tmpfile = file.Name() +- fh.Size = size ++ fh.Size = int64(b.Len()) + remainingSize + fh.tmpoff = fileOff +- fileOff += size ++ fileOff += fh.Size + if !combineFiles { + if err := file.Close(); err != nil { + return nil, err +diff --git a/src/mime/multipart/formdata_test.go b/src/mime/multipart/formdata_test.go +index 5cded7170c6b8..f5b56083b2377 100644 +--- a/src/mime/multipart/formdata_test.go ++++ b/src/mime/multipart/formdata_test.go +@@ -368,3 +368,52 @@ func testReadFormManyFiles(t *testing.T, distinct bool) { + t.Fatalf("temp dir contains %v files; want 0", len(names)) + } + } ++ ++func BenchmarkReadForm(b *testing.B) { ++ for _, test := range []struct { ++ name string ++ form func(fw *Writer, count int) ++ }{{ ++ name: "fields", ++ form: func(fw *Writer, count int) { ++ for i := 0; i < count; i++ { ++ w, _ := fw.CreateFormField(fmt.Sprintf("field%v", i)) ++ fmt.Fprintf(w, "value %v", i) ++ } ++ }, ++ }, { ++ name: "files", ++ form: func(fw *Writer, count int) { ++ for i := 0; i < count; i++ { ++ w, _ := fw.CreateFormFile(fmt.Sprintf("field%v", i), fmt.Sprintf("file%v", i)) ++ fmt.Fprintf(w, "value %v", i) ++ } ++ }, ++ }} { ++ b.Run(test.name, func(b *testing.B) { ++ for _, maxMemory := range []int64{ ++ 0, ++ 1 << 20, ++ } { ++ var buf bytes.Buffer ++ fw := NewWriter(&buf) ++ test.form(fw, 10) ++ if err := fw.Close(); err != nil { ++ b.Fatal(err) ++ } ++ b.Run(fmt.Sprintf("maxMemory=%v", maxMemory), func(b *testing.B) { ++ b.ReportAllocs() ++ for i := 0; i < b.N; i++ { ++ fr := NewReader(bytes.NewReader(buf.Bytes()), fw.Boundary()) ++ form, err := fr.ReadForm(maxMemory) ++ if err != nil { ++ b.Fatal(err) ++ } ++ form.RemoveAll() ++ } ++ ++ }) ++ } ++ }) ++ } ++} diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-24536_2.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-24536_2.patch new file mode 100644 index 0000000000..9ba5114c82 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-24536_2.patch @@ -0,0 +1,184 @@ +From 7a359a651c7ebdb29e0a1c03102fce793e9f58f0 Mon Sep 17 00:00:00 2001 +From: Damien Neil <dneil@google.com> +Date: Thu, 16 Mar 2023 16:56:12 -0700 +Subject: [PATCH] [release-branch.go1.19] net/textproto, mime/multipart: + improve accounting of non-file data + +For requests containing large numbers of small parts, +memory consumption of a parsed form could be about 250% +over the estimated size. + +When considering the size of parsed forms, account for the size of +FileHeader structs and increase the estimate of memory consumed by +map entries. + +Thanks to Jakob Ackermann (@das7pad) for reporting this issue. + +For CVE-2023-24536 +For #59153 +For #59269 + +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802454 +Run-TryBot: Damien Neil <dneil@google.com> +Reviewed-by: Roland Shoemaker <bracewell@google.com> +Reviewed-by: Julie Qiu <julieqiu@google.com> +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802396 +Run-TryBot: Roland Shoemaker <bracewell@google.com> +Reviewed-by: Damien Neil <dneil@google.com> +Change-Id: I31bc50e9346b4eee6fbe51a18c3c57230cc066db +Reviewed-on: https://go-review.googlesource.com/c/go/+/481984 +Reviewed-by: Matthew Dempsky <mdempsky@google.com> +Auto-Submit: Michael Knyszek <mknyszek@google.com> +TryBot-Result: Gopher Robot <gobot@golang.org> +Run-TryBot: Michael Knyszek <mknyszek@google.com> + +Upstream-Status: Backport [https://github.com/golang/go/commit/7a359a651c7ebdb29e0a1c03102fce793e9f58f0] +CVE: CVE-2023-24536 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + src/mime/multipart/formdata.go | 9 +++-- + src/mime/multipart/formdata_test.go | 55 ++++++++++++----------------- + src/net/textproto/reader.go | 8 ++++- + 3 files changed, 37 insertions(+), 35 deletions(-) + +diff --git a/src/mime/multipart/formdata.go b/src/mime/multipart/formdata.go +index 975dcb6b26db4..3f6ff697ca608 100644 +--- a/src/mime/multipart/formdata.go ++++ b/src/mime/multipart/formdata.go +@@ -103,8 +103,9 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { + // Multiple values for the same key (one map entry, longer slice) are cheaper + // than the same number of values for different keys (many map entries), but + // using a consistent per-value cost for overhead is simpler. ++ const mapEntryOverhead = 200 + maxMemoryBytes -= int64(len(name)) +- maxMemoryBytes -= 100 // map overhead ++ maxMemoryBytes -= mapEntryOverhead + if maxMemoryBytes < 0 { + // We can't actually take this path, since nextPart would already have + // rejected the MIME headers for being too large. Check anyway. +@@ -128,7 +129,10 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { + } + + // file, store in memory or on disk ++ const fileHeaderSize = 100 + maxMemoryBytes -= mimeHeaderSize(p.Header) ++ maxMemoryBytes -= mapEntryOverhead ++ maxMemoryBytes -= fileHeaderSize + if maxMemoryBytes < 0 { + return nil, ErrMessageTooLarge + } +@@ -183,9 +187,10 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { + } + + func mimeHeaderSize(h textproto.MIMEHeader) (size int64) { ++ size = 400 + for k, vs := range h { + size += int64(len(k)) +- size += 100 // map entry overhead ++ size += 200 // map entry overhead + for _, v := range vs { + size += int64(len(v)) + } +diff --git a/src/mime/multipart/formdata_test.go b/src/mime/multipart/formdata_test.go +index f5b56083b2377..8ed26e0c34081 100644 +--- a/src/mime/multipart/formdata_test.go ++++ b/src/mime/multipart/formdata_test.go +@@ -192,10 +192,10 @@ func (r *failOnReadAfterErrorReader) Read(p []byte) (n int, err error) { + // TestReadForm_NonFileMaxMemory asserts that the ReadForm maxMemory limit is applied + // while processing non-file form data as well as file form data. + func TestReadForm_NonFileMaxMemory(t *testing.T) { +- n := 10<<20 + 25 + if testing.Short() { +- n = 10<<10 + 25 ++ t.Skip("skipping in -short mode") + } ++ n := 10 << 20 + largeTextValue := strings.Repeat("1", n) + message := `--MyBoundary + Content-Disposition: form-data; name="largetext" +@@ -203,38 +203,29 @@ Content-Disposition: form-data; name="largetext" + ` + largeTextValue + ` + --MyBoundary-- + ` +- + testBody := strings.ReplaceAll(message, "\n", "\r\n") +- testCases := []struct { +- name string +- maxMemory int64 +- err error +- }{ +- {"smaller", 50 + int64(len("largetext")) + 100, nil}, +- {"exact-fit", 25 + int64(len("largetext")) + 100, nil}, +- {"too-large", 0, ErrMessageTooLarge}, +- } +- for _, tc := range testCases { +- t.Run(tc.name, func(t *testing.T) { +- if tc.maxMemory == 0 && testing.Short() { +- t.Skip("skipping in -short mode") +- } +- b := strings.NewReader(testBody) +- r := NewReader(b, boundary) +- f, err := r.ReadForm(tc.maxMemory) +- if err == nil { +- defer f.RemoveAll() +- } +- if tc.err != err { +- t.Fatalf("ReadForm error - got: %v; expected: %v", err, tc.err) +- } +- if err == nil { +- if g := f.Value["largetext"][0]; g != largeTextValue { +- t.Errorf("largetext mismatch: got size: %v, expected size: %v", len(g), len(largeTextValue)) +- } +- } +- }) ++ // Try parsing the form with increasing maxMemory values. ++ // Changes in how we account for non-file form data may cause the exact point ++ // where we change from rejecting the form as too large to accepting it to vary, ++ // but we should see both successes and failures. ++ const failWhenMaxMemoryLessThan = 128 ++ for maxMemory := int64(0); maxMemory < failWhenMaxMemoryLessThan*2; maxMemory += 16 { ++ b := strings.NewReader(testBody) ++ r := NewReader(b, boundary) ++ f, err := r.ReadForm(maxMemory) ++ if err != nil { ++ continue ++ } ++ if g := f.Value["largetext"][0]; g != largeTextValue { ++ t.Errorf("largetext mismatch: got size: %v, expected size: %v", len(g), len(largeTextValue)) ++ } ++ f.RemoveAll() ++ if maxMemory < failWhenMaxMemoryLessThan { ++ t.Errorf("ReadForm(%v): no error, expect to hit memory limit when maxMemory < %v", maxMemory, failWhenMaxMemoryLessThan) ++ } ++ return + } ++ t.Errorf("ReadForm(x) failed for x < 1024, expect success") + } + + // TestReadForm_MetadataTooLarge verifies that we account for the size of field names, +diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go +index 9a21777df8be0..c1284fde25eb7 100644 +--- a/src/net/textproto/reader.go ++++ b/src/net/textproto/reader.go +@@ -503,6 +503,12 @@ func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) { + + m := make(MIMEHeader, hint) + ++ // Account for 400 bytes of overhead for the MIMEHeader, plus 200 bytes per entry. ++ // Benchmarking map creation as of go1.20, a one-entry MIMEHeader is 416 bytes and large ++ // MIMEHeaders average about 200 bytes per entry. ++ lim -= 400 ++ const mapEntryOverhead = 200 ++ + // The first line cannot start with a leading space. + if buf, err := r.R.Peek(1); err == nil && (buf[0] == ' ' || buf[0] == '\t') { + line, err := r.readLineSlice() +@@ -538,7 +544,7 @@ func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) { + vv := m[key] + if vv == nil { + lim -= int64(len(key)) +- lim -= 100 // map entry overhead ++ lim -= mapEntryOverhead + } + lim -= int64(len(value)) + if lim < 0 { diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-24536_3.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-24536_3.patch new file mode 100644 index 0000000000..58c0a484ee --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-24536_3.patch @@ -0,0 +1,349 @@ +From 7917b5f31204528ea72e0629f0b7d52b35b27538 Mon Sep 17 00:00:00 2001 +From: Damien Neil <dneil@google.com> +Date: Mon, 20 Mar 2023 10:43:19 -0700 +Subject: [PATCH] [release-branch.go1.19] mime/multipart: limit parsed mime message sizes + +The parsed forms of MIME headers and multipart forms can consume +substantially more memory than the size of the input data. +A malicious input containing a very large number of headers or +form parts can cause excessively large memory allocations. + +Set limits on the size of MIME data: + +Reader.NextPart and Reader.NextRawPart limit the the number +of headers in a part to 10000. + +Reader.ReadForm limits the total number of headers in all +FileHeaders to 10000. + +Both of these limits may be set with with +GODEBUG=multipartmaxheaders=<values>. + +Reader.ReadForm limits the number of parts in a form to 1000. +This limit may be set with GODEBUG=multipartmaxparts=<value>. + +Thanks for Jakob Ackermann (@das7pad) for reporting this issue. + +For CVE-2023-24536 +For #59153 +For #59269 + +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802455 +Run-TryBot: Damien Neil <dneil@google.com> +Reviewed-by: Roland Shoemaker <bracewell@google.com> +Reviewed-by: Julie Qiu <julieqiu@google.com> +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1801087 +Reviewed-by: Damien Neil <dneil@google.com> +Run-TryBot: Roland Shoemaker <bracewell@google.com> +Change-Id: If134890d75f0d95c681d67234daf191ba08e6424 +Reviewed-on: https://go-review.googlesource.com/c/go/+/481985 +Run-TryBot: Michael Knyszek <mknyszek@google.com> +Auto-Submit: Michael Knyszek <mknyszek@google.com> +TryBot-Result: Gopher Robot <gobot@golang.org> +Reviewed-by: Matthew Dempsky <mdempsky@google.com> + +Upstream-Status: Backport [https://github.com/golang/go/commit/7917b5f31204528ea72e0629f0b7d52b35b27538] +CVE: CVE-2023-24536 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + src/mime/multipart/formdata.go | 19 ++++++++- + src/mime/multipart/formdata_test.go | 61 ++++++++++++++++++++++++++++ + src/mime/multipart/multipart.go | 31 ++++++++++---- + src/mime/multipart/readmimeheader.go | 2 +- + src/net/textproto/reader.go | 19 +++++---- + 5 files changed, 115 insertions(+), 17 deletions(-) + +diff --git a/src/mime/multipart/formdata.go b/src/mime/multipart/formdata.go +index 216cccb..0b508ae 100644 +--- a/src/mime/multipart/formdata.go ++++ b/src/mime/multipart/formdata.go +@@ -13,6 +13,7 @@ import ( + "math" + "net/textproto" + "os" ++ "strconv" + ) + + // ErrMessageTooLarge is returned by ReadForm if the message form +@@ -42,6 +43,15 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { + numDiskFiles := 0 + multipartFiles := godebug.Get("multipartfiles") + combineFiles := multipartFiles != "distinct" ++ maxParts := 1000 ++ multipartMaxParts := godebug.Get("multipartmaxparts") ++ if multipartMaxParts != "" { ++ if v, err := strconv.Atoi(multipartMaxParts); err == nil && v >= 0 { ++ maxParts = v ++ } ++ } ++ maxHeaders := maxMIMEHeaders() ++ + defer func() { + if file != nil { + if cerr := file.Close(); err == nil { +@@ -87,13 +97,17 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { + } + var copyBuf []byte + for { +- p, err := r.nextPart(false, maxMemoryBytes) ++ p, err := r.nextPart(false, maxMemoryBytes, maxHeaders) + if err == io.EOF { + break + } + if err != nil { + return nil, err + } ++ if maxParts <= 0 { ++ return nil, ErrMessageTooLarge ++ } ++ maxParts-- + + name := p.FormName() + if name == "" { +@@ -137,6 +151,9 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { + if maxMemoryBytes < 0 { + return nil, ErrMessageTooLarge + } ++ for _, v := range p.Header { ++ maxHeaders -= int64(len(v)) ++ } + fh := &FileHeader{ + Filename: filename, + Header: p.Header, +diff --git a/src/mime/multipart/formdata_test.go b/src/mime/multipart/formdata_test.go +index 8ed26e0..c78eeb7 100644 +--- a/src/mime/multipart/formdata_test.go ++++ b/src/mime/multipart/formdata_test.go +@@ -360,6 +360,67 @@ func testReadFormManyFiles(t *testing.T, distinct bool) { + } + } + ++func TestReadFormLimits(t *testing.T) { ++ for _, test := range []struct { ++ values int ++ files int ++ extraKeysPerFile int ++ wantErr error ++ godebug string ++ }{ ++ {values: 1000}, ++ {values: 1001, wantErr: ErrMessageTooLarge}, ++ {values: 500, files: 500}, ++ {values: 501, files: 500, wantErr: ErrMessageTooLarge}, ++ {files: 1000}, ++ {files: 1001, wantErr: ErrMessageTooLarge}, ++ {files: 1, extraKeysPerFile: 9998}, // plus Content-Disposition and Content-Type ++ {files: 1, extraKeysPerFile: 10000, wantErr: ErrMessageTooLarge}, ++ {godebug: "multipartmaxparts=100", values: 100}, ++ {godebug: "multipartmaxparts=100", values: 101, wantErr: ErrMessageTooLarge}, ++ {godebug: "multipartmaxheaders=100", files: 2, extraKeysPerFile: 48}, ++ {godebug: "multipartmaxheaders=100", files: 2, extraKeysPerFile: 50, wantErr: ErrMessageTooLarge}, ++ } { ++ name := fmt.Sprintf("values=%v/files=%v/extraKeysPerFile=%v", test.values, test.files, test.extraKeysPerFile) ++ if test.godebug != "" { ++ name += fmt.Sprintf("/godebug=%v", test.godebug) ++ } ++ t.Run(name, func(t *testing.T) { ++ if test.godebug != "" { ++ t.Setenv("GODEBUG", test.godebug) ++ } ++ var buf bytes.Buffer ++ fw := NewWriter(&buf) ++ for i := 0; i < test.values; i++ { ++ w, _ := fw.CreateFormField(fmt.Sprintf("field%v", i)) ++ fmt.Fprintf(w, "value %v", i) ++ } ++ for i := 0; i < test.files; i++ { ++ h := make(textproto.MIMEHeader) ++ h.Set("Content-Disposition", ++ fmt.Sprintf(`form-data; name="file%v"; filename="file%v"`, i, i)) ++ h.Set("Content-Type", "application/octet-stream") ++ for j := 0; j < test.extraKeysPerFile; j++ { ++ h.Set(fmt.Sprintf("k%v", j), "v") ++ } ++ w, _ := fw.CreatePart(h) ++ fmt.Fprintf(w, "value %v", i) ++ } ++ if err := fw.Close(); err != nil { ++ t.Fatal(err) ++ } ++ fr := NewReader(bytes.NewReader(buf.Bytes()), fw.Boundary()) ++ form, err := fr.ReadForm(1 << 10) ++ if err == nil { ++ defer form.RemoveAll() ++ } ++ if err != test.wantErr { ++ t.Errorf("ReadForm = %v, want %v", err, test.wantErr) ++ } ++ }) ++ } ++} ++ + func BenchmarkReadForm(b *testing.B) { + for _, test := range []struct { + name string +diff --git a/src/mime/multipart/multipart.go b/src/mime/multipart/multipart.go +index 958cef8..94464a8 100644 +--- a/src/mime/multipart/multipart.go ++++ b/src/mime/multipart/multipart.go +@@ -16,11 +16,13 @@ import ( + "bufio" + "bytes" + "fmt" ++ "internal/godebug" + "io" + "io/ioutil" + "mime" + "mime/quotedprintable" + "net/textproto" ++ "strconv" + "strings" + ) + +@@ -121,12 +123,12 @@ func (r *stickyErrorReader) Read(p []byte) (n int, _ error) { + return n, r.err + } + +-func newPart(mr *Reader, rawPart bool, maxMIMEHeaderSize int64) (*Part, error) { ++func newPart(mr *Reader, rawPart bool, maxMIMEHeaderSize, maxMIMEHeaders int64) (*Part, error) { + bp := &Part{ + Header: make(map[string][]string), + mr: mr, + } +- if err := bp.populateHeaders(maxMIMEHeaderSize); err != nil { ++ if err := bp.populateHeaders(maxMIMEHeaderSize, maxMIMEHeaders); err != nil { + return nil, err + } + bp.r = partReader{bp} +@@ -142,9 +144,9 @@ func newPart(mr *Reader, rawPart bool, maxMIMEHeaderSize int64) (*Part, error) { + return bp, nil + } + +-func (bp *Part) populateHeaders(maxMIMEHeaderSize int64) error { ++func (bp *Part) populateHeaders(maxMIMEHeaderSize, maxMIMEHeaders int64) error { + r := textproto.NewReader(bp.mr.bufReader) +- header, err := readMIMEHeader(r, maxMIMEHeaderSize) ++ header, err := readMIMEHeader(r, maxMIMEHeaderSize, maxMIMEHeaders) + if err == nil { + bp.Header = header + } +@@ -306,6 +308,19 @@ type Reader struct { + // including header keys, values, and map overhead. + const maxMIMEHeaderSize = 10 << 20 + ++func maxMIMEHeaders() int64 { ++ // multipartMaxHeaders is the maximum number of header entries NextPart will return, ++ // as well as the maximum combined total of header entries Reader.ReadForm will return ++ // in FileHeaders. ++ multipartMaxHeaders := godebug.Get("multipartmaxheaders") ++ if multipartMaxHeaders != "" { ++ if v, err := strconv.ParseInt(multipartMaxHeaders, 10, 64); err == nil && v >= 0 { ++ return v ++ } ++ } ++ return 10000 ++} ++ + // NextPart returns the next part in the multipart or an error. + // When there are no more parts, the error io.EOF is returned. + // +@@ -313,7 +328,7 @@ const maxMIMEHeaderSize = 10 << 20 + // has a value of "quoted-printable", that header is instead + // hidden and the body is transparently decoded during Read calls. + func (r *Reader) NextPart() (*Part, error) { +- return r.nextPart(false, maxMIMEHeaderSize) ++ return r.nextPart(false, maxMIMEHeaderSize, maxMIMEHeaders()) + } + + // NextRawPart returns the next part in the multipart or an error. +@@ -322,10 +337,10 @@ func (r *Reader) NextPart() (*Part, error) { + // Unlike NextPart, it does not have special handling for + // "Content-Transfer-Encoding: quoted-printable". + func (r *Reader) NextRawPart() (*Part, error) { +- return r.nextPart(true, maxMIMEHeaderSize) ++ return r.nextPart(true, maxMIMEHeaderSize, maxMIMEHeaders()) + } + +-func (r *Reader) nextPart(rawPart bool, maxMIMEHeaderSize int64) (*Part, error) { ++func (r *Reader) nextPart(rawPart bool, maxMIMEHeaderSize, maxMIMEHeaders int64) (*Part, error) { + if r.currentPart != nil { + r.currentPart.Close() + } +@@ -350,7 +365,7 @@ func (r *Reader) nextPart(rawPart bool, maxMIMEHeaderSize int64) (*Part, error) + + if r.isBoundaryDelimiterLine(line) { + r.partsRead++ +- bp, err := newPart(r, rawPart, maxMIMEHeaderSize) ++ bp, err := newPart(r, rawPart, maxMIMEHeaderSize, maxMIMEHeaders) + if err != nil { + return nil, err + } +diff --git a/src/mime/multipart/readmimeheader.go b/src/mime/multipart/readmimeheader.go +index 6836928..25aa6e2 100644 +--- a/src/mime/multipart/readmimeheader.go ++++ b/src/mime/multipart/readmimeheader.go +@@ -11,4 +11,4 @@ import ( + // readMIMEHeader is defined in package net/textproto. + // + //go:linkname readMIMEHeader net/textproto.readMIMEHeader +-func readMIMEHeader(r *textproto.Reader, lim int64) (textproto.MIMEHeader, error) ++func readMIMEHeader(r *textproto.Reader, maxMemory, maxHeaders int64) (textproto.MIMEHeader, error) +diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go +index 1c79f0a..ad2d777 100644 +--- a/src/net/textproto/reader.go ++++ b/src/net/textproto/reader.go +@@ -484,12 +484,12 @@ func (r *Reader) ReadDotLines() ([]string, error) { + // } + // + func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) { +- return readMIMEHeader(r, math.MaxInt64) ++ return readMIMEHeader(r, math.MaxInt64, math.MaxInt64) + } + + // readMIMEHeader is a version of ReadMIMEHeader which takes a limit on the header size. + // It is called by the mime/multipart package. +-func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) { ++func readMIMEHeader(r *Reader, maxMemory, maxHeaders int64) (MIMEHeader, error) { + // Avoid lots of small slice allocations later by allocating one + // large one ahead of time which we'll cut up into smaller + // slices. If this isn't big enough later, we allocate small ones. +@@ -507,7 +507,7 @@ func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) { + // Account for 400 bytes of overhead for the MIMEHeader, plus 200 bytes per entry. + // Benchmarking map creation as of go1.20, a one-entry MIMEHeader is 416 bytes and large + // MIMEHeaders average about 200 bytes per entry. +- lim -= 400 ++ maxMemory -= 400 + const mapEntryOverhead = 200 + + // The first line cannot start with a leading space. +@@ -539,6 +539,11 @@ func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) { + continue + } + ++ maxHeaders-- ++ if maxHeaders < 0 { ++ return nil, errors.New("message too large") ++ } ++ + // backport 5c55ac9bf1e5f779220294c843526536605f42ab + // + // value is computed as +@@ -557,11 +562,11 @@ func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) { + + vv := m[key] + if vv == nil { +- lim -= int64(len(key)) +- lim -= mapEntryOverhead ++ maxMemory -= int64(len(key)) ++ maxMemory -= mapEntryOverhead + } +- lim -= int64(len(value)) +- if lim < 0 { ++ maxMemory -= int64(len(value)) ++ if maxMemory < 0 { + // TODO: This should be a distinguishable error (ErrMessageTooLarge) + // to allow mime/multipart to detect it. + return m, errors.New("message too large") +-- +2.25.1 + diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-24537.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-24537.patch new file mode 100644 index 0000000000..e04b717fc1 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-24537.patch @@ -0,0 +1,76 @@ +From bf8c7c575c8a552d9d79deb29e80854dc88528d0 Mon Sep 17 00:00:00 2001 +From: Damien Neil <dneil@google.com> +Date: Mon, 20 Mar 2023 10:43:19 -0700 +Subject: [PATCH] [release-branch.go1.20] mime/multipart: limit parsed mime + message sizes + +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802456 +Reviewed-by: Julie Qiu <julieqiu@google.com> +Reviewed-by: Roland Shoemaker <bracewell@google.com> +Run-TryBot: Damien Neil <dneil@google.com> +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802611 +Reviewed-by: Damien Neil <dneil@google.com> +Change-Id: Ifdfa192d54f722d781a4d8c5f35b5fb72d122168 +Reviewed-on: https://go-review.googlesource.com/c/go/+/481986 +Reviewed-by: Matthew Dempsky <mdempsky@google.com> +TryBot-Result: Gopher Robot <gobot@golang.org> +Run-TryBot: Michael Knyszek <mknyszek@google.com> +Auto-Submit: Michael Knyszek <mknyszek@google.com> + +Upstream-Status: Backport [https://github.com/golang/go/commit/126a1d02da82f93ede7ce0bd8d3c51ef627f2104] +CVE: CVE-2023-24537 +Signed-off-by: Vivek Kumbhar <vkumbhar@mvista.com> +--- + src/go/parser/parser_test.go | 16 ++++++++++++++++ + src/go/scanner/scanner.go | 5 ++++- + 2 files changed, 20 insertions(+), 1 deletion(-) + +diff --git a/src/go/parser/parser_test.go b/src/go/parser/parser_test.go +index 37a6a2b..714557c 100644 +--- a/src/go/parser/parser_test.go ++++ b/src/go/parser/parser_test.go +@@ -738,3 +738,19 @@ func TestScopeDepthLimit(t *testing.T) { + } + } + } ++ ++// TestIssue59180 tests that line number overflow doesn't cause an infinite loop. ++func TestIssue59180(t *testing.T) { ++ testcases := []string{ ++ "package p\n//line :9223372036854775806\n\n//", ++ "package p\n//line :1:9223372036854775806\n\n//", ++ "package p\n//line file:9223372036854775806\n\n//", ++ } ++ ++ for _, src := range testcases { ++ _, err := ParseFile(token.NewFileSet(), "", src, ParseComments) ++ if err == nil { ++ t.Errorf("ParseFile(%s) succeeded unexpectedly", src) ++ } ++ } ++} +diff --git a/src/go/scanner/scanner.go b/src/go/scanner/scanner.go +index 00fe2dc..3159d25 100644 +--- a/src/go/scanner/scanner.go ++++ b/src/go/scanner/scanner.go +@@ -246,13 +246,16 @@ func (s *Scanner) updateLineInfo(next, offs int, text []byte) { + return + } + ++ // Put a cap on the maximum size of line and column numbers. ++ // 30 bits allows for some additional space before wrapping an int32. ++ const maxLineCol = 1<<30 - 1 + var line, col int + i2, n2, ok2 := trailingDigits(text[:i-1]) + if ok2 { + //line filename:line:col + i, i2 = i2, i + line, col = n2, n +- if col == 0 { ++ if col == 0 || col > maxLineCol { + s.error(offs+i2, "invalid column number: "+string(text[i2:])) + return + } +-- +2.25.1 + diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-24538-1.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-24538-1.patch new file mode 100644 index 0000000000..23c5075e41 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-24538-1.patch @@ -0,0 +1,125 @@ +From 8acd01094d9ee17f6e763a61e49a8a808b3a9ddb Mon Sep 17 00:00:00 2001 +From: Brad Fitzpatrick <bradfitz@golang.org> +Date: Mon, 2 Aug 2021 14:55:51 -0700 +Subject: [PATCH 1/6] net/netip: add new IP address package + +Co-authored-by: Alex Willmer <alex@moreati.org.uk> (GitHub @moreati) +Co-authored-by: Alexander Yastrebov <yastrebov.alex@gmail.com> +Co-authored-by: David Anderson <dave@natulte.net> (Tailscale CLA) +Co-authored-by: David Crawshaw <crawshaw@tailscale.com> (Tailscale CLA) +Co-authored-by: Dmytro Shynkevych <dmytro@tailscale.com> (Tailscale CLA) +Co-authored-by: Elias Naur <mail@eliasnaur.com> +Co-authored-by: Joe Tsai <joetsai@digital-static.net> (Tailscale CLA) +Co-authored-by: Jonathan Yu <jawnsy@cpan.org> (GitHub @jawnsy) +Co-authored-by: Josh Bleecher Snyder <josharian@gmail.com> (Tailscale CLA) +Co-authored-by: Maisem Ali <maisem@tailscale.com> (Tailscale CLA) +Co-authored-by: Manuel Mendez (Go AUTHORS mmendez534@...) +Co-authored-by: Matt Layher <mdlayher@gmail.com> +Co-authored-by: Noah Treuhaft <noah.treuhaft@gmail.com> (GitHub @nwt) +Co-authored-by: Stefan Majer <stefan.majer@gmail.com> +Co-authored-by: Terin Stock <terinjokes@gmail.com> (Cloudflare CLA) +Co-authored-by: Tobias Klauser <tklauser@distanz.ch> + +Fixes #46518 + +Change-Id: I0041f9e1115d61fa6e95fcf32b01d9faee708712 +Reviewed-on: https://go-review.googlesource.com/c/go/+/339309 +Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> +TryBot-Result: Go Bot <gobot@golang.org> +Reviewed-by: Russ Cox <rsc@golang.org> +Trust: Brad Fitzpatrick <bradfitz@golang.org> + +Dependency Patch #1 + +Upstream-Status: Backport from https://github.com/golang/go/commit/a59e33224e42d60a97fa720a45e1b74eb6aaa3d0 +CVE: CVE-2023-24538 +Signed-off-by: Shubham Kulkarni <skulkarni@mvista.com> +--- + src/internal/godebug/godebug.go | 34 ++++++++++++++++++++++++++++++++++ + src/internal/godebug/godebug_test.go | 34 ++++++++++++++++++++++++++++++++++ + 2 files changed, 68 insertions(+) + create mode 100644 src/internal/godebug/godebug.go + create mode 100644 src/internal/godebug/godebug_test.go + +diff --git a/src/internal/godebug/godebug.go b/src/internal/godebug/godebug.go +new file mode 100644 +index 0000000..ac434e5 +--- /dev/null ++++ b/src/internal/godebug/godebug.go +@@ -0,0 +1,34 @@ ++// Copyright 2021 The Go Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style ++// license that can be found in the LICENSE file. ++ ++// Package godebug parses the GODEBUG environment variable. ++package godebug ++ ++import "os" ++ ++// Get returns the value for the provided GODEBUG key. ++func Get(key string) string { ++ return get(os.Getenv("GODEBUG"), key) ++} ++ ++// get returns the value part of key=value in s (a GODEBUG value). ++func get(s, key string) string { ++ for i := 0; i < len(s)-len(key)-1; i++ { ++ if i > 0 && s[i-1] != ',' { ++ continue ++ } ++ afterKey := s[i+len(key):] ++ if afterKey[0] != '=' || s[i:i+len(key)] != key { ++ continue ++ } ++ val := afterKey[1:] ++ for i, b := range val { ++ if b == ',' { ++ return val[:i] ++ } ++ } ++ return val ++ } ++ return "" ++} +diff --git a/src/internal/godebug/godebug_test.go b/src/internal/godebug/godebug_test.go +new file mode 100644 +index 0000000..41b9117 +--- /dev/null ++++ b/src/internal/godebug/godebug_test.go +@@ -0,0 +1,34 @@ ++// Copyright 2021 The Go Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style ++// license that can be found in the LICENSE file. ++ ++package godebug ++ ++import "testing" ++ ++func TestGet(t *testing.T) { ++ tests := []struct { ++ godebug string ++ key string ++ want string ++ }{ ++ {"", "", ""}, ++ {"", "foo", ""}, ++ {"foo=bar", "foo", "bar"}, ++ {"foo=bar,after=x", "foo", "bar"}, ++ {"before=x,foo=bar,after=x", "foo", "bar"}, ++ {"before=x,foo=bar", "foo", "bar"}, ++ {",,,foo=bar,,,", "foo", "bar"}, ++ {"foodecoy=wrong,foo=bar", "foo", "bar"}, ++ {"foo=", "foo", ""}, ++ {"foo", "foo", ""}, ++ {",foo", "foo", ""}, ++ {"foo=bar,baz", "loooooooong", ""}, ++ } ++ for _, tt := range tests { ++ got := get(tt.godebug, tt.key) ++ if got != tt.want { ++ t.Errorf("get(%q, %q) = %q; want %q", tt.godebug, tt.key, got, tt.want) ++ } ++ } ++} +-- +2.7.4 diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-24538-2.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-24538-2.patch new file mode 100644 index 0000000000..f200c41e16 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-24538-2.patch @@ -0,0 +1,635 @@ +From 6fc21505614f36178df0dad7034b6b8e3f7588d5 Mon Sep 17 00:00:00 2001 +From: empijei <robclap8@gmail.com> +Date: Fri, 27 Mar 2020 19:27:55 +0100 +Subject: [PATCH 2/6] html/template,text/template: switch to Unicode escapes + for JSON compatibility +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The existing implementation is not compatible with JSON +escape as it uses hex escaping. +Unicode escape, instead, is valid for both JSON and JS. +This fix avoids creating a separate escaping context for +scripts of type "application/ld+json" and it is more +future-proof in case more JSON+JS contexts get added +to the platform (e.g. import maps). + +Fixes #33671 +Fixes #37634 + +Change-Id: Id6f6524b4abc52e81d9d744d46bbe5bf2e081543 +Reviewed-on: https://go-review.googlesource.com/c/go/+/226097 +Reviewed-by: Carl Johnson <me@carlmjohnson.net> +Reviewed-by: Daniel Martí <mvdan@mvdan.cc> +Run-TryBot: Daniel Martí <mvdan@mvdan.cc> +TryBot-Result: Gobot Gobot <gobot@golang.org> + +Dependency Patch #2 + +Upstream-Status: Backport from https://github.com/golang/go/commit/d4d298040d072ddacea0e0d6b55fb148fff18070 +CVE: CVE-2023-24538 +Signed-off-by: Shubham Kulkarni <skulkarni@mvista.com> +--- + src/html/template/content_test.go | 70 +++++++++++++++++++------------------- + src/html/template/escape_test.go | 6 ++-- + src/html/template/example_test.go | 6 ++-- + src/html/template/js.go | 70 +++++++++++++++++++++++--------------- + src/html/template/js_test.go | 68 ++++++++++++++++++------------------ + src/html/template/template_test.go | 39 +++++++++++++++++++++ + src/text/template/exec_test.go | 6 ++-- + src/text/template/funcs.go | 8 ++--- + 8 files changed, 163 insertions(+), 110 deletions(-) + +diff --git a/src/html/template/content_test.go b/src/html/template/content_test.go +index 72d56f5..bd86527 100644 +--- a/src/html/template/content_test.go ++++ b/src/html/template/content_test.go +@@ -18,7 +18,7 @@ func TestTypedContent(t *testing.T) { + HTML(`Hello, <b>World</b> &tc!`), + HTMLAttr(` dir="ltr"`), + JS(`c && alert("Hello, World!");`), +- JSStr(`Hello, World & O'Reilly\x21`), ++ JSStr(`Hello, World & O'Reilly\u0021`), + URL(`greeting=H%69,&addressee=(World)`), + Srcset(`greeting=H%69,&addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`), + URL(`,foo/,`), +@@ -70,7 +70,7 @@ func TestTypedContent(t *testing.T) { + `Hello, <b>World</b> &tc!`, + ` dir="ltr"`, + `c && alert("Hello, World!");`, +- `Hello, World & O'Reilly\x21`, ++ `Hello, World & O'Reilly\u0021`, + `greeting=H%69,&addressee=(World)`, + `greeting=H%69,&addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`, + `,foo/,`, +@@ -100,7 +100,7 @@ func TestTypedContent(t *testing.T) { + `Hello, World &tc!`, + ` dir="ltr"`, + `c && alert("Hello, World!");`, +- `Hello, World & O'Reilly\x21`, ++ `Hello, World & O'Reilly\u0021`, + `greeting=H%69,&addressee=(World)`, + `greeting=H%69,&addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`, + `,foo/,`, +@@ -115,7 +115,7 @@ func TestTypedContent(t *testing.T) { + `Hello, World &tc!`, + ` dir="ltr"`, + `c && alert("Hello, World!");`, +- `Hello, World & O'Reilly\x21`, ++ `Hello, World & O'Reilly\u0021`, + `greeting=H%69,&addressee=(World)`, + `greeting=H%69,&addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`, + `,foo/,`, +@@ -130,7 +130,7 @@ func TestTypedContent(t *testing.T) { + `Hello, <b>World</b> &tc!`, + ` dir="ltr"`, + `c && alert("Hello, World!");`, +- `Hello, World & O'Reilly\x21`, ++ `Hello, World & O'Reilly\u0021`, + `greeting=H%69,&addressee=(World)`, + `greeting=H%69,&addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`, + `,foo/,`, +@@ -146,7 +146,7 @@ func TestTypedContent(t *testing.T) { + // Not escaped. + `c && alert("Hello, World!");`, + // Escape sequence not over-escaped. +- `"Hello, World & O'Reilly\x21"`, ++ `"Hello, World & O'Reilly\u0021"`, + `"greeting=H%69,\u0026addressee=(World)"`, + `"greeting=H%69,\u0026addressee=(World) 2x, https://golang.org/favicon.ico 500.5w"`, + `",foo/,"`, +@@ -162,7 +162,7 @@ func TestTypedContent(t *testing.T) { + // Not JS escaped but HTML escaped. + `c && alert("Hello, World!");`, + // Escape sequence not over-escaped. +- `"Hello, World & O'Reilly\x21"`, ++ `"Hello, World & O'Reilly\u0021"`, + `"greeting=H%69,\u0026addressee=(World)"`, + `"greeting=H%69,\u0026addressee=(World) 2x, https://golang.org/favicon.ico 500.5w"`, + `",foo/,"`, +@@ -171,30 +171,30 @@ func TestTypedContent(t *testing.T) { + { + `<script>alert("{{.}}")</script>`, + []string{ +- `\x3cb\x3e \x22foo%\x22 O\x27Reilly \x26bar;`, +- `a[href =~ \x22\/\/example.com\x22]#foo`, +- `Hello, \x3cb\x3eWorld\x3c\/b\x3e \x26amp;tc!`, +- ` dir=\x22ltr\x22`, +- `c \x26\x26 alert(\x22Hello, World!\x22);`, ++ `\u003cb\u003e \u0022foo%\u0022 O\u0027Reilly \u0026bar;`, ++ `a[href =~ \u0022\/\/example.com\u0022]#foo`, ++ `Hello, \u003cb\u003eWorld\u003c\/b\u003e \u0026amp;tc!`, ++ ` dir=\u0022ltr\u0022`, ++ `c \u0026\u0026 alert(\u0022Hello, World!\u0022);`, + // Escape sequence not over-escaped. +- `Hello, World \x26 O\x27Reilly\x21`, +- `greeting=H%69,\x26addressee=(World)`, +- `greeting=H%69,\x26addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`, ++ `Hello, World \u0026 O\u0027Reilly\u0021`, ++ `greeting=H%69,\u0026addressee=(World)`, ++ `greeting=H%69,\u0026addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`, + `,foo\/,`, + }, + }, + { + `<script type="text/javascript">alert("{{.}}")</script>`, + []string{ +- `\x3cb\x3e \x22foo%\x22 O\x27Reilly \x26bar;`, +- `a[href =~ \x22\/\/example.com\x22]#foo`, +- `Hello, \x3cb\x3eWorld\x3c\/b\x3e \x26amp;tc!`, +- ` dir=\x22ltr\x22`, +- `c \x26\x26 alert(\x22Hello, World!\x22);`, ++ `\u003cb\u003e \u0022foo%\u0022 O\u0027Reilly \u0026bar;`, ++ `a[href =~ \u0022\/\/example.com\u0022]#foo`, ++ `Hello, \u003cb\u003eWorld\u003c\/b\u003e \u0026amp;tc!`, ++ ` dir=\u0022ltr\u0022`, ++ `c \u0026\u0026 alert(\u0022Hello, World!\u0022);`, + // Escape sequence not over-escaped. +- `Hello, World \x26 O\x27Reilly\x21`, +- `greeting=H%69,\x26addressee=(World)`, +- `greeting=H%69,\x26addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`, ++ `Hello, World \u0026 O\u0027Reilly\u0021`, ++ `greeting=H%69,\u0026addressee=(World)`, ++ `greeting=H%69,\u0026addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`, + `,foo\/,`, + }, + }, +@@ -208,7 +208,7 @@ func TestTypedContent(t *testing.T) { + // Not escaped. + `c && alert("Hello, World!");`, + // Escape sequence not over-escaped. +- `"Hello, World & O'Reilly\x21"`, ++ `"Hello, World & O'Reilly\u0021"`, + `"greeting=H%69,\u0026addressee=(World)"`, + `"greeting=H%69,\u0026addressee=(World) 2x, https://golang.org/favicon.ico 500.5w"`, + `",foo/,"`, +@@ -224,7 +224,7 @@ func TestTypedContent(t *testing.T) { + `Hello, <b>World</b> &tc!`, + ` dir="ltr"`, + `c && alert("Hello, World!");`, +- `Hello, World & O'Reilly\x21`, ++ `Hello, World & O'Reilly\u0021`, + `greeting=H%69,&addressee=(World)`, + `greeting=H%69,&addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`, + `,foo/,`, +@@ -233,15 +233,15 @@ func TestTypedContent(t *testing.T) { + { + `<button onclick='alert("{{.}}")'>`, + []string{ +- `\x3cb\x3e \x22foo%\x22 O\x27Reilly \x26bar;`, +- `a[href =~ \x22\/\/example.com\x22]#foo`, +- `Hello, \x3cb\x3eWorld\x3c\/b\x3e \x26amp;tc!`, +- ` dir=\x22ltr\x22`, +- `c \x26\x26 alert(\x22Hello, World!\x22);`, ++ `\u003cb\u003e \u0022foo%\u0022 O\u0027Reilly \u0026bar;`, ++ `a[href =~ \u0022\/\/example.com\u0022]#foo`, ++ `Hello, \u003cb\u003eWorld\u003c\/b\u003e \u0026amp;tc!`, ++ ` dir=\u0022ltr\u0022`, ++ `c \u0026\u0026 alert(\u0022Hello, World!\u0022);`, + // Escape sequence not over-escaped. +- `Hello, World \x26 O\x27Reilly\x21`, +- `greeting=H%69,\x26addressee=(World)`, +- `greeting=H%69,\x26addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`, ++ `Hello, World \u0026 O\u0027Reilly\u0021`, ++ `greeting=H%69,\u0026addressee=(World)`, ++ `greeting=H%69,\u0026addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`, + `,foo\/,`, + }, + }, +@@ -253,7 +253,7 @@ func TestTypedContent(t *testing.T) { + `Hello%2c%20%3cb%3eWorld%3c%2fb%3e%20%26amp%3btc%21`, + `%20dir%3d%22ltr%22`, + `c%20%26%26%20alert%28%22Hello%2c%20World%21%22%29%3b`, +- `Hello%2c%20World%20%26%20O%27Reilly%5cx21`, ++ `Hello%2c%20World%20%26%20O%27Reilly%5cu0021`, + // Quotes and parens are escaped but %69 is not over-escaped. HTML escaping is done. + `greeting=H%69,&addressee=%28World%29`, + `greeting%3dH%2569%2c%26addressee%3d%28World%29%202x%2c%20https%3a%2f%2fgolang.org%2ffavicon.ico%20500.5w`, +@@ -268,7 +268,7 @@ func TestTypedContent(t *testing.T) { + `Hello%2c%20%3cb%3eWorld%3c%2fb%3e%20%26amp%3btc%21`, + `%20dir%3d%22ltr%22`, + `c%20%26%26%20alert%28%22Hello%2c%20World%21%22%29%3b`, +- `Hello%2c%20World%20%26%20O%27Reilly%5cx21`, ++ `Hello%2c%20World%20%26%20O%27Reilly%5cu0021`, + // Quotes and parens are escaped but %69 is not over-escaped. HTML escaping is not done. + `greeting=H%69,&addressee=%28World%29`, + `greeting%3dH%2569%2c%26addressee%3d%28World%29%202x%2c%20https%3a%2f%2fgolang.org%2ffavicon.ico%20500.5w`, +diff --git a/src/html/template/escape_test.go b/src/html/template/escape_test.go +index e72a9ba..c709660 100644 +--- a/src/html/template/escape_test.go ++++ b/src/html/template/escape_test.go +@@ -238,7 +238,7 @@ func TestEscape(t *testing.T) { + { + "jsStr", + "<button onclick='alert("{{.H}}")'>", +- `<button onclick='alert("\x3cHello\x3e")'>`, ++ `<button onclick='alert("\u003cHello\u003e")'>`, + }, + { + "badMarshaler", +@@ -259,7 +259,7 @@ func TestEscape(t *testing.T) { + { + "jsRe", + `<button onclick='alert(/{{"foo+bar"}}/.test(""))'>`, +- `<button onclick='alert(/foo\x2bbar/.test(""))'>`, ++ `<button onclick='alert(/foo\u002bbar/.test(""))'>`, + }, + { + "jsReBlank", +@@ -825,7 +825,7 @@ func TestEscapeSet(t *testing.T) { + "main": `<button onclick="title='{{template "helper"}}'; ...">{{template "helper"}}</button>`, + "helper": `{{11}} of {{"<100>"}}`, + }, +- `<button onclick="title='11 of \x3c100\x3e'; ...">11 of <100></button>`, ++ `<button onclick="title='11 of \u003c100\u003e'; ...">11 of <100></button>`, + }, + // A non-recursive template that ends in a different context. + // helper starts in jsCtxRegexp and ends in jsCtxDivOp. +diff --git a/src/html/template/example_test.go b/src/html/template/example_test.go +index 9d965f1..6cf936f 100644 +--- a/src/html/template/example_test.go ++++ b/src/html/template/example_test.go +@@ -116,9 +116,9 @@ func Example_escape() { + // "Fran & Freddie's Diner" <tasty@example.com> + // "Fran & Freddie's Diner" <tasty@example.com> + // "Fran & Freddie's Diner"32<tasty@example.com> +- // \"Fran \x26 Freddie\'s Diner\" \x3Ctasty@example.com\x3E +- // \"Fran \x26 Freddie\'s Diner\" \x3Ctasty@example.com\x3E +- // \"Fran \x26 Freddie\'s Diner\"32\x3Ctasty@example.com\x3E ++ // \"Fran \u0026 Freddie\'s Diner\" \u003Ctasty@example.com\u003E ++ // \"Fran \u0026 Freddie\'s Diner\" \u003Ctasty@example.com\u003E ++ // \"Fran \u0026 Freddie\'s Diner\"32\u003Ctasty@example.com\u003E + // %22Fran+%26+Freddie%27s+Diner%2232%3Ctasty%40example.com%3E + + } +diff --git a/src/html/template/js.go b/src/html/template/js.go +index 0e91458..ea9c183 100644 +--- a/src/html/template/js.go ++++ b/src/html/template/js.go +@@ -163,7 +163,6 @@ func jsValEscaper(args ...interface{}) string { + } + // TODO: detect cycles before calling Marshal which loops infinitely on + // cyclic data. This may be an unacceptable DoS risk. +- + b, err := json.Marshal(a) + if err != nil { + // Put a space before comment so that if it is flush against +@@ -178,8 +177,8 @@ func jsValEscaper(args ...interface{}) string { + // TODO: maybe post-process output to prevent it from containing + // "<!--", "-->", "<![CDATA[", "]]>", or "</script" + // in case custom marshalers produce output containing those. +- +- // TODO: Maybe abbreviate \u00ab to \xab to produce more compact output. ++ // Note: Do not use \x escaping to save bytes because it is not JSON compatible and this escaper ++ // supports ld+json content-type. + if len(b) == 0 { + // In, `x=y/{{.}}*z` a json.Marshaler that produces "" should + // not cause the output `x=y/*z`. +@@ -260,6 +259,8 @@ func replace(s string, replacementTable []string) string { + r, w = utf8.DecodeRuneInString(s[i:]) + var repl string + switch { ++ case int(r) < len(lowUnicodeReplacementTable): ++ repl = lowUnicodeReplacementTable[r] + case int(r) < len(replacementTable) && replacementTable[r] != "": + repl = replacementTable[r] + case r == '\u2028': +@@ -283,67 +284,80 @@ func replace(s string, replacementTable []string) string { + return b.String() + } + ++var lowUnicodeReplacementTable = []string{ ++ 0: `\u0000`, 1: `\u0001`, 2: `\u0002`, 3: `\u0003`, 4: `\u0004`, 5: `\u0005`, 6: `\u0006`, ++ '\a': `\u0007`, ++ '\b': `\u0008`, ++ '\t': `\t`, ++ '\n': `\n`, ++ '\v': `\u000b`, // "\v" == "v" on IE 6. ++ '\f': `\f`, ++ '\r': `\r`, ++ 0xe: `\u000e`, 0xf: `\u000f`, 0x10: `\u0010`, 0x11: `\u0011`, 0x12: `\u0012`, 0x13: `\u0013`, ++ 0x14: `\u0014`, 0x15: `\u0015`, 0x16: `\u0016`, 0x17: `\u0017`, 0x18: `\u0018`, 0x19: `\u0019`, ++ 0x1a: `\u001a`, 0x1b: `\u001b`, 0x1c: `\u001c`, 0x1d: `\u001d`, 0x1e: `\u001e`, 0x1f: `\u001f`, ++} ++ + var jsStrReplacementTable = []string{ +- 0: `\0`, ++ 0: `\u0000`, + '\t': `\t`, + '\n': `\n`, +- '\v': `\x0b`, // "\v" == "v" on IE 6. ++ '\v': `\u000b`, // "\v" == "v" on IE 6. + '\f': `\f`, + '\r': `\r`, + // Encode HTML specials as hex so the output can be embedded + // in HTML attributes without further encoding. +- '"': `\x22`, +- '&': `\x26`, +- '\'': `\x27`, +- '+': `\x2b`, ++ '"': `\u0022`, ++ '&': `\u0026`, ++ '\'': `\u0027`, ++ '+': `\u002b`, + '/': `\/`, +- '<': `\x3c`, +- '>': `\x3e`, ++ '<': `\u003c`, ++ '>': `\u003e`, + '\\': `\\`, + } + + // jsStrNormReplacementTable is like jsStrReplacementTable but does not + // overencode existing escapes since this table has no entry for `\`. + var jsStrNormReplacementTable = []string{ +- 0: `\0`, ++ 0: `\u0000`, + '\t': `\t`, + '\n': `\n`, +- '\v': `\x0b`, // "\v" == "v" on IE 6. ++ '\v': `\u000b`, // "\v" == "v" on IE 6. + '\f': `\f`, + '\r': `\r`, + // Encode HTML specials as hex so the output can be embedded + // in HTML attributes without further encoding. +- '"': `\x22`, +- '&': `\x26`, +- '\'': `\x27`, +- '+': `\x2b`, ++ '"': `\u0022`, ++ '&': `\u0026`, ++ '\'': `\u0027`, ++ '+': `\u002b`, + '/': `\/`, +- '<': `\x3c`, +- '>': `\x3e`, ++ '<': `\u003c`, ++ '>': `\u003e`, + } +- + var jsRegexpReplacementTable = []string{ +- 0: `\0`, ++ 0: `\u0000`, + '\t': `\t`, + '\n': `\n`, +- '\v': `\x0b`, // "\v" == "v" on IE 6. ++ '\v': `\u000b`, // "\v" == "v" on IE 6. + '\f': `\f`, + '\r': `\r`, + // Encode HTML specials as hex so the output can be embedded + // in HTML attributes without further encoding. +- '"': `\x22`, ++ '"': `\u0022`, + '$': `\$`, +- '&': `\x26`, +- '\'': `\x27`, ++ '&': `\u0026`, ++ '\'': `\u0027`, + '(': `\(`, + ')': `\)`, + '*': `\*`, +- '+': `\x2b`, ++ '+': `\u002b`, + '-': `\-`, + '.': `\.`, + '/': `\/`, +- '<': `\x3c`, +- '>': `\x3e`, ++ '<': `\u003c`, ++ '>': `\u003e`, + '?': `\?`, + '[': `\[`, + '\\': `\\`, +diff --git a/src/html/template/js_test.go b/src/html/template/js_test.go +index 075adaa..d7ee47b 100644 +--- a/src/html/template/js_test.go ++++ b/src/html/template/js_test.go +@@ -137,7 +137,7 @@ func TestJSValEscaper(t *testing.T) { + {"foo", `"foo"`}, + // Newlines. + {"\r\n\u2028\u2029", `"\r\n\u2028\u2029"`}, +- // "\v" == "v" on IE 6 so use "\x0b" instead. ++ // "\v" == "v" on IE 6 so use "\u000b" instead. + {"\t\x0b", `"\t\u000b"`}, + {struct{ X, Y int }{1, 2}, `{"X":1,"Y":2}`}, + {[]interface{}{}, "[]"}, +@@ -173,7 +173,7 @@ func TestJSStrEscaper(t *testing.T) { + }{ + {"", ``}, + {"foo", `foo`}, +- {"\u0000", `\0`}, ++ {"\u0000", `\u0000`}, + {"\t", `\t`}, + {"\n", `\n`}, + {"\r", `\r`}, +@@ -183,14 +183,14 @@ func TestJSStrEscaper(t *testing.T) { + {"\\n", `\\n`}, + {"foo\r\nbar", `foo\r\nbar`}, + // Preserve attribute boundaries. +- {`"`, `\x22`}, +- {`'`, `\x27`}, ++ {`"`, `\u0022`}, ++ {`'`, `\u0027`}, + // Allow embedding in HTML without further escaping. +- {`&`, `\x26amp;`}, ++ {`&`, `\u0026amp;`}, + // Prevent breaking out of text node and element boundaries. +- {"</script>", `\x3c\/script\x3e`}, +- {"<![CDATA[", `\x3c![CDATA[`}, +- {"]]>", `]]\x3e`}, ++ {"</script>", `\u003c\/script\u003e`}, ++ {"<![CDATA[", `\u003c![CDATA[`}, ++ {"]]>", `]]\u003e`}, + // https://dev.w3.org/html5/markup/aria/syntax.html#escaping-text-span + // "The text in style, script, title, and textarea elements + // must not have an escaping text span start that is not +@@ -201,11 +201,11 @@ func TestJSStrEscaper(t *testing.T) { + // allow regular text content to be interpreted as script + // allowing script execution via a combination of a JS string + // injection followed by an HTML text injection. +- {"<!--", `\x3c!--`}, +- {"-->", `--\x3e`}, ++ {"<!--", `\u003c!--`}, ++ {"-->", `--\u003e`}, + // From https://code.google.com/p/doctype/wiki/ArticleUtf7 + {"+ADw-script+AD4-alert(1)+ADw-/script+AD4-", +- `\x2bADw-script\x2bAD4-alert(1)\x2bADw-\/script\x2bAD4-`, ++ `\u002bADw-script\u002bAD4-alert(1)\u002bADw-\/script\u002bAD4-`, + }, + // Invalid UTF-8 sequence + {"foo\xA0bar", "foo\xA0bar"}, +@@ -228,7 +228,7 @@ func TestJSRegexpEscaper(t *testing.T) { + }{ + {"", `(?:)`}, + {"foo", `foo`}, +- {"\u0000", `\0`}, ++ {"\u0000", `\u0000`}, + {"\t", `\t`}, + {"\n", `\n`}, + {"\r", `\r`}, +@@ -238,19 +238,19 @@ func TestJSRegexpEscaper(t *testing.T) { + {"\\n", `\\n`}, + {"foo\r\nbar", `foo\r\nbar`}, + // Preserve attribute boundaries. +- {`"`, `\x22`}, +- {`'`, `\x27`}, ++ {`"`, `\u0022`}, ++ {`'`, `\u0027`}, + // Allow embedding in HTML without further escaping. +- {`&`, `\x26amp;`}, ++ {`&`, `\u0026amp;`}, + // Prevent breaking out of text node and element boundaries. +- {"</script>", `\x3c\/script\x3e`}, +- {"<![CDATA[", `\x3c!\[CDATA\[`}, +- {"]]>", `\]\]\x3e`}, ++ {"</script>", `\u003c\/script\u003e`}, ++ {"<![CDATA[", `\u003c!\[CDATA\[`}, ++ {"]]>", `\]\]\u003e`}, + // Escaping text spans. +- {"<!--", `\x3c!\-\-`}, +- {"-->", `\-\-\x3e`}, ++ {"<!--", `\u003c!\-\-`}, ++ {"-->", `\-\-\u003e`}, + {"*", `\*`}, +- {"+", `\x2b`}, ++ {"+", `\u002b`}, + {"?", `\?`}, + {"[](){}", `\[\]\(\)\{\}`}, + {"$foo|x.y", `\$foo\|x\.y`}, +@@ -284,27 +284,27 @@ func TestEscapersOnLower7AndSelectHighCodepoints(t *testing.T) { + { + "jsStrEscaper", + jsStrEscaper, +- "\\0\x01\x02\x03\x04\x05\x06\x07" + +- "\x08\\t\\n\\x0b\\f\\r\x0E\x0F" + +- "\x10\x11\x12\x13\x14\x15\x16\x17" + +- "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + +- ` !\x22#$%\x26\x27()*\x2b,-.\/` + +- `0123456789:;\x3c=\x3e?` + ++ `\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007` + ++ `\u0008\t\n\u000b\f\r\u000e\u000f` + ++ `\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017` + ++ `\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f` + ++ ` !\u0022#$%\u0026\u0027()*\u002b,-.\/` + ++ `0123456789:;\u003c=\u003e?` + + `@ABCDEFGHIJKLMNO` + + `PQRSTUVWXYZ[\\]^_` + + "`abcdefghijklmno" + +- "pqrstuvwxyz{|}~\x7f" + ++ "pqrstuvwxyz{|}~\u007f" + + "\u00A0\u0100\\u2028\\u2029\ufeff\U0001D11E", + }, + { + "jsRegexpEscaper", + jsRegexpEscaper, +- "\\0\x01\x02\x03\x04\x05\x06\x07" + +- "\x08\\t\\n\\x0b\\f\\r\x0E\x0F" + +- "\x10\x11\x12\x13\x14\x15\x16\x17" + +- "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + +- ` !\x22#\$%\x26\x27\(\)\*\x2b,\-\.\/` + +- `0123456789:;\x3c=\x3e\?` + ++ `\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007` + ++ `\u0008\t\n\u000b\f\r\u000e\u000f` + ++ `\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017` + ++ `\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f` + ++ ` !\u0022#\$%\u0026\u0027\(\)\*\u002b,\-\.\/` + ++ `0123456789:;\u003c=\u003e\?` + + `@ABCDEFGHIJKLMNO` + + `PQRSTUVWXYZ\[\\\]\^_` + + "`abcdefghijklmno" + +diff --git a/src/html/template/template_test.go b/src/html/template/template_test.go +index 13e6ba4..86bd4db 100644 +--- a/src/html/template/template_test.go ++++ b/src/html/template/template_test.go +@@ -6,6 +6,7 @@ package template_test + + import ( + "bytes" ++ "encoding/json" + . "html/template" + "strings" + "testing" +@@ -121,6 +122,44 @@ func TestNumbers(t *testing.T) { + c.mustExecute(c.root, nil, "12.34 7.5") + } + ++func TestStringsInScriptsWithJsonContentTypeAreCorrectlyEscaped(t *testing.T) { ++ // See #33671 and #37634 for more context on this. ++ tests := []struct{ name, in string }{ ++ {"empty", ""}, ++ {"invalid", string(rune(-1))}, ++ {"null", "\u0000"}, ++ {"unit separator", "\u001F"}, ++ {"tab", "\t"}, ++ {"gt and lt", "<>"}, ++ {"quotes", `'"`}, ++ {"ASCII letters", "ASCII letters"}, ++ {"Unicode", "ʕ⊙ϖ⊙ʔ"}, ++ {"Pizza", "P"}, ++ } ++ const ( ++ prefix = `<script type="application/ld+json">` ++ suffix = `</script>` ++ templ = prefix + `"{{.}}"` + suffix ++ ) ++ tpl := Must(New("JS string is JSON string").Parse(templ)) ++ for _, tt := range tests { ++ t.Run(tt.name, func(t *testing.T) { ++ var buf bytes.Buffer ++ if err := tpl.Execute(&buf, tt.in); err != nil { ++ t.Fatalf("Cannot render template: %v", err) ++ } ++ trimmed := bytes.TrimSuffix(bytes.TrimPrefix(buf.Bytes(), []byte(prefix)), []byte(suffix)) ++ var got string ++ if err := json.Unmarshal(trimmed, &got); err != nil { ++ t.Fatalf("Cannot parse JS string %q as JSON: %v", trimmed[1:len(trimmed)-1], err) ++ } ++ if got != tt.in { ++ t.Errorf("Serialization changed the string value: got %q want %q", got, tt.in) ++ } ++ }) ++ } ++} ++ + type testCase struct { + t *testing.T + root *Template +diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go +index 77294ed..b8a809e 100644 +--- a/src/text/template/exec_test.go ++++ b/src/text/template/exec_test.go +@@ -911,9 +911,9 @@ func TestJSEscaping(t *testing.T) { + {`Go "jump" \`, `Go \"jump\" \\`}, + {`Yukihiro says "今日は世界"`, `Yukihiro says \"今日は世界\"`}, + {"unprintable \uFDFF", `unprintable \uFDFF`}, +- {`<html>`, `\x3Chtml\x3E`}, +- {`no = in attributes`, `no \x3D in attributes`}, +- {`' does not become HTML entity`, `\x26#x27; does not become HTML entity`}, ++ {`<html>`, `\u003Chtml\u003E`}, ++ {`no = in attributes`, `no \u003D in attributes`}, ++ {`' does not become HTML entity`, `\u0026#x27; does not become HTML entity`}, + } + for _, tc := range testCases { + s := JSEscapeString(tc.in) +diff --git a/src/text/template/funcs.go b/src/text/template/funcs.go +index 46125bc..f3de9fb 100644 +--- a/src/text/template/funcs.go ++++ b/src/text/template/funcs.go +@@ -640,10 +640,10 @@ var ( + jsBackslash = []byte(`\\`) + jsApos = []byte(`\'`) + jsQuot = []byte(`\"`) +- jsLt = []byte(`\x3C`) +- jsGt = []byte(`\x3E`) +- jsAmp = []byte(`\x26`) +- jsEq = []byte(`\x3D`) ++ jsLt = []byte(`\u003C`) ++ jsGt = []byte(`\u003E`) ++ jsAmp = []byte(`\u0026`) ++ jsEq = []byte(`\u003D`) + ) + + // JSEscape writes to w the escaped JavaScript equivalent of the plain text data b. +-- +2.7.4 diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-24538_3.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-24538_3.patch new file mode 100644 index 0000000000..cd7dd0957c --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-24538_3.patch @@ -0,0 +1,393 @@ +From 7ddce23c7d5b728acf8482f5006497c7b9915f8a Mon Sep 17 00:00:00 2001 +From: Ariel Mashraki <ariel@mashraki.co.il> +Date: Wed, 22 Apr 2020 22:17:56 +0300 +Subject: [PATCH 3/6] text/template: add CommentNode to template parse tree +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fixes #34652 + +Change-Id: Icf6e3eda593fed826736f34f95a9d66f5450cc98 +Reviewed-on: https://go-review.googlesource.com/c/go/+/229398 +Reviewed-by: Daniel Martí <mvdan@mvdan.cc> +Run-TryBot: Daniel Martí <mvdan@mvdan.cc> +TryBot-Result: Gobot Gobot <gobot@golang.org> + +Dependency Patch #3 + +Upstream-Status: Backport from https://github.com/golang/go/commit/c8ea03828b0645b1fd5725888e44873b75fcfbb6 +CVE: CVE-2023-24538 +Signed-off-by: Shubham Kulkarni <skulkarni@mvista.com> +--- + api/next.txt | 19 +++++++++++++++++++ + src/html/template/escape.go | 2 ++ + src/html/template/template_test.go | 16 ++++++++++++++++ + src/text/template/exec.go | 1 + + src/text/template/parse/lex.go | 8 +++++++- + src/text/template/parse/lex_test.go | 7 +++++-- + src/text/template/parse/node.go | 33 +++++++++++++++++++++++++++++++++ + src/text/template/parse/parse.go | 22 +++++++++++++++++++--- + src/text/template/parse/parse_test.go | 25 +++++++++++++++++++++++++ + 9 files changed, 127 insertions(+), 6 deletions(-) + +diff --git a/api/next.txt b/api/next.txt +index e69de29..076f39e 100644 +--- a/api/next.txt ++++ b/api/next.txt +@@ -0,0 +1,19 @@ ++pkg unicode, const Version = "13.0.0" ++pkg unicode, var Chorasmian *RangeTable ++pkg unicode, var Dives_Akuru *RangeTable ++pkg unicode, var Khitan_Small_Script *RangeTable ++pkg unicode, var Yezidi *RangeTable ++pkg text/template/parse, const NodeComment = 20 ++pkg text/template/parse, const NodeComment NodeType ++pkg text/template/parse, const ParseComments = 1 ++pkg text/template/parse, const ParseComments Mode ++pkg text/template/parse, method (*CommentNode) Copy() Node ++pkg text/template/parse, method (*CommentNode) String() string ++pkg text/template/parse, method (CommentNode) Position() Pos ++pkg text/template/parse, method (CommentNode) Type() NodeType ++pkg text/template/parse, type CommentNode struct ++pkg text/template/parse, type CommentNode struct, Text string ++pkg text/template/parse, type CommentNode struct, embedded NodeType ++pkg text/template/parse, type CommentNode struct, embedded Pos ++pkg text/template/parse, type Mode uint ++pkg text/template/parse, type Tree struct, Mode Mode +diff --git a/src/html/template/escape.go b/src/html/template/escape.go +index f12dafa..8739735 100644 +--- a/src/html/template/escape.go ++++ b/src/html/template/escape.go +@@ -124,6 +124,8 @@ func (e *escaper) escape(c context, n parse.Node) context { + switch n := n.(type) { + case *parse.ActionNode: + return e.escapeAction(c, n) ++ case *parse.CommentNode: ++ return c + case *parse.IfNode: + return e.escapeBranch(c, &n.BranchNode, "if") + case *parse.ListNode: +diff --git a/src/html/template/template_test.go b/src/html/template/template_test.go +index 86bd4db..1f2c888 100644 +--- a/src/html/template/template_test.go ++++ b/src/html/template/template_test.go +@@ -10,6 +10,7 @@ import ( + . "html/template" + "strings" + "testing" ++ "text/template/parse" + ) + + func TestTemplateClone(t *testing.T) { +@@ -160,6 +161,21 @@ func TestStringsInScriptsWithJsonContentTypeAreCorrectlyEscaped(t *testing.T) { + } + } + ++func TestSkipEscapeComments(t *testing.T) { ++ c := newTestCase(t) ++ tr := parse.New("root") ++ tr.Mode = parse.ParseComments ++ newT, err := tr.Parse("{{/* A comment */}}{{ 1 }}{{/* Another comment */}}", "", "", make(map[string]*parse.Tree)) ++ if err != nil { ++ t.Fatalf("Cannot parse template text: %v", err) ++ } ++ c.root, err = c.root.AddParseTree("root", newT) ++ if err != nil { ++ t.Fatalf("Cannot add parse tree to template: %v", err) ++ } ++ c.mustExecute(c.root, nil, "1") ++} ++ + type testCase struct { + t *testing.T + root *Template +diff --git a/src/text/template/exec.go b/src/text/template/exec.go +index ac3e741..7ac5175 100644 +--- a/src/text/template/exec.go ++++ b/src/text/template/exec.go +@@ -256,6 +256,7 @@ func (s *state) walk(dot reflect.Value, node parse.Node) { + if len(node.Pipe.Decl) == 0 { + s.printValue(node, val) + } ++ case *parse.CommentNode: + case *parse.IfNode: + s.walkIfOrWith(parse.NodeIf, dot, node.Pipe, node.List, node.ElseList) + case *parse.ListNode: +diff --git a/src/text/template/parse/lex.go b/src/text/template/parse/lex.go +index 30371f2..e41373a 100644 +--- a/src/text/template/parse/lex.go ++++ b/src/text/template/parse/lex.go +@@ -41,6 +41,7 @@ const ( + itemBool // boolean constant + itemChar // printable ASCII character; grab bag for comma etc. + itemCharConstant // character constant ++ itemComment // comment text + itemComplex // complex constant (1+2i); imaginary is just a number + itemAssign // equals ('=') introducing an assignment + itemDeclare // colon-equals (':=') introducing a declaration +@@ -112,6 +113,7 @@ type lexer struct { + leftDelim string // start of action + rightDelim string // end of action + trimRightDelim string // end of action with trim marker ++ emitComment bool // emit itemComment tokens. + pos Pos // current position in the input + start Pos // start position of this item + width Pos // width of last rune read from input +@@ -203,7 +205,7 @@ func (l *lexer) drain() { + } + + // lex creates a new scanner for the input string. +-func lex(name, input, left, right string) *lexer { ++func lex(name, input, left, right string, emitComment bool) *lexer { + if left == "" { + left = leftDelim + } +@@ -216,6 +218,7 @@ func lex(name, input, left, right string) *lexer { + leftDelim: left, + rightDelim: right, + trimRightDelim: rightTrimMarker + right, ++ emitComment: emitComment, + items: make(chan item), + line: 1, + startLine: 1, +@@ -323,6 +326,9 @@ func lexComment(l *lexer) stateFn { + if !delim { + return l.errorf("comment ends before closing delimiter") + } ++ if l.emitComment { ++ l.emit(itemComment) ++ } + if trimSpace { + l.pos += trimMarkerLen + } +diff --git a/src/text/template/parse/lex_test.go b/src/text/template/parse/lex_test.go +index 563c4fc..f6d5f28 100644 +--- a/src/text/template/parse/lex_test.go ++++ b/src/text/template/parse/lex_test.go +@@ -15,6 +15,7 @@ var itemName = map[itemType]string{ + itemBool: "bool", + itemChar: "char", + itemCharConstant: "charconst", ++ itemComment: "comment", + itemComplex: "complex", + itemDeclare: ":=", + itemEOF: "EOF", +@@ -90,6 +91,7 @@ var lexTests = []lexTest{ + {"text", `now is the time`, []item{mkItem(itemText, "now is the time"), tEOF}}, + {"text with comment", "hello-{{/* this is a comment */}}-world", []item{ + mkItem(itemText, "hello-"), ++ mkItem(itemComment, "/* this is a comment */"), + mkItem(itemText, "-world"), + tEOF, + }}, +@@ -311,6 +313,7 @@ var lexTests = []lexTest{ + }}, + {"trimming spaces before and after comment", "hello- {{- /* hello */ -}} -world", []item{ + mkItem(itemText, "hello-"), ++ mkItem(itemComment, "/* hello */"), + mkItem(itemText, "-world"), + tEOF, + }}, +@@ -389,7 +392,7 @@ var lexTests = []lexTest{ + + // collect gathers the emitted items into a slice. + func collect(t *lexTest, left, right string) (items []item) { +- l := lex(t.name, t.input, left, right) ++ l := lex(t.name, t.input, left, right, true) + for { + item := l.nextItem() + items = append(items, item) +@@ -529,7 +532,7 @@ func TestPos(t *testing.T) { + func TestShutdown(t *testing.T) { + // We need to duplicate template.Parse here to hold on to the lexer. + const text = "erroneous{{define}}{{else}}1234" +- lexer := lex("foo", text, "{{", "}}") ++ lexer := lex("foo", text, "{{", "}}", false) + _, err := New("root").parseLexer(lexer) + if err == nil { + t.Fatalf("expected error") +diff --git a/src/text/template/parse/node.go b/src/text/template/parse/node.go +index 1c116ea..a9dad5e 100644 +--- a/src/text/template/parse/node.go ++++ b/src/text/template/parse/node.go +@@ -70,6 +70,7 @@ const ( + NodeTemplate // A template invocation action. + NodeVariable // A $ variable. + NodeWith // A with action. ++ NodeComment // A comment. + ) + + // Nodes. +@@ -149,6 +150,38 @@ func (t *TextNode) Copy() Node { + return &TextNode{tr: t.tr, NodeType: NodeText, Pos: t.Pos, Text: append([]byte{}, t.Text...)} + } + ++// CommentNode holds a comment. ++type CommentNode struct { ++ NodeType ++ Pos ++ tr *Tree ++ Text string // Comment text. ++} ++ ++func (t *Tree) newComment(pos Pos, text string) *CommentNode { ++ return &CommentNode{tr: t, NodeType: NodeComment, Pos: pos, Text: text} ++} ++ ++func (c *CommentNode) String() string { ++ var sb strings.Builder ++ c.writeTo(&sb) ++ return sb.String() ++} ++ ++func (c *CommentNode) writeTo(sb *strings.Builder) { ++ sb.WriteString("{{") ++ sb.WriteString(c.Text) ++ sb.WriteString("}}") ++} ++ ++func (c *CommentNode) tree() *Tree { ++ return c.tr ++} ++ ++func (c *CommentNode) Copy() Node { ++ return &CommentNode{tr: c.tr, NodeType: NodeComment, Pos: c.Pos, Text: c.Text} ++} ++ + // PipeNode holds a pipeline with optional declaration + type PipeNode struct { + NodeType +diff --git a/src/text/template/parse/parse.go b/src/text/template/parse/parse.go +index c9b80f4..496d8bf 100644 +--- a/src/text/template/parse/parse.go ++++ b/src/text/template/parse/parse.go +@@ -21,6 +21,7 @@ type Tree struct { + Name string // name of the template represented by the tree. + ParseName string // name of the top-level template during parsing, for error messages. + Root *ListNode // top-level root of the tree. ++ Mode Mode // parsing mode. + text string // text parsed to create the template (or its parent) + // Parsing only; cleared after parse. + funcs []map[string]interface{} +@@ -29,8 +30,16 @@ type Tree struct { + peekCount int + vars []string // variables defined at the moment. + treeSet map[string]*Tree ++ mode Mode + } + ++// A mode value is a set of flags (or 0). Modes control parser behavior. ++type Mode uint ++ ++const ( ++ ParseComments Mode = 1 << iota // parse comments and add them to AST ++) ++ + // Copy returns a copy of the Tree. Any parsing state is discarded. + func (t *Tree) Copy() *Tree { + if t == nil { +@@ -220,7 +229,8 @@ func (t *Tree) stopParse() { + func (t *Tree) Parse(text, leftDelim, rightDelim string, treeSet map[string]*Tree, funcs ...map[string]interface{}) (tree *Tree, err error) { + defer t.recover(&err) + t.ParseName = t.Name +- t.startParse(funcs, lex(t.Name, text, leftDelim, rightDelim), treeSet) ++ emitComment := t.Mode&ParseComments != 0 ++ t.startParse(funcs, lex(t.Name, text, leftDelim, rightDelim, emitComment), treeSet) + t.text = text + t.parse() + t.add() +@@ -240,12 +250,14 @@ func (t *Tree) add() { + } + } + +-// IsEmptyTree reports whether this tree (node) is empty of everything but space. ++// IsEmptyTree reports whether this tree (node) is empty of everything but space or comments. + func IsEmptyTree(n Node) bool { + switch n := n.(type) { + case nil: + return true + case *ActionNode: ++ case *CommentNode: ++ return true + case *IfNode: + case *ListNode: + for _, node := range n.Nodes { +@@ -276,6 +288,7 @@ func (t *Tree) parse() { + if t.nextNonSpace().typ == itemDefine { + newT := New("definition") // name will be updated once we know it. + newT.text = t.text ++ newT.Mode = t.Mode + newT.ParseName = t.ParseName + newT.startParse(t.funcs, t.lex, t.treeSet) + newT.parseDefinition() +@@ -331,13 +344,15 @@ func (t *Tree) itemList() (list *ListNode, next Node) { + } + + // textOrAction: +-// text | action ++// text | comment | action + func (t *Tree) textOrAction() Node { + switch token := t.nextNonSpace(); token.typ { + case itemText: + return t.newText(token.pos, token.val) + case itemLeftDelim: + return t.action() ++ case itemComment: ++ return t.newComment(token.pos, token.val) + default: + t.unexpected(token, "input") + } +@@ -539,6 +554,7 @@ func (t *Tree) blockControl() Node { + + block := New(name) // name will be updated once we know it. + block.text = t.text ++ block.Mode = t.Mode + block.ParseName = t.ParseName + block.startParse(t.funcs, t.lex, t.treeSet) + var end Node +diff --git a/src/text/template/parse/parse_test.go b/src/text/template/parse/parse_test.go +index 4e09a78..d9c13c5 100644 +--- a/src/text/template/parse/parse_test.go ++++ b/src/text/template/parse/parse_test.go +@@ -348,6 +348,30 @@ func TestParseCopy(t *testing.T) { + testParse(true, t) + } + ++func TestParseWithComments(t *testing.T) { ++ textFormat = "%q" ++ defer func() { textFormat = "%s" }() ++ tests := [...]parseTest{ ++ {"comment", "{{/*\n\n\n*/}}", noError, "{{/*\n\n\n*/}}"}, ++ {"comment trim left", "x \r\n\t{{- /* hi */}}", noError, `"x"{{/* hi */}}`}, ++ {"comment trim right", "{{/* hi */ -}}\n\n\ty", noError, `{{/* hi */}}"y"`}, ++ {"comment trim left and right", "x \r\n\t{{- /* */ -}}\n\n\ty", noError, `"x"{{/* */}}"y"`}, ++ } ++ for _, test := range tests { ++ t.Run(test.name, func(t *testing.T) { ++ tr := New(test.name) ++ tr.Mode = ParseComments ++ tmpl, err := tr.Parse(test.input, "", "", make(map[string]*Tree)) ++ if err != nil { ++ t.Errorf("%q: expected error; got none", test.name) ++ } ++ if result := tmpl.Root.String(); result != test.result { ++ t.Errorf("%s=(%q): got\n\t%v\nexpected\n\t%v", test.name, test.input, result, test.result) ++ } ++ }) ++ } ++} ++ + type isEmptyTest struct { + name string + input string +@@ -358,6 +382,7 @@ var isEmptyTests = []isEmptyTest{ + {"empty", ``, true}, + {"nonempty", `hello`, false}, + {"spaces only", " \t\n \t\n", true}, ++ {"comment only", "{{/* comment */}}", true}, + {"definition", `{{define "x"}}something{{end}}`, true}, + {"definitions and space", "{{define `x`}}something{{end}}\n\n{{define `y`}}something{{end}}\n\n", true}, + {"definitions and text", "{{define `x`}}something{{end}}\nx\n{{define `y`}}something{{end}}\ny\n", false}, +-- +2.7.4 diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-24538_4.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-24538_4.patch new file mode 100644 index 0000000000..d5e2eb6684 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-24538_4.patch @@ -0,0 +1,497 @@ +From 760d88497091fb5d6d231a18e6f4e06ecb9af9b2 Mon Sep 17 00:00:00 2001 +From: Russ Cox <rsc@golang.org> +Date: Thu, 10 Sep 2020 18:53:26 -0400 +Subject: [PATCH 4/6] text/template: allow newlines inside action delimiters + +This allows multiline constructs like: + + {{"hello" | + printf}} + +Now that unclosed actions can span multiple lines, +track and report the start of the action when reporting errors. + +Also clean up a few "unexpected <error message>" to be just "<error message>". + +Fixes #29770. + +Change-Id: I54c6c016029a8328b7902a4b6d85eab713ec3285 +Reviewed-on: https://go-review.googlesource.com/c/go/+/254257 +Trust: Russ Cox <rsc@golang.org> +Run-TryBot: Russ Cox <rsc@golang.org> +TryBot-Result: Go Bot <gobot@golang.org> +Reviewed-by: Rob Pike <r@golang.org> + +Dependency Patch #4 + +Upstream-Status: Backport from https://github.com/golang/go/commit/9384d34c58099657bb1b133beaf3ff37ada9b017 +CVE: CVE-2023-24538 +Signed-off-by: Shubham Kulkarni <skulkarni@mvista.com> +--- + src/text/template/doc.go | 21 ++++----- + src/text/template/exec_test.go | 2 +- + src/text/template/parse/lex.go | 84 +++++++++++++++++------------------ + src/text/template/parse/lex_test.go | 2 +- + src/text/template/parse/parse.go | 59 +++++++++++++----------- + src/text/template/parse/parse_test.go | 36 ++++++++++++--- + 6 files changed, 117 insertions(+), 87 deletions(-) + +diff --git a/src/text/template/doc.go b/src/text/template/doc.go +index 4b0efd2..7b30294 100644 +--- a/src/text/template/doc.go ++++ b/src/text/template/doc.go +@@ -40,16 +40,17 @@ More intricate examples appear below. + Text and spaces + + By default, all text between actions is copied verbatim when the template is +-executed. For example, the string " items are made of " in the example above appears +-on standard output when the program is run. +- +-However, to aid in formatting template source code, if an action's left delimiter +-(by default "{{") is followed immediately by a minus sign and ASCII space character +-("{{- "), all trailing white space is trimmed from the immediately preceding text. +-Similarly, if the right delimiter ("}}") is preceded by a space and minus sign +-(" -}}"), all leading white space is trimmed from the immediately following text. +-In these trim markers, the ASCII space must be present; "{{-3}}" parses as an +-action containing the number -3. ++executed. For example, the string " items are made of " in the example above ++appears on standard output when the program is run. ++ ++However, to aid in formatting template source code, if an action's left ++delimiter (by default "{{") is followed immediately by a minus sign and white ++space, all trailing white space is trimmed from the immediately preceding text. ++Similarly, if the right delimiter ("}}") is preceded by white space and a minus ++sign, all leading white space is trimmed from the immediately following text. ++In these trim markers, the white space must be present: ++"{{- 3}}" is like "{{3}}" but trims the immediately preceding text, while ++"{{-3}}" parses as an action containing the number -3. + + For instance, when executing the template whose source is + +diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go +index b8a809e..3309b33 100644 +--- a/src/text/template/exec_test.go ++++ b/src/text/template/exec_test.go +@@ -1295,7 +1295,7 @@ func TestUnterminatedStringError(t *testing.T) { + t.Fatal("expected error") + } + str := err.Error() +- if !strings.Contains(str, "X:3: unexpected unterminated raw quoted string") { ++ if !strings.Contains(str, "X:3: unterminated raw quoted string") { + t.Fatalf("unexpected error: %s", str) + } + } +diff --git a/src/text/template/parse/lex.go b/src/text/template/parse/lex.go +index e41373a..6784071 100644 +--- a/src/text/template/parse/lex.go ++++ b/src/text/template/parse/lex.go +@@ -92,15 +92,14 @@ const eof = -1 + // If the action begins "{{- " rather than "{{", then all space/tab/newlines + // preceding the action are trimmed; conversely if it ends " -}}" the + // leading spaces are trimmed. This is done entirely in the lexer; the +-// parser never sees it happen. We require an ASCII space to be +-// present to avoid ambiguity with things like "{{-3}}". It reads ++// parser never sees it happen. We require an ASCII space (' ', \t, \r, \n) ++// to be present to avoid ambiguity with things like "{{-3}}". It reads + // better with the space present anyway. For simplicity, only ASCII +-// space does the job. ++// does the job. + const ( +- spaceChars = " \t\r\n" // These are the space characters defined by Go itself. +- leftTrimMarker = "- " // Attached to left delimiter, trims trailing spaces from preceding text. +- rightTrimMarker = " -" // Attached to right delimiter, trims leading spaces from following text. +- trimMarkerLen = Pos(len(leftTrimMarker)) ++ spaceChars = " \t\r\n" // These are the space characters defined by Go itself. ++ trimMarker = '-' // Attached to left/right delimiter, trims trailing spaces from preceding/following text. ++ trimMarkerLen = Pos(1 + 1) // marker plus space before or after + ) + + // stateFn represents the state of the scanner as a function that returns the next state. +@@ -108,19 +107,18 @@ type stateFn func(*lexer) stateFn + + // lexer holds the state of the scanner. + type lexer struct { +- name string // the name of the input; used only for error reports +- input string // the string being scanned +- leftDelim string // start of action +- rightDelim string // end of action +- trimRightDelim string // end of action with trim marker +- emitComment bool // emit itemComment tokens. +- pos Pos // current position in the input +- start Pos // start position of this item +- width Pos // width of last rune read from input +- items chan item // channel of scanned items +- parenDepth int // nesting depth of ( ) exprs +- line int // 1+number of newlines seen +- startLine int // start line of this item ++ name string // the name of the input; used only for error reports ++ input string // the string being scanned ++ leftDelim string // start of action ++ rightDelim string // end of action ++ emitComment bool // emit itemComment tokens. ++ pos Pos // current position in the input ++ start Pos // start position of this item ++ width Pos // width of last rune read from input ++ items chan item // channel of scanned items ++ parenDepth int // nesting depth of ( ) exprs ++ line int // 1+number of newlines seen ++ startLine int // start line of this item + } + + // next returns the next rune in the input. +@@ -213,15 +211,14 @@ func lex(name, input, left, right string, emitComment bool) *lexer { + right = rightDelim + } + l := &lexer{ +- name: name, +- input: input, +- leftDelim: left, +- rightDelim: right, +- trimRightDelim: rightTrimMarker + right, +- emitComment: emitComment, +- items: make(chan item), +- line: 1, +- startLine: 1, ++ name: name, ++ input: input, ++ leftDelim: left, ++ rightDelim: right, ++ emitComment: emitComment, ++ items: make(chan item), ++ line: 1, ++ startLine: 1, + } + go l.run() + return l +@@ -251,7 +248,7 @@ func lexText(l *lexer) stateFn { + ldn := Pos(len(l.leftDelim)) + l.pos += Pos(x) + trimLength := Pos(0) +- if strings.HasPrefix(l.input[l.pos+ldn:], leftTrimMarker) { ++ if hasLeftTrimMarker(l.input[l.pos+ldn:]) { + trimLength = rightTrimLength(l.input[l.start:l.pos]) + } + l.pos -= trimLength +@@ -280,7 +277,7 @@ func rightTrimLength(s string) Pos { + + // atRightDelim reports whether the lexer is at a right delimiter, possibly preceded by a trim marker. + func (l *lexer) atRightDelim() (delim, trimSpaces bool) { +- if strings.HasPrefix(l.input[l.pos:], l.trimRightDelim) { // With trim marker. ++ if hasRightTrimMarker(l.input[l.pos:]) && strings.HasPrefix(l.input[l.pos+trimMarkerLen:], l.rightDelim) { // With trim marker. + return true, true + } + if strings.HasPrefix(l.input[l.pos:], l.rightDelim) { // Without trim marker. +@@ -297,7 +294,7 @@ func leftTrimLength(s string) Pos { + // lexLeftDelim scans the left delimiter, which is known to be present, possibly with a trim marker. + func lexLeftDelim(l *lexer) stateFn { + l.pos += Pos(len(l.leftDelim)) +- trimSpace := strings.HasPrefix(l.input[l.pos:], leftTrimMarker) ++ trimSpace := hasLeftTrimMarker(l.input[l.pos:]) + afterMarker := Pos(0) + if trimSpace { + afterMarker = trimMarkerLen +@@ -342,7 +339,7 @@ func lexComment(l *lexer) stateFn { + + // lexRightDelim scans the right delimiter, which is known to be present, possibly with a trim marker. + func lexRightDelim(l *lexer) stateFn { +- trimSpace := strings.HasPrefix(l.input[l.pos:], rightTrimMarker) ++ trimSpace := hasRightTrimMarker(l.input[l.pos:]) + if trimSpace { + l.pos += trimMarkerLen + l.ignore() +@@ -369,7 +366,7 @@ func lexInsideAction(l *lexer) stateFn { + return l.errorf("unclosed left paren") + } + switch r := l.next(); { +- case r == eof || isEndOfLine(r): ++ case r == eof: + return l.errorf("unclosed action") + case isSpace(r): + l.backup() // Put space back in case we have " -}}". +@@ -439,7 +436,7 @@ func lexSpace(l *lexer) stateFn { + } + // Be careful about a trim-marked closing delimiter, which has a minus + // after a space. We know there is a space, so check for the '-' that might follow. +- if strings.HasPrefix(l.input[l.pos-1:], l.trimRightDelim) { ++ if hasRightTrimMarker(l.input[l.pos-1:]) && strings.HasPrefix(l.input[l.pos-1+trimMarkerLen:], l.rightDelim) { + l.backup() // Before the space. + if numSpaces == 1 { + return lexRightDelim // On the delim, so go right to that. +@@ -526,7 +523,7 @@ func lexFieldOrVariable(l *lexer, typ itemType) stateFn { + // day to implement arithmetic. + func (l *lexer) atTerminator() bool { + r := l.peek() +- if isSpace(r) || isEndOfLine(r) { ++ if isSpace(r) { + return true + } + switch r { +@@ -657,15 +654,18 @@ Loop: + + // isSpace reports whether r is a space character. + func isSpace(r rune) bool { +- return r == ' ' || r == '\t' +-} +- +-// isEndOfLine reports whether r is an end-of-line character. +-func isEndOfLine(r rune) bool { +- return r == '\r' || r == '\n' ++ return r == ' ' || r == '\t' || r == '\r' || r == '\n' + } + + // isAlphaNumeric reports whether r is an alphabetic, digit, or underscore. + func isAlphaNumeric(r rune) bool { + return r == '_' || unicode.IsLetter(r) || unicode.IsDigit(r) + } ++ ++func hasLeftTrimMarker(s string) bool { ++ return len(s) >= 2 && s[0] == trimMarker && isSpace(rune(s[1])) ++} ++ ++func hasRightTrimMarker(s string) bool { ++ return len(s) >= 2 && isSpace(rune(s[0])) && s[1] == trimMarker ++} +diff --git a/src/text/template/parse/lex_test.go b/src/text/template/parse/lex_test.go +index f6d5f28..6510eed 100644 +--- a/src/text/template/parse/lex_test.go ++++ b/src/text/template/parse/lex_test.go +@@ -323,7 +323,7 @@ var lexTests = []lexTest{ + tLeft, + mkItem(itemError, "unrecognized character in action: U+0001"), + }}, +- {"unclosed action", "{{\n}}", []item{ ++ {"unclosed action", "{{", []item{ + tLeft, + mkItem(itemError, "unclosed action"), + }}, +diff --git a/src/text/template/parse/parse.go b/src/text/template/parse/parse.go +index 496d8bf..5e6e512 100644 +--- a/src/text/template/parse/parse.go ++++ b/src/text/template/parse/parse.go +@@ -24,13 +24,14 @@ type Tree struct { + Mode Mode // parsing mode. + text string // text parsed to create the template (or its parent) + // Parsing only; cleared after parse. +- funcs []map[string]interface{} +- lex *lexer +- token [3]item // three-token lookahead for parser. +- peekCount int +- vars []string // variables defined at the moment. +- treeSet map[string]*Tree +- mode Mode ++ funcs []map[string]interface{} ++ lex *lexer ++ token [3]item // three-token lookahead for parser. ++ peekCount int ++ vars []string // variables defined at the moment. ++ treeSet map[string]*Tree ++ actionLine int // line of left delim starting action ++ mode Mode + } + + // A mode value is a set of flags (or 0). Modes control parser behavior. +@@ -187,6 +188,16 @@ func (t *Tree) expectOneOf(expected1, expected2 itemType, context string) item { + + // unexpected complains about the token and terminates processing. + func (t *Tree) unexpected(token item, context string) { ++ if token.typ == itemError { ++ extra := "" ++ if t.actionLine != 0 && t.actionLine != token.line { ++ extra = fmt.Sprintf(" in action started at %s:%d", t.ParseName, t.actionLine) ++ if strings.HasSuffix(token.val, " action") { ++ extra = extra[len(" in action"):] // avoid "action in action" ++ } ++ } ++ t.errorf("%s%s", token, extra) ++ } + t.errorf("unexpected %s in %s", token, context) + } + +@@ -350,6 +361,8 @@ func (t *Tree) textOrAction() Node { + case itemText: + return t.newText(token.pos, token.val) + case itemLeftDelim: ++ t.actionLine = token.line ++ defer t.clearActionLine() + return t.action() + case itemComment: + return t.newComment(token.pos, token.val) +@@ -359,6 +372,10 @@ func (t *Tree) textOrAction() Node { + return nil + } + ++func (t *Tree) clearActionLine() { ++ t.actionLine = 0 ++} ++ + // Action: + // control + // command ("|" command)* +@@ -384,12 +401,12 @@ func (t *Tree) action() (n Node) { + t.backup() + token := t.peek() + // Do not pop variables; they persist until "end". +- return t.newAction(token.pos, token.line, t.pipeline("command")) ++ return t.newAction(token.pos, token.line, t.pipeline("command", itemRightDelim)) + } + + // Pipeline: + // declarations? command ('|' command)* +-func (t *Tree) pipeline(context string) (pipe *PipeNode) { ++func (t *Tree) pipeline(context string, end itemType) (pipe *PipeNode) { + token := t.peekNonSpace() + pipe = t.newPipeline(token.pos, token.line, nil) + // Are there declarations or assignments? +@@ -430,12 +447,9 @@ decls: + } + for { + switch token := t.nextNonSpace(); token.typ { +- case itemRightDelim, itemRightParen: ++ case end: + // At this point, the pipeline is complete + t.checkPipeline(pipe, context) +- if token.typ == itemRightParen { +- t.backup() +- } + return + case itemBool, itemCharConstant, itemComplex, itemDot, itemField, itemIdentifier, + itemNumber, itemNil, itemRawString, itemString, itemVariable, itemLeftParen: +@@ -464,7 +478,7 @@ func (t *Tree) checkPipeline(pipe *PipeNode, context string) { + + func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) { + defer t.popVars(len(t.vars)) +- pipe = t.pipeline(context) ++ pipe = t.pipeline(context, itemRightDelim) + var next Node + list, next = t.itemList() + switch next.Type() { +@@ -550,7 +564,7 @@ func (t *Tree) blockControl() Node { + + token := t.nextNonSpace() + name := t.parseTemplateName(token, context) +- pipe := t.pipeline(context) ++ pipe := t.pipeline(context, itemRightDelim) + + block := New(name) // name will be updated once we know it. + block.text = t.text +@@ -580,7 +594,7 @@ func (t *Tree) templateControl() Node { + if t.nextNonSpace().typ != itemRightDelim { + t.backup() + // Do not pop variables; they persist until "end". +- pipe = t.pipeline(context) ++ pipe = t.pipeline(context, itemRightDelim) + } + return t.newTemplate(token.pos, token.line, name, pipe) + } +@@ -614,13 +628,12 @@ func (t *Tree) command() *CommandNode { + switch token := t.next(); token.typ { + case itemSpace: + continue +- case itemError: +- t.errorf("%s", token.val) + case itemRightDelim, itemRightParen: + t.backup() + case itemPipe: ++ // nothing here; break loop below + default: +- t.errorf("unexpected %s in operand", token) ++ t.unexpected(token, "operand") + } + break + } +@@ -675,8 +688,6 @@ func (t *Tree) operand() Node { + // A nil return means the next item is not a term. + func (t *Tree) term() Node { + switch token := t.nextNonSpace(); token.typ { +- case itemError: +- t.errorf("%s", token.val) + case itemIdentifier: + if !t.hasFunction(token.val) { + t.errorf("function %q not defined", token.val) +@@ -699,11 +710,7 @@ func (t *Tree) term() Node { + } + return number + case itemLeftParen: +- pipe := t.pipeline("parenthesized pipeline") +- if token := t.next(); token.typ != itemRightParen { +- t.errorf("unclosed right paren: unexpected %s", token) +- } +- return pipe ++ return t.pipeline("parenthesized pipeline", itemRightParen) + case itemString, itemRawString: + s, err := strconv.Unquote(token.val) + if err != nil { +diff --git a/src/text/template/parse/parse_test.go b/src/text/template/parse/parse_test.go +index d9c13c5..220f984 100644 +--- a/src/text/template/parse/parse_test.go ++++ b/src/text/template/parse/parse_test.go +@@ -250,6 +250,13 @@ var parseTests = []parseTest{ + {"comment trim left and right", "x \r\n\t{{- /* */ -}}\n\n\ty", noError, `"x""y"`}, + {"block definition", `{{block "foo" .}}hello{{end}}`, noError, + `{{template "foo" .}}`}, ++ ++ {"newline in assignment", "{{ $x \n := \n 1 \n }}", noError, "{{$x := 1}}"}, ++ {"newline in empty action", "{{\n}}", hasError, "{{\n}}"}, ++ {"newline in pipeline", "{{\n\"x\"\n|\nprintf\n}}", noError, `{{"x" | printf}}`}, ++ {"newline in comment", "{{/*\nhello\n*/}}", noError, ""}, ++ {"newline in comment", "{{-\n/*\nhello\n*/\n-}}", noError, ""}, ++ + // Errors. + {"unclosed action", "hello{{range", hasError, ""}, + {"unmatched end", "{{end}}", hasError, ""}, +@@ -426,23 +433,38 @@ var errorTests = []parseTest{ + // Check line numbers are accurate. + {"unclosed1", + "line1\n{{", +- hasError, `unclosed1:2: unexpected unclosed action in command`}, ++ hasError, `unclosed1:2: unclosed action`}, + {"unclosed2", + "line1\n{{define `x`}}line2\n{{", +- hasError, `unclosed2:3: unexpected unclosed action in command`}, ++ hasError, `unclosed2:3: unclosed action`}, ++ {"unclosed3", ++ "line1\n{{\"x\"\n\"y\"\n", ++ hasError, `unclosed3:4: unclosed action started at unclosed3:2`}, ++ {"unclosed4", ++ "{{\n\n\n\n\n", ++ hasError, `unclosed4:6: unclosed action started at unclosed4:1`}, ++ {"var1", ++ "line1\n{{\nx\n}}", ++ hasError, `var1:3: function "x" not defined`}, + // Specific errors. + {"function", + "{{foo}}", + hasError, `function "foo" not defined`}, +- {"comment", ++ {"comment1", + "{{/*}}", +- hasError, `unclosed comment`}, ++ hasError, `comment1:1: unclosed comment`}, ++ {"comment2", ++ "{{/*\nhello\n}}", ++ hasError, `comment2:1: unclosed comment`}, + {"lparen", + "{{.X (1 2 3}}", + hasError, `unclosed left paren`}, + {"rparen", +- "{{.X 1 2 3)}}", +- hasError, `unexpected ")"`}, ++ "{{.X 1 2 3 ) }}", ++ hasError, `unexpected ")" in command`}, ++ {"rparen2", ++ "{{(.X 1 2 3", ++ hasError, `unclosed action`}, + {"space", + "{{`x`3}}", + hasError, `in operand`}, +@@ -488,7 +510,7 @@ var errorTests = []parseTest{ + hasError, `missing value for parenthesized pipeline`}, + {"multilinerawstring", + "{{ $v := `\n` }} {{", +- hasError, `multilinerawstring:2: unexpected unclosed action`}, ++ hasError, `multilinerawstring:2: unclosed action`}, + {"rangeundefvar", + "{{range $k}}{{end}}", + hasError, `undefined variable`}, +-- +2.7.4 diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-24538_5.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-24538_5.patch new file mode 100644 index 0000000000..fc38929648 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-24538_5.patch @@ -0,0 +1,585 @@ +From e0e6bca6ddc0e6d9fa3a5b644af9b446924fbf83 Mon Sep 17 00:00:00 2001 +From: Russ Cox <rsc@golang.org> +Date: Thu, 20 May 2021 12:46:33 -0400 +Subject: [PATCH 5/6] html/template, text/template: implement break and + continue for range loops + +Break and continue for range loops was accepted as a proposal in June 2017. +It was implemented in CL 66410 (Oct 2017) +but then rolled back in CL 92155 (Feb 2018) +because html/template changes had not been implemented. + +This CL reimplements break and continue in text/template +and then adds support for them in html/template as well. + +Fixes #20531. + +Change-Id: I05330482a976f1c078b4b49c2287bd9031bb7616 +Reviewed-on: https://go-review.googlesource.com/c/go/+/321491 +Trust: Russ Cox <rsc@golang.org> +Run-TryBot: Russ Cox <rsc@golang.org> +TryBot-Result: Go Bot <gobot@golang.org> +Reviewed-by: Rob Pike <r@golang.org> + +Dependency Patch #5 + +Upstream-Status: Backport from https://github.com/golang/go/commit/d0dd26a88c019d54f22463daae81e785f5867565 +CVE: CVE-2023-24538 +Signed-off-by: Shubham Kulkarni <skulkarni@mvista.com> +--- + src/html/template/context.go | 4 ++ + src/html/template/escape.go | 71 ++++++++++++++++++++++++++++++++++- + src/html/template/escape_test.go | 24 ++++++++++++ + src/text/template/doc.go | 8 ++++ + src/text/template/exec.go | 24 +++++++++++- + src/text/template/exec_test.go | 2 + + src/text/template/parse/lex.go | 13 ++++++- + src/text/template/parse/lex_test.go | 2 + + src/text/template/parse/node.go | 36 ++++++++++++++++++ + src/text/template/parse/parse.go | 42 ++++++++++++++++++++- + src/text/template/parse/parse_test.go | 8 ++++ + 11 files changed, 230 insertions(+), 4 deletions(-) + +diff --git a/src/html/template/context.go b/src/html/template/context.go +index f7d4849..aaa7d08 100644 +--- a/src/html/template/context.go ++++ b/src/html/template/context.go +@@ -6,6 +6,7 @@ package template + + import ( + "fmt" ++ "text/template/parse" + ) + + // context describes the state an HTML parser must be in when it reaches the +@@ -22,6 +23,7 @@ type context struct { + jsCtx jsCtx + attr attr + element element ++ n parse.Node // for range break/continue + err *Error + } + +@@ -141,6 +143,8 @@ const ( + // stateError is an infectious error state outside any valid + // HTML/CSS/JS construct. + stateError ++ // stateDead marks unreachable code after a {{break}} or {{continue}}. ++ stateDead + ) + + // isComment is true for any state that contains content meant for template +diff --git a/src/html/template/escape.go b/src/html/template/escape.go +index 8739735..6dea79c 100644 +--- a/src/html/template/escape.go ++++ b/src/html/template/escape.go +@@ -97,6 +97,15 @@ type escaper struct { + actionNodeEdits map[*parse.ActionNode][]string + templateNodeEdits map[*parse.TemplateNode]string + textNodeEdits map[*parse.TextNode][]byte ++ // rangeContext holds context about the current range loop. ++ rangeContext *rangeContext ++} ++ ++// rangeContext holds information about the current range loop. ++type rangeContext struct { ++ outer *rangeContext // outer loop ++ breaks []context // context at each break action ++ continues []context // context at each continue action + } + + // makeEscaper creates a blank escaper for the given set. +@@ -109,6 +118,7 @@ func makeEscaper(n *nameSpace) escaper { + map[*parse.ActionNode][]string{}, + map[*parse.TemplateNode]string{}, + map[*parse.TextNode][]byte{}, ++ nil, + } + } + +@@ -124,8 +134,16 @@ func (e *escaper) escape(c context, n parse.Node) context { + switch n := n.(type) { + case *parse.ActionNode: + return e.escapeAction(c, n) ++ case *parse.BreakNode: ++ c.n = n ++ e.rangeContext.breaks = append(e.rangeContext.breaks, c) ++ return context{state: stateDead} + case *parse.CommentNode: + return c ++ case *parse.ContinueNode: ++ c.n = n ++ e.rangeContext.continues = append(e.rangeContext.breaks, c) ++ return context{state: stateDead} + case *parse.IfNode: + return e.escapeBranch(c, &n.BranchNode, "if") + case *parse.ListNode: +@@ -427,6 +445,12 @@ func join(a, b context, node parse.Node, nodeName string) context { + if b.state == stateError { + return b + } ++ if a.state == stateDead { ++ return b ++ } ++ if b.state == stateDead { ++ return a ++ } + if a.eq(b) { + return a + } +@@ -466,14 +490,27 @@ func join(a, b context, node parse.Node, nodeName string) context { + + // escapeBranch escapes a branch template node: "if", "range" and "with". + func (e *escaper) escapeBranch(c context, n *parse.BranchNode, nodeName string) context { ++ if nodeName == "range" { ++ e.rangeContext = &rangeContext{outer: e.rangeContext} ++ } + c0 := e.escapeList(c, n.List) +- if nodeName == "range" && c0.state != stateError { ++ if nodeName == "range" { ++ if c0.state != stateError { ++ c0 = joinRange(c0, e.rangeContext) ++ } ++ e.rangeContext = e.rangeContext.outer ++ if c0.state == stateError { ++ return c0 ++ } ++ + // The "true" branch of a "range" node can execute multiple times. + // We check that executing n.List once results in the same context + // as executing n.List twice. ++ e.rangeContext = &rangeContext{outer: e.rangeContext} + c1, _ := e.escapeListConditionally(c0, n.List, nil) + c0 = join(c0, c1, n, nodeName) + if c0.state == stateError { ++ e.rangeContext = e.rangeContext.outer + // Make clear that this is a problem on loop re-entry + // since developers tend to overlook that branch when + // debugging templates. +@@ -481,11 +518,39 @@ func (e *escaper) escapeBranch(c context, n *parse.BranchNode, nodeName string) + c0.err.Description = "on range loop re-entry: " + c0.err.Description + return c0 + } ++ c0 = joinRange(c0, e.rangeContext) ++ e.rangeContext = e.rangeContext.outer ++ if c0.state == stateError { ++ return c0 ++ } + } + c1 := e.escapeList(c, n.ElseList) + return join(c0, c1, n, nodeName) + } + ++func joinRange(c0 context, rc *rangeContext) context { ++ // Merge contexts at break and continue statements into overall body context. ++ // In theory we could treat breaks differently from continues, but for now it is ++ // enough to treat them both as going back to the start of the loop (which may then stop). ++ for _, c := range rc.breaks { ++ c0 = join(c0, c, c.n, "range") ++ if c0.state == stateError { ++ c0.err.Line = c.n.(*parse.BreakNode).Line ++ c0.err.Description = "at range loop break: " + c0.err.Description ++ return c0 ++ } ++ } ++ for _, c := range rc.continues { ++ c0 = join(c0, c, c.n, "range") ++ if c0.state == stateError { ++ c0.err.Line = c.n.(*parse.ContinueNode).Line ++ c0.err.Description = "at range loop continue: " + c0.err.Description ++ return c0 ++ } ++ } ++ return c0 ++} ++ + // escapeList escapes a list template node. + func (e *escaper) escapeList(c context, n *parse.ListNode) context { + if n == nil { +@@ -493,6 +558,9 @@ func (e *escaper) escapeList(c context, n *parse.ListNode) context { + } + for _, m := range n.Nodes { + c = e.escape(c, m) ++ if c.state == stateDead { ++ break ++ } + } + return c + } +@@ -503,6 +571,7 @@ func (e *escaper) escapeList(c context, n *parse.ListNode) context { + // which is the same as whether e was updated. + func (e *escaper) escapeListConditionally(c context, n *parse.ListNode, filter func(*escaper, context) bool) (context, bool) { + e1 := makeEscaper(e.ns) ++ e1.rangeContext = e.rangeContext + // Make type inferences available to f. + for k, v := range e.output { + e1.output[k] = v +diff --git a/src/html/template/escape_test.go b/src/html/template/escape_test.go +index c709660..fa2b84a 100644 +--- a/src/html/template/escape_test.go ++++ b/src/html/template/escape_test.go +@@ -920,6 +920,22 @@ func TestErrors(t *testing.T) { + "<a href='/foo?{{range .Items}}&{{.K}}={{.V}}{{end}}'>", + "", + }, ++ { ++ "{{range .Items}}<a{{if .X}}{{end}}>{{end}}", ++ "", ++ }, ++ { ++ "{{range .Items}}<a{{if .X}}{{end}}>{{continue}}{{end}}", ++ "", ++ }, ++ { ++ "{{range .Items}}<a{{if .X}}{{end}}>{{break}}{{end}}", ++ "", ++ }, ++ { ++ "{{range .Items}}<a{{if .X}}{{end}}>{{if .X}}{{break}}{{end}}{{end}}", ++ "", ++ }, + // Error cases. + { + "{{if .Cond}}<a{{end}}", +@@ -956,6 +972,14 @@ func TestErrors(t *testing.T) { + "z:2:8: on range loop re-entry: {{range}} branches", + }, + { ++ "{{range .Items}}<a{{if .X}}{{break}}{{end}}>{{end}}", ++ "z:1:29: at range loop break: {{range}} branches end in different contexts", ++ }, ++ { ++ "{{range .Items}}<a{{if .X}}{{continue}}{{end}}>{{end}}", ++ "z:1:29: at range loop continue: {{range}} branches end in different contexts", ++ }, ++ { + "<a b=1 c={{.H}}", + "z: ends in a non-text context: {stateAttr delimSpaceOrTagEnd", + }, +diff --git a/src/text/template/doc.go b/src/text/template/doc.go +index 7b30294..0228b15 100644 +--- a/src/text/template/doc.go ++++ b/src/text/template/doc.go +@@ -112,6 +112,14 @@ data, defined in detail in the corresponding sections that follow. + T0 is executed; otherwise, dot is set to the successive elements + of the array, slice, or map and T1 is executed. + ++ {{break}} ++ The innermost {{range pipeline}} loop is ended early, stopping the ++ current iteration and bypassing all remaining iterations. ++ ++ {{continue}} ++ The current iteration of the innermost {{range pipeline}} loop is ++ stopped, and the loop starts the next iteration. ++ + {{template "name"}} + The template with the specified name is executed with nil data. + +diff --git a/src/text/template/exec.go b/src/text/template/exec.go +index 7ac5175..6cb140a 100644 +--- a/src/text/template/exec.go ++++ b/src/text/template/exec.go +@@ -5,6 +5,7 @@ + package template + + import ( ++ "errors" + "fmt" + "internal/fmtsort" + "io" +@@ -244,6 +245,12 @@ func (t *Template) DefinedTemplates() string { + return b.String() + } + ++// Sentinel errors for use with panic to signal early exits from range loops. ++var ( ++ walkBreak = errors.New("break") ++ walkContinue = errors.New("continue") ++) ++ + // Walk functions step through the major pieces of the template structure, + // generating output as they go. + func (s *state) walk(dot reflect.Value, node parse.Node) { +@@ -256,7 +263,11 @@ func (s *state) walk(dot reflect.Value, node parse.Node) { + if len(node.Pipe.Decl) == 0 { + s.printValue(node, val) + } ++ case *parse.BreakNode: ++ panic(walkBreak) + case *parse.CommentNode: ++ case *parse.ContinueNode: ++ panic(walkContinue) + case *parse.IfNode: + s.walkIfOrWith(parse.NodeIf, dot, node.Pipe, node.List, node.ElseList) + case *parse.ListNode: +@@ -335,6 +346,11 @@ func isTrue(val reflect.Value) (truth, ok bool) { + + func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) { + s.at(r) ++ defer func() { ++ if r := recover(); r != nil && r != walkBreak { ++ panic(r) ++ } ++ }() + defer s.pop(s.mark()) + val, _ := indirect(s.evalPipeline(dot, r.Pipe)) + // mark top of stack before any variables in the body are pushed. +@@ -348,8 +364,14 @@ func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) { + if len(r.Pipe.Decl) > 1 { + s.setTopVar(2, index) + } ++ defer s.pop(mark) ++ defer func() { ++ // Consume panic(walkContinue) ++ if r := recover(); r != nil && r != walkContinue { ++ panic(r) ++ } ++ }() + s.walk(elem, r.List) +- s.pop(mark) + } + switch val.Kind() { + case reflect.Array, reflect.Slice: +diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go +index 3309b33..a639f44 100644 +--- a/src/text/template/exec_test.go ++++ b/src/text/template/exec_test.go +@@ -563,6 +563,8 @@ var execTests = []execTest{ + {"range empty no else", "{{range .SIEmpty}}-{{.}}-{{end}}", "", tVal, true}, + {"range []int else", "{{range .SI}}-{{.}}-{{else}}EMPTY{{end}}", "-3--4--5-", tVal, true}, + {"range empty else", "{{range .SIEmpty}}-{{.}}-{{else}}EMPTY{{end}}", "EMPTY", tVal, true}, ++ {"range []int break else", "{{range .SI}}-{{.}}-{{break}}NOTREACHED{{else}}EMPTY{{end}}", "-3-", tVal, true}, ++ {"range []int continue else", "{{range .SI}}-{{.}}-{{continue}}NOTREACHED{{else}}EMPTY{{end}}", "-3--4--5-", tVal, true}, + {"range []bool", "{{range .SB}}-{{.}}-{{end}}", "-true--false-", tVal, true}, + {"range []int method", "{{range .SI | .MAdd .I}}-{{.}}-{{end}}", "-20--21--22-", tVal, true}, + {"range map", "{{range .MSI}}-{{.}}-{{end}}", "-1--3--2-", tVal, true}, +diff --git a/src/text/template/parse/lex.go b/src/text/template/parse/lex.go +index 6784071..95e3377 100644 +--- a/src/text/template/parse/lex.go ++++ b/src/text/template/parse/lex.go +@@ -62,6 +62,8 @@ const ( + // Keywords appear after all the rest. + itemKeyword // used only to delimit the keywords + itemBlock // block keyword ++ itemBreak // break keyword ++ itemContinue // continue keyword + itemDot // the cursor, spelled '.' + itemDefine // define keyword + itemElse // else keyword +@@ -76,6 +78,8 @@ const ( + var key = map[string]itemType{ + ".": itemDot, + "block": itemBlock, ++ "break": itemBreak, ++ "continue": itemContinue, + "define": itemDefine, + "else": itemElse, + "end": itemEnd, +@@ -119,6 +123,8 @@ type lexer struct { + parenDepth int // nesting depth of ( ) exprs + line int // 1+number of newlines seen + startLine int // start line of this item ++ breakOK bool // break keyword allowed ++ continueOK bool // continue keyword allowed + } + + // next returns the next rune in the input. +@@ -461,7 +467,12 @@ Loop: + } + switch { + case key[word] > itemKeyword: +- l.emit(key[word]) ++ item := key[word] ++ if item == itemBreak && !l.breakOK || item == itemContinue && !l.continueOK { ++ l.emit(itemIdentifier) ++ } else { ++ l.emit(item) ++ } + case word[0] == '.': + l.emit(itemField) + case word == "true", word == "false": +diff --git a/src/text/template/parse/lex_test.go b/src/text/template/parse/lex_test.go +index 6510eed..df6aabf 100644 +--- a/src/text/template/parse/lex_test.go ++++ b/src/text/template/parse/lex_test.go +@@ -35,6 +35,8 @@ var itemName = map[itemType]string{ + // keywords + itemDot: ".", + itemBlock: "block", ++ itemBreak: "break", ++ itemContinue: "continue", + itemDefine: "define", + itemElse: "else", + itemIf: "if", +diff --git a/src/text/template/parse/node.go b/src/text/template/parse/node.go +index a9dad5e..c398da0 100644 +--- a/src/text/template/parse/node.go ++++ b/src/text/template/parse/node.go +@@ -71,6 +71,8 @@ const ( + NodeVariable // A $ variable. + NodeWith // A with action. + NodeComment // A comment. ++ NodeBreak // A break action. ++ NodeContinue // A continue action. + ) + + // Nodes. +@@ -907,6 +909,40 @@ func (i *IfNode) Copy() Node { + return i.tr.newIf(i.Pos, i.Line, i.Pipe.CopyPipe(), i.List.CopyList(), i.ElseList.CopyList()) + } + ++// BreakNode represents a {{break}} action. ++type BreakNode struct { ++ tr *Tree ++ NodeType ++ Pos ++ Line int ++} ++ ++func (t *Tree) newBreak(pos Pos, line int) *BreakNode { ++ return &BreakNode{tr: t, NodeType: NodeBreak, Pos: pos, Line: line} ++} ++ ++func (b *BreakNode) Copy() Node { return b.tr.newBreak(b.Pos, b.Line) } ++func (b *BreakNode) String() string { return "{{break}}" } ++func (b *BreakNode) tree() *Tree { return b.tr } ++func (b *BreakNode) writeTo(sb *strings.Builder) { sb.WriteString("{{break}}") } ++ ++// ContinueNode represents a {{continue}} action. ++type ContinueNode struct { ++ tr *Tree ++ NodeType ++ Pos ++ Line int ++} ++ ++func (t *Tree) newContinue(pos Pos, line int) *ContinueNode { ++ return &ContinueNode{tr: t, NodeType: NodeContinue, Pos: pos, Line: line} ++} ++ ++func (c *ContinueNode) Copy() Node { return c.tr.newContinue(c.Pos, c.Line) } ++func (c *ContinueNode) String() string { return "{{continue}}" } ++func (c *ContinueNode) tree() *Tree { return c.tr } ++func (c *ContinueNode) writeTo(sb *strings.Builder) { sb.WriteString("{{continue}}") } ++ + // RangeNode represents a {{range}} action and its commands. + type RangeNode struct { + BranchNode +diff --git a/src/text/template/parse/parse.go b/src/text/template/parse/parse.go +index 5e6e512..7f78b56 100644 +--- a/src/text/template/parse/parse.go ++++ b/src/text/template/parse/parse.go +@@ -31,6 +31,7 @@ type Tree struct { + vars []string // variables defined at the moment. + treeSet map[string]*Tree + actionLine int // line of left delim starting action ++ rangeDepth int + mode Mode + } + +@@ -223,6 +224,8 @@ func (t *Tree) startParse(funcs []map[string]interface{}, lex *lexer, treeSet ma + t.vars = []string{"$"} + t.funcs = funcs + t.treeSet = treeSet ++ lex.breakOK = !t.hasFunction("break") ++ lex.continueOK = !t.hasFunction("continue") + } + + // stopParse terminates parsing. +@@ -385,6 +388,10 @@ func (t *Tree) action() (n Node) { + switch token := t.nextNonSpace(); token.typ { + case itemBlock: + return t.blockControl() ++ case itemBreak: ++ return t.breakControl(token.pos, token.line) ++ case itemContinue: ++ return t.continueControl(token.pos, token.line) + case itemElse: + return t.elseControl() + case itemEnd: +@@ -404,6 +411,32 @@ func (t *Tree) action() (n Node) { + return t.newAction(token.pos, token.line, t.pipeline("command", itemRightDelim)) + } + ++// Break: ++// {{break}} ++// Break keyword is past. ++func (t *Tree) breakControl(pos Pos, line int) Node { ++ if token := t.next(); token.typ != itemRightDelim { ++ t.unexpected(token, "in {{break}}") ++ } ++ if t.rangeDepth == 0 { ++ t.errorf("{{break}} outside {{range}}") ++ } ++ return t.newBreak(pos, line) ++} ++ ++// Continue: ++// {{continue}} ++// Continue keyword is past. ++func (t *Tree) continueControl(pos Pos, line int) Node { ++ if token := t.next(); token.typ != itemRightDelim { ++ t.unexpected(token, "in {{continue}}") ++ } ++ if t.rangeDepth == 0 { ++ t.errorf("{{continue}} outside {{range}}") ++ } ++ return t.newContinue(pos, line) ++} ++ + // Pipeline: + // declarations? command ('|' command)* + func (t *Tree) pipeline(context string, end itemType) (pipe *PipeNode) { +@@ -479,8 +512,14 @@ func (t *Tree) checkPipeline(pipe *PipeNode, context string) { + func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) { + defer t.popVars(len(t.vars)) + pipe = t.pipeline(context, itemRightDelim) ++ if context == "range" { ++ t.rangeDepth++ ++ } + var next Node + list, next = t.itemList() ++ if context == "range" { ++ t.rangeDepth-- ++ } + switch next.Type() { + case nodeEnd: //done + case nodeElse: +@@ -522,7 +561,8 @@ func (t *Tree) ifControl() Node { + // {{range pipeline}} itemList {{else}} itemList {{end}} + // Range keyword is past. + func (t *Tree) rangeControl() Node { +- return t.newRange(t.parseControl(false, "range")) ++ r := t.newRange(t.parseControl(false, "range")) ++ return r + } + + // With: +diff --git a/src/text/template/parse/parse_test.go b/src/text/template/parse/parse_test.go +index 220f984..ba45636 100644 +--- a/src/text/template/parse/parse_test.go ++++ b/src/text/template/parse/parse_test.go +@@ -230,6 +230,10 @@ var parseTests = []parseTest{ + `{{range $x := .SI}}{{.}}{{end}}`}, + {"range 2 vars", "{{range $x, $y := .SI}}{{.}}{{end}}", noError, + `{{range $x, $y := .SI}}{{.}}{{end}}`}, ++ {"range with break", "{{range .SI}}{{.}}{{break}}{{end}}", noError, ++ `{{range .SI}}{{.}}{{break}}{{end}}`}, ++ {"range with continue", "{{range .SI}}{{.}}{{continue}}{{end}}", noError, ++ `{{range .SI}}{{.}}{{continue}}{{end}}`}, + {"constants", "{{range .SI 1 -3.2i true false 'a' nil}}{{end}}", noError, + `{{range .SI 1 -3.2i true false 'a' nil}}{{end}}`}, + {"template", "{{template `x`}}", noError, +@@ -279,6 +283,10 @@ var parseTests = []parseTest{ + {"adjacent args", "{{printf 3`x`}}", hasError, ""}, + {"adjacent args with .", "{{printf `x`.}}", hasError, ""}, + {"extra end after if", "{{if .X}}a{{else if .Y}}b{{end}}{{end}}", hasError, ""}, ++ {"break outside range", "{{range .}}{{end}} {{break}}", hasError, ""}, ++ {"continue outside range", "{{range .}}{{end}} {{continue}}", hasError, ""}, ++ {"break in range else", "{{range .}}{{else}}{{break}}{{end}}", hasError, ""}, ++ {"continue in range else", "{{range .}}{{else}}{{continue}}{{end}}", hasError, ""}, + // Other kinds of assignments and operators aren't available yet. + {"bug0a", "{{$x := 0}}{{$x}}", noError, "{{$x := 0}}{{$x}}"}, + {"bug0b", "{{$x += 1}}{{$x}}", hasError, ""}, +-- +2.7.4 diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-24538_6.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-24538_6.patch new file mode 100644 index 0000000000..baf400b891 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-24538_6.patch @@ -0,0 +1,371 @@ +From 16f4882984569f179d73967c9eee679bb9b098c5 Mon Sep 17 00:00:00 2001 +From: Roland Shoemaker <bracewell@google.com> +Date: Mon, 20 Mar 2023 11:01:13 -0700 +Subject: [PATCH 6/6] html/template: disallow actions in JS template literals + +ECMAScript 6 introduced template literals[0][1] which are delimited with +backticks. These need to be escaped in a similar fashion to the +delimiters for other string literals. Additionally template literals can +contain special syntax for string interpolation. + +There is no clear way to allow safe insertion of actions within JS +template literals, as handling (JS) string interpolation inside of these +literals is rather complex. As such we've chosen to simply disallow +template actions within these template literals. + +A new error code is added for this parsing failure case, errJsTmplLit, +but it is unexported as it is not backwards compatible with other minor +release versions to introduce an API change in a minor release. We will +export this code in the next major release. + +The previous behavior (with the cavet that backticks are now escaped +properly) can be re-enabled with GODEBUG=jstmpllitinterp=1. + +This change subsumes CL471455. + +Thanks to Sohom Datta, Manipal Institute of Technology, for reporting +this issue. + +Fixes CVE-2023-24538 +For #59234 +Fixes #59271 + +[0] https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#sec-template-literals +[1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals + +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802457 +Reviewed-by: Damien Neil <dneil@google.com> +Run-TryBot: Damien Neil <dneil@google.com> +Reviewed-by: Julie Qiu <julieqiu@google.com> +Reviewed-by: Roland Shoemaker <bracewell@google.com> +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802612 +Run-TryBot: Roland Shoemaker <bracewell@google.com> +Change-Id: Ic7f10595615f2b2740d9c85ad7ef40dc0e78c04c +Reviewed-on: https://go-review.googlesource.com/c/go/+/481987 +Auto-Submit: Michael Knyszek <mknyszek@google.com> +TryBot-Result: Gopher Robot <gobot@golang.org> +Run-TryBot: Michael Knyszek <mknyszek@google.com> +Reviewed-by: Matthew Dempsky <mdempsky@google.com> + +Upstream-Status: Backport from https://github.com/golang/go/commit/b1e3ecfa06b67014429a197ec5e134ce4303ad9b +CVE: CVE-2023-24538 +Signed-off-by: Shubham Kulkarni <skulkarni@mvista.com> +--- + src/html/template/context.go | 2 ++ + src/html/template/error.go | 13 ++++++++ + src/html/template/escape.go | 11 +++++++ + src/html/template/escape_test.go | 66 ++++++++++++++++++++++----------------- + src/html/template/js.go | 2 ++ + src/html/template/js_test.go | 2 +- + src/html/template/jsctx_string.go | 9 ++++++ + src/html/template/state_string.go | 37 ++++++++++++++++++++-- + src/html/template/transition.go | 7 ++++- + 9 files changed, 116 insertions(+), 33 deletions(-) + +diff --git a/src/html/template/context.go b/src/html/template/context.go +index f7d4849..0b65313 100644 +--- a/src/html/template/context.go ++++ b/src/html/template/context.go +@@ -116,6 +116,8 @@ const ( + stateJSDqStr + // stateJSSqStr occurs inside a JavaScript single quoted string. + stateJSSqStr ++ // stateJSBqStr occurs inside a JavaScript back quoted string. ++ stateJSBqStr + // stateJSRegexp occurs inside a JavaScript regexp literal. + stateJSRegexp + // stateJSBlockCmt occurs inside a JavaScript /* block comment */. +diff --git a/src/html/template/error.go b/src/html/template/error.go +index 0e52706..fd26b64 100644 +--- a/src/html/template/error.go ++++ b/src/html/template/error.go +@@ -211,6 +211,19 @@ const ( + // pipeline occurs in an unquoted attribute value context, "html" is + // disallowed. Avoid using "html" and "urlquery" entirely in new templates. + ErrPredefinedEscaper ++ ++ // errJSTmplLit: "... appears in a JS template literal" ++ // Example: ++ // <script>var tmpl = `{{.Interp}`</script> ++ // Discussion: ++ // Package html/template does not support actions inside of JS template ++ // literals. ++ // ++ // TODO(rolandshoemaker): we cannot add this as an exported error in a minor ++ // release, since it is backwards incompatible with the other minor ++ // releases. As such we need to leave it unexported, and then we'll add it ++ // in the next major release. ++ errJSTmplLit + ) + + func (e *Error) Error() string { +diff --git a/src/html/template/escape.go b/src/html/template/escape.go +index f12dafa..29ca5b3 100644 +--- a/src/html/template/escape.go ++++ b/src/html/template/escape.go +@@ -8,6 +8,7 @@ import ( + "bytes" + "fmt" + "html" ++ "internal/godebug" + "io" + "text/template" + "text/template/parse" +@@ -203,6 +204,16 @@ func (e *escaper) escapeAction(c context, n *parse.ActionNode) context { + c.jsCtx = jsCtxDivOp + case stateJSDqStr, stateJSSqStr: + s = append(s, "_html_template_jsstrescaper") ++ case stateJSBqStr: ++ debugAllowActionJSTmpl := godebug.Get("jstmpllitinterp") ++ if debugAllowActionJSTmpl == "1" { ++ s = append(s, "_html_template_jsstrescaper") ++ } else { ++ return context{ ++ state: stateError, ++ err: errorf(errJSTmplLit, n, n.Line, "%s appears in a JS template literal", n), ++ } ++ } + case stateJSRegexp: + s = append(s, "_html_template_jsregexpescaper") + case stateCSS: +diff --git a/src/html/template/escape_test.go b/src/html/template/escape_test.go +index fa2b84a..1b150e9 100644 +--- a/src/html/template/escape_test.go ++++ b/src/html/template/escape_test.go +@@ -681,35 +681,31 @@ func TestEscape(t *testing.T) { + } + + for _, test := range tests { +- tmpl := New(test.name) +- tmpl = Must(tmpl.Parse(test.input)) +- // Check for bug 6459: Tree field was not set in Parse. +- if tmpl.Tree != tmpl.text.Tree { +- t.Errorf("%s: tree not set properly", test.name) +- continue +- } +- b := new(bytes.Buffer) +- if err := tmpl.Execute(b, data); err != nil { +- t.Errorf("%s: template execution failed: %s", test.name, err) +- continue +- } +- if w, g := test.output, b.String(); w != g { +- t.Errorf("%s: escaped output: want\n\t%q\ngot\n\t%q", test.name, w, g) +- continue +- } +- b.Reset() +- if err := tmpl.Execute(b, pdata); err != nil { +- t.Errorf("%s: template execution failed for pointer: %s", test.name, err) +- continue +- } +- if w, g := test.output, b.String(); w != g { +- t.Errorf("%s: escaped output for pointer: want\n\t%q\ngot\n\t%q", test.name, w, g) +- continue +- } +- if tmpl.Tree != tmpl.text.Tree { +- t.Errorf("%s: tree mismatch", test.name) +- continue +- } ++ t.Run(test.name, func(t *testing.T) { ++ tmpl := New(test.name) ++ tmpl = Must(tmpl.Parse(test.input)) ++ // Check for bug 6459: Tree field was not set in Parse. ++ if tmpl.Tree != tmpl.text.Tree { ++ t.Fatalf("%s: tree not set properly", test.name) ++ } ++ b := new(strings.Builder) ++ if err := tmpl.Execute(b, data); err != nil { ++ t.Fatalf("%s: template execution failed: %s", test.name, err) ++ } ++ if w, g := test.output, b.String(); w != g { ++ t.Fatalf("%s: escaped output: want\n\t%q\ngot\n\t%q", test.name, w, g) ++ } ++ b.Reset() ++ if err := tmpl.Execute(b, pdata); err != nil { ++ t.Fatalf("%s: template execution failed for pointer: %s", test.name, err) ++ } ++ if w, g := test.output, b.String(); w != g { ++ t.Fatalf("%s: escaped output for pointer: want\n\t%q\ngot\n\t%q", test.name, w, g) ++ } ++ if tmpl.Tree != tmpl.text.Tree { ++ t.Fatalf("%s: tree mismatch", test.name) ++ } ++ }) + } + } + +@@ -936,6 +932,10 @@ func TestErrors(t *testing.T) { + "{{range .Items}}<a{{if .X}}{{end}}>{{if .X}}{{break}}{{end}}{{end}}", + "", + }, ++ { ++ "<script>var a = `${a+b}`</script>`", ++ "", ++ }, + // Error cases. + { + "{{if .Cond}}<a{{end}}", +@@ -1082,6 +1082,10 @@ func TestErrors(t *testing.T) { + // html is allowed since it is the last command in the pipeline, but urlquery is not. + `predefined escaper "urlquery" disallowed in template`, + }, ++ { ++ "<script>var tmpl = `asd {{.}}`;</script>", ++ `{{.}} appears in a JS template literal`, ++ }, + } + for _, test := range tests { + buf := new(bytes.Buffer) +@@ -1304,6 +1308,10 @@ func TestEscapeText(t *testing.T) { + context{state: stateJSSqStr, delim: delimDoubleQuote, attr: attrScript}, + }, + { ++ "<a onclick=\"`foo", ++ context{state: stateJSBqStr, delim: delimDoubleQuote, attr: attrScript}, ++ }, ++ { + `<A ONCLICK="'`, + context{state: stateJSSqStr, delim: delimDoubleQuote, attr: attrScript}, + }, +diff --git a/src/html/template/js.go b/src/html/template/js.go +index ea9c183..b888eaf 100644 +--- a/src/html/template/js.go ++++ b/src/html/template/js.go +@@ -308,6 +308,7 @@ var jsStrReplacementTable = []string{ + // Encode HTML specials as hex so the output can be embedded + // in HTML attributes without further encoding. + '"': `\u0022`, ++ '`': `\u0060`, + '&': `\u0026`, + '\'': `\u0027`, + '+': `\u002b`, +@@ -331,6 +332,7 @@ var jsStrNormReplacementTable = []string{ + '"': `\u0022`, + '&': `\u0026`, + '\'': `\u0027`, ++ '`': `\u0060`, + '+': `\u002b`, + '/': `\/`, + '<': `\u003c`, +diff --git a/src/html/template/js_test.go b/src/html/template/js_test.go +index d7ee47b..7d963ae 100644 +--- a/src/html/template/js_test.go ++++ b/src/html/template/js_test.go +@@ -292,7 +292,7 @@ func TestEscapersOnLower7AndSelectHighCodepoints(t *testing.T) { + `0123456789:;\u003c=\u003e?` + + `@ABCDEFGHIJKLMNO` + + `PQRSTUVWXYZ[\\]^_` + +- "`abcdefghijklmno" + ++ "\\u0060abcdefghijklmno" + + "pqrstuvwxyz{|}~\u007f" + + "\u00A0\u0100\\u2028\\u2029\ufeff\U0001D11E", + }, +diff --git a/src/html/template/jsctx_string.go b/src/html/template/jsctx_string.go +index dd1d87e..2394893 100644 +--- a/src/html/template/jsctx_string.go ++++ b/src/html/template/jsctx_string.go +@@ -4,6 +4,15 @@ package template + + import "strconv" + ++func _() { ++ // An "invalid array index" compiler error signifies that the constant values have changed. ++ // Re-run the stringer command to generate them again. ++ var x [1]struct{} ++ _ = x[jsCtxRegexp-0] ++ _ = x[jsCtxDivOp-1] ++ _ = x[jsCtxUnknown-2] ++} ++ + const _jsCtx_name = "jsCtxRegexpjsCtxDivOpjsCtxUnknown" + + var _jsCtx_index = [...]uint8{0, 11, 21, 33} +diff --git a/src/html/template/state_string.go b/src/html/template/state_string.go +index 05104be..6fb1a6e 100644 +--- a/src/html/template/state_string.go ++++ b/src/html/template/state_string.go +@@ -4,9 +4,42 @@ package template + + import "strconv" + +-const _state_name = "stateTextstateTagstateAttrNamestateAfterNamestateBeforeValuestateHTMLCmtstateRCDATAstateAttrstateURLstateSrcsetstateJSstateJSDqStrstateJSSqStrstateJSRegexpstateJSBlockCmtstateJSLineCmtstateCSSstateCSSDqStrstateCSSSqStrstateCSSDqURLstateCSSSqURLstateCSSURLstateCSSBlockCmtstateCSSLineCmtstateError" ++func _() { ++ // An "invalid array index" compiler error signifies that the constant values have changed. ++ // Re-run the stringer command to generate them again. ++ var x [1]struct{} ++ _ = x[stateText-0] ++ _ = x[stateTag-1] ++ _ = x[stateAttrName-2] ++ _ = x[stateAfterName-3] ++ _ = x[stateBeforeValue-4] ++ _ = x[stateHTMLCmt-5] ++ _ = x[stateRCDATA-6] ++ _ = x[stateAttr-7] ++ _ = x[stateURL-8] ++ _ = x[stateSrcset-9] ++ _ = x[stateJS-10] ++ _ = x[stateJSDqStr-11] ++ _ = x[stateJSSqStr-12] ++ _ = x[stateJSBqStr-13] ++ _ = x[stateJSRegexp-14] ++ _ = x[stateJSBlockCmt-15] ++ _ = x[stateJSLineCmt-16] ++ _ = x[stateCSS-17] ++ _ = x[stateCSSDqStr-18] ++ _ = x[stateCSSSqStr-19] ++ _ = x[stateCSSDqURL-20] ++ _ = x[stateCSSSqURL-21] ++ _ = x[stateCSSURL-22] ++ _ = x[stateCSSBlockCmt-23] ++ _ = x[stateCSSLineCmt-24] ++ _ = x[stateError-25] ++ _ = x[stateDead-26] ++} ++ ++const _state_name = "stateTextstateTagstateAttrNamestateAfterNamestateBeforeValuestateHTMLCmtstateRCDATAstateAttrstateURLstateSrcsetstateJSstateJSDqStrstateJSSqStrstateJSBqStrstateJSRegexpstateJSBlockCmtstateJSLineCmtstateCSSstateCSSDqStrstateCSSSqStrstateCSSDqURLstateCSSSqURLstateCSSURLstateCSSBlockCmtstateCSSLineCmtstateErrorstateDead" + +-var _state_index = [...]uint16{0, 9, 17, 30, 44, 60, 72, 83, 92, 100, 111, 118, 130, 142, 155, 170, 184, 192, 205, 218, 231, 244, 255, 271, 286, 296} ++var _state_index = [...]uint16{0, 9, 17, 30, 44, 60, 72, 83, 92, 100, 111, 118, 130, 142, 154, 167, 182, 196, 204, 217, 230, 243, 256, 267, 283, 298, 308, 317} + + func (i state) String() string { + if i >= state(len(_state_index)-1) { +diff --git a/src/html/template/transition.go b/src/html/template/transition.go +index 06df679..92eb351 100644 +--- a/src/html/template/transition.go ++++ b/src/html/template/transition.go +@@ -27,6 +27,7 @@ var transitionFunc = [...]func(context, []byte) (context, int){ + stateJS: tJS, + stateJSDqStr: tJSDelimited, + stateJSSqStr: tJSDelimited, ++ stateJSBqStr: tJSDelimited, + stateJSRegexp: tJSDelimited, + stateJSBlockCmt: tBlockCmt, + stateJSLineCmt: tLineCmt, +@@ -262,7 +263,7 @@ func tURL(c context, s []byte) (context, int) { + + // tJS is the context transition function for the JS state. + func tJS(c context, s []byte) (context, int) { +- i := bytes.IndexAny(s, `"'/`) ++ i := bytes.IndexAny(s, "\"`'/") + if i == -1 { + // Entire input is non string, comment, regexp tokens. + c.jsCtx = nextJSCtx(s, c.jsCtx) +@@ -274,6 +275,8 @@ func tJS(c context, s []byte) (context, int) { + c.state, c.jsCtx = stateJSDqStr, jsCtxRegexp + case '\'': + c.state, c.jsCtx = stateJSSqStr, jsCtxRegexp ++ case '`': ++ c.state, c.jsCtx = stateJSBqStr, jsCtxRegexp + case '/': + switch { + case i+1 < len(s) && s[i+1] == '/': +@@ -303,6 +306,8 @@ func tJSDelimited(c context, s []byte) (context, int) { + switch c.state { + case stateJSSqStr: + specials = `\'` ++ case stateJSBqStr: ++ specials = "`\\" + case stateJSRegexp: + specials = `\/[]` + } +-- +2.7.4 diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-24539.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-24539.patch new file mode 100644 index 0000000000..281b6486a8 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-24539.patch @@ -0,0 +1,60 @@ +From 8673ca81e5340b87709db2d9749c92a3bf925df1 Mon Sep 17 00:00:00 2001 +From: Roland Shoemaker <bracewell@google.com> +Date: Thu, 13 Apr 2023 15:40:44 -0700 +Subject: [PATCH] html/template: disallow angle brackets in CSS values + +Angle brackets should not appear in CSS contexts, as they may affect +token boundaries (such as closing a <style> tag, resulting in +injection). Instead emit filterFailsafe, matching the behavior for other +dangerous characters. + +Thanks to Juho Nurminen of Mattermost for reporting this issue. + +Fixes #59720 +Fixes CVE-2023-24539 + +Change-Id: Iccc659c9a18415992b0c05c178792228e3a7bae4 +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1826636 +Reviewed-by: Julie Qiu <julieqiu@google.com> +Run-TryBot: Roland Shoemaker <bracewell@google.com> +Reviewed-by: Damien Neil <dneil@google.com> +Reviewed-on: https://go-review.googlesource.com/c/go/+/491615 +Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org> +Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> +Run-TryBot: Carlos Amedee <carlos@golang.org> +TryBot-Result: Gopher Robot <gobot@golang.org> + +Upstream-Status: Backport from [https://github.com/golang/go/commit/8673ca81e5340b87709db2d9749c92a3bf925df1] +CVE: CVE-2023-24539 +Signed-off-by: Ashish Sharma <asharma@mvista.com> +--- + src/html/template/css.go | 2 +- + src/html/template/css_test.go | 2 ++ + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/html/template/css.go b/src/html/template/css.go +index 890a0c6b227fe..f650d8b3e843a 100644 +--- a/src/html/template/css.go ++++ b/src/html/template/css.go +@@ -238,7 +238,7 @@ func cssValueFilter(args ...any) string { + // inside a string that might embed JavaScript source. + for i, c := range b { + switch c { +- case 0, '"', '\'', '(', ')', '/', ';', '@', '[', '\\', ']', '`', '{', '}': ++ case 0, '"', '\'', '(', ')', '/', ';', '@', '[', '\\', ']', '`', '{', '}', '<', '>': + return filterFailsafe + case '-': + // Disallow <!-- or -->. +diff --git a/src/html/template/css_test.go b/src/html/template/css_test.go +index a735638b0314f..2b76256a766e9 100644 +--- a/src/html/template/css_test.go ++++ b/src/html/template/css_test.go +@@ -231,6 +231,8 @@ func TestCSSValueFilter(t *testing.T) { + {`-exp\000052 ession(alert(1337))`, "ZgotmplZ"}, + {`-expre\0000073sion`, "-expre\x073sion"}, + {`@import url evil.css`, "ZgotmplZ"}, ++ {"<", "ZgotmplZ"}, ++ {">", "ZgotmplZ"}, + } + for _, test := range tests { + got := cssValueFilter(test.css) diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-24540.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-24540.patch new file mode 100644 index 0000000000..799a0dfcda --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-24540.patch @@ -0,0 +1,90 @@ +From ce7bd33345416e6d8cac901792060591cafc2797 Mon Sep 17 00:00:00 2001 +From: Roland Shoemaker <bracewell@google.com> +Date: Tue, 11 Apr 2023 16:27:43 +0100 +Subject: [PATCH] [release-branch.go1.19] html/template: handle all JS + whitespace characters + +Rather than just a small set. Character class as defined by \s [0]. + +Thanks to Juho Nurminen of Mattermost for reporting this. + +For #59721 +Fixes #59813 +Fixes CVE-2023-24540 + +[0] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes + +Change-Id: I56d4fa1ef08125b417106ee7dbfb5b0923b901ba +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1821459 +Reviewed-by: Julie Qiu <julieqiu@google.com> +Run-TryBot: Roland Shoemaker <bracewell@google.com> +Reviewed-by: Damien Neil <dneil@google.com> +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1851497 +Run-TryBot: Damien Neil <dneil@google.com> +Reviewed-by: Roland Shoemaker <bracewell@google.com> +Reviewed-on: https://go-review.googlesource.com/c/go/+/491355 +Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> +Reviewed-by: Carlos Amedee <carlos@golang.org> +TryBot-Bypass: Carlos Amedee <carlos@golang.org> +Run-TryBot: Carlos Amedee <carlos@golang.org> + +Upstream-Status: Backport [https://github.com/golang/go/commit/ce7bd33345416e6d8cac901792060591cafc2797] +CVE: CVE-2023-24540 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + src/html/template/js.go | 8 +++++++- + src/html/template/js_test.go | 11 +++++++---- + 2 files changed, 14 insertions(+), 5 deletions(-) + +diff --git a/src/html/template/js.go b/src/html/template/js.go +index fe7054efe5cd8..4e05c1455723f 100644 +--- a/src/html/template/js.go ++++ b/src/html/template/js.go +@@ -13,6 +13,11 @@ import ( + "unicode/utf8" + ) + ++// jsWhitespace contains all of the JS whitespace characters, as defined ++// by the \s character class. ++// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions/Character_classes. ++const jsWhitespace = "\f\n\r\t\v\u0020\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000\ufeff" ++ + // nextJSCtx returns the context that determines whether a slash after the + // given run of tokens starts a regular expression instead of a division + // operator: / or /=. +@@ -26,7 +31,8 @@ import ( + // JavaScript 2.0 lexical grammar and requires one token of lookbehind: + // https://www.mozilla.org/js/language/js20-2000-07/rationale/syntax.html + func nextJSCtx(s []byte, preceding jsCtx) jsCtx { +- s = bytes.TrimRight(s, "\t\n\f\r \u2028\u2029") ++ // Trim all JS whitespace characters ++ s = bytes.TrimRight(s, jsWhitespace) + if len(s) == 0 { + return preceding + } +diff --git a/src/html/template/js_test.go b/src/html/template/js_test.go +index e07c695f7a77d..e52180cc113b5 100644 +--- a/src/html/template/js_test.go ++++ b/src/html/template/js_test.go +@@ -81,14 +81,17 @@ func TestNextJsCtx(t *testing.T) { + {jsCtxDivOp, "0"}, + // Dots that are part of a number are div preceders. + {jsCtxDivOp, "0."}, ++ // Some JS interpreters treat NBSP as a normal space, so ++ // we must too in order to properly escape things. ++ {jsCtxRegexp, "=\u00A0"}, + } + + for _, test := range tests { +- if nextJSCtx([]byte(test.s), jsCtxRegexp) != test.jsCtx { +- t.Errorf("want %s got %q", test.jsCtx, test.s) ++ if ctx := nextJSCtx([]byte(test.s), jsCtxRegexp); ctx != test.jsCtx { ++ t.Errorf("%q: want %s got %s", test.s, test.jsCtx, ctx) + } +- if nextJSCtx([]byte(test.s), jsCtxDivOp) != test.jsCtx { +- t.Errorf("want %s got %q", test.jsCtx, test.s) ++ if ctx := nextJSCtx([]byte(test.s), jsCtxDivOp); ctx != test.jsCtx { ++ t.Errorf("%q: want %s got %s", test.s, test.jsCtx, ctx) + } + } + diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-29400.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-29400.patch new file mode 100644 index 0000000000..092c7aa0ff --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-29400.patch @@ -0,0 +1,94 @@ +From 0d347544cbca0f42b160424f6bc2458ebcc7b3fc Mon Sep 17 00:00:00 2001 +From: Roland Shoemaker <bracewell@google.com> +Date: Thu, 13 Apr 2023 14:01:50 -0700 +Subject: [PATCH] html/template: emit filterFailsafe for empty unquoted attr + value + +An unquoted action used as an attribute value can result in unsafe +behavior if it is empty, as HTML normalization will result in unexpected +attributes, and may allow attribute injection. If executing a template +results in a empty unquoted attribute value, emit filterFailsafe +instead. + +Thanks to Juho Nurminen of Mattermost for reporting this issue. + +Fixes #59722 +Fixes CVE-2023-29400 + +Change-Id: Ia38d1b536ae2b4af5323a6c6d861e3c057c2570a +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1826631 +Reviewed-by: Julie Qiu <julieqiu@google.com> +Run-TryBot: Roland Shoemaker <bracewell@google.com> +Reviewed-by: Damien Neil <dneil@google.com> +Reviewed-on: https://go-review.googlesource.com/c/go/+/491617 +Run-TryBot: Carlos Amedee <carlos@golang.org> +Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org> +Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> +TryBot-Result: Gopher Robot <gobot@golang.org> + +Upstream-Status: Backport from [https://github.com/golang/go/commit/0d347544cbca0f42b160424f6bc2458ebcc7b3fc] +CVE: CVE-2023-29400 +Signed-off-by: Ashish Sharma <asharma@mvista.com> +--- + src/html/template/escape.go | 5 ++--- + src/html/template/escape_test.go | 15 +++++++++++++++ + src/html/template/html.go | 3 +++ + 3 files changed, 20 insertions(+), 3 deletions(-) + +diff --git a/src/html/template/escape.go b/src/html/template/escape.go +index 4ba1d6b31897e..a62ef159f0dcd 100644 +--- a/src/html/template/escape.go ++++ b/src/html/template/escape.go +@@ -382,9 +382,8 @@ func normalizeEscFn(e string) string { + // for all x. + var redundantFuncs = map[string]map[string]bool{ + "_html_template_commentescaper": { +- "_html_template_attrescaper": true, +- "_html_template_nospaceescaper": true, +- "_html_template_htmlescaper": true, ++ "_html_template_attrescaper": true, ++ "_html_template_htmlescaper": true, + }, + "_html_template_cssescaper": { + "_html_template_attrescaper": true, +diff --git a/src/html/template/escape_test.go b/src/html/template/escape_test.go +index 3dd212bac9406..f8b2b448f2dfa 100644 +--- a/src/html/template/escape_test.go ++++ b/src/html/template/escape_test.go +@@ -678,6 +678,21 @@ func TestEscape(t *testing.T) { + `<img srcset={{",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"}}>`, + `<img srcset=,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,>`, + }, ++ { ++ "unquoted empty attribute value (plaintext)", ++ "<p name={{.U}}>", ++ "<p name=ZgotmplZ>", ++ }, ++ { ++ "unquoted empty attribute value (url)", ++ "<p href={{.U}}>", ++ "<p href=ZgotmplZ>", ++ }, ++ { ++ "quoted empty attribute value", ++ "<p name=\"{{.U}}\">", ++ "<p name=\"\">", ++ }, + } + + for _, test := range tests { +diff --git a/src/html/template/html.go b/src/html/template/html.go +index bcca0b51a0ef9..a181699a5bda8 100644 +--- a/src/html/template/html.go ++++ b/src/html/template/html.go +@@ -14,6 +14,9 @@ import ( + // htmlNospaceEscaper escapes for inclusion in unquoted attribute values. + func htmlNospaceEscaper(args ...interface{}) string { + s, t := stringify(args...) ++ if s == "" { ++ return filterFailsafe ++ } + if t == contentTypeHTML { + return htmlReplacer(stripTags(s), htmlNospaceNormReplacementTable, false) + } + diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-29402.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-29402.patch new file mode 100644 index 0000000000..01eed9fe1b --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-29402.patch @@ -0,0 +1,201 @@ +rom c160b49b6d328c86bd76ca2fff9009a71347333f Mon Sep 17 00:00:00 2001 +From: "Bryan C. Mills" <bcmills@google.com> +Date: Fri, 12 May 2023 14:15:16 -0400 +Subject: [PATCH] [release-branch.go1.19] cmd/go: disallow package directories + containing newlines + +Directory or file paths containing newlines may cause tools (such as +cmd/cgo) that emit "//line" or "#line" -directives to write part of +the path into non-comment lines in generated source code. If those +lines contain valid Go code, it may be injected into the resulting +binary. + +(Note that Go import paths and file paths within module zip files +already could not contain newlines.) + +Thanks to Juho Nurminen of Mattermost for reporting this issue. + +Updates #60167. +Fixes #60515. +Fixes CVE-2023-29402. + +Change-Id: If55d0400c02beb7a5da5eceac60f1abeac99f064 +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1882606 +Reviewed-by: Roland Shoemaker <bracewell@google.com> +Run-TryBot: Roland Shoemaker <bracewell@google.com> +Reviewed-by: Russ Cox <rsc@google.com> +Reviewed-by: Damien Neil <dneil@google.com> +(cherry picked from commit 41f9046495564fc728d6f98384ab7276450ac7e2) +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1902229 +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1904343 +Reviewed-by: Michael Knyszek <mknyszek@google.com> +Reviewed-by: Bryan Mills <bcmills@google.com> +Reviewed-on: https://go-review.googlesource.com/c/go/+/501218 +Run-TryBot: David Chase <drchase@google.com> +Auto-Submit: Michael Knyszek <mknyszek@google.com> +TryBot-Result: Gopher Robot <gobot@golang.org> + +Upstream-Status: Backport [https://github.com/golang/go/commit/c160b49b6d328c86bd76ca2fff9009a71347333f] +CVE: CVE-2023-29402 +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> +--- + src/cmd/go/internal/load/pkg.go | 4 + + src/cmd/go/internal/work/exec.go | 6 ++ + src/cmd/go/script_test.go | 1 + + .../go/testdata/script/build_cwd_newline.txt | 100 ++++++++++++++++++ + 4 files changed, 111 insertions(+) + create mode 100644 src/cmd/go/testdata/script/build_cwd_newline.txt + +diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go +index 369a79b..d2b63b0 100644 +--- a/src/cmd/go/internal/load/pkg.go ++++ b/src/cmd/go/internal/load/pkg.go +@@ -1697,6 +1697,10 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) { + setError(ImportErrorf(p.ImportPath, "invalid import path %q", p.ImportPath)) + return + } ++ if strings.ContainsAny(p.Dir, "\r\n") { ++ setError(fmt.Errorf("invalid package directory %q", p.Dir)) ++ return ++ } + + // Build list of imported packages and full dependency list. + imports := make([]*Package, 0, len(p.Imports)) +diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go +index 9a9650b..050b785 100644 +--- a/src/cmd/go/internal/work/exec.go ++++ b/src/cmd/go/internal/work/exec.go +@@ -458,6 +458,12 @@ func (b *Builder) build(a *Action) (err error) { + b.Print(a.Package.ImportPath + "\n") + } + ++ if p.Error != nil { ++ // Don't try to build anything for packages with errors. There may be a ++ // problem with the inputs that makes the package unsafe to build. ++ return p.Error ++ } ++ + if a.Package.BinaryOnly { + p.Stale = true + p.StaleReason = "binary-only packages are no longer supported" +diff --git a/src/cmd/go/script_test.go b/src/cmd/go/script_test.go +index ec498bb..a1398ad 100644 +--- a/src/cmd/go/script_test.go ++++ b/src/cmd/go/script_test.go +@@ -123,6 +123,7 @@ func (ts *testScript) setup() { + "devnull=" + os.DevNull, + "goversion=" + goVersion(ts), + ":=" + string(os.PathListSeparator), ++ "newline=\n", + } + + if runtime.GOOS == "plan9" { +diff --git a/src/cmd/go/testdata/script/build_cwd_newline.txt b/src/cmd/go/testdata/script/build_cwd_newline.txt +new file mode 100644 +index 0000000..61c6966 +--- /dev/null ++++ b/src/cmd/go/testdata/script/build_cwd_newline.txt +@@ -0,0 +1,100 @@ ++[windows] skip 'filesystem normalizes / to \' ++[plan9] skip 'filesystem disallows \n in paths' ++ ++# If the directory path containing a package to be built includes a newline, ++# the go command should refuse to even try to build the package. ++ ++env DIR=$WORK${/}${newline}'package main'${newline}'func main() { panic("uh-oh")'${newline}'/*' ++ ++mkdir $DIR ++cd $DIR ++exec pwd ++cp $WORK/go.mod ./go.mod ++cp $WORK/main.go ./main.go ++cp $WORK/main_test.go ./main_test.go ++ ++! go build -o $devnull . ++stderr 'package example: invalid package directory .*uh-oh' ++ ++! go build -o $devnull main.go ++stderr 'package command-line-arguments: invalid package directory .*uh-oh' ++ ++! go run . ++stderr 'package example: invalid package directory .*uh-oh' ++ ++! go run main.go ++stderr 'package command-line-arguments: invalid package directory .*uh-oh' ++ ++! go test . ++stderr 'package example: invalid package directory .*uh-oh' ++ ++! go test -v main.go main_test.go ++stderr 'package command-line-arguments: invalid package directory .*uh-oh' ++ ++ ++# Since we do preserve $PWD (or set it appropriately) for commands, and we do ++# not resolve symlinks unnecessarily, referring to the contents of the unsafe ++# directory via a safe symlink should be ok, and should not inject the data from ++# the symlink target path. ++ ++[!symlink] stop 'remainder of test checks symlink behavior' ++[short] stop 'links and runs binaries' ++ ++symlink $WORK${/}link -> $DIR ++ ++go run $WORK${/}link${/}main.go ++! stdout panic ++! stderr panic ++stderr '^ok$' ++ ++go test -v $WORK${/}link${/}main.go $WORK${/}link${/}main_test.go ++! stdout panic ++! stderr panic ++stdout '^ok$' # 'go test' combines the test's stdout into stderr ++ ++cd $WORK/link ++ ++! go run $DIR${/}main.go ++stderr 'package command-line-arguments: invalid package directory .*uh-oh' ++ ++go run . ++! stdout panic ++! stderr panic ++stderr '^ok$' ++ ++go run main.go ++! stdout panic ++! stderr panic ++stderr '^ok$' ++ ++go test -v ++! stdout panic ++! stderr panic ++stdout '^ok$' # 'go test' combines the test's stdout into stderr ++ ++go test -v . ++! stdout panic ++! stderr panic ++stdout '^ok$' # 'go test' combines the test's stdout into stderr ++ ++ ++-- $WORK/go.mod -- ++module example ++go 1.19 ++-- $WORK/main.go -- ++package main ++ ++import "C" ++ ++func main() { ++ /* nothing here */ ++ println("ok") ++} ++-- $WORK/main_test.go -- ++package main ++ ++import "testing" ++ ++func TestMain(*testing.M) { ++ main() ++} +-- +2.25.1 + diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-29404.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-29404.patch new file mode 100644 index 0000000000..61336ee9ee --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-29404.patch @@ -0,0 +1,84 @@ +From bf3c8ce03e175e870763901a3850bca01381a828 Mon Sep 17 00:00:00 2001 +From: Roland Shoemaker <bracewell@google.com> +Date: Fri, 5 May 2023 13:10:34 -0700 +Subject: [PATCH] [release-branch.go1.19] cmd/go: enforce flags with + non-optional arguments + +Enforce that linker flags which expect arguments get them, otherwise it +may be possible to smuggle unexpected flags through as the linker can +consume what looks like a flag as an argument to a preceding flag (i.e. +"-Wl,-O -Wl,-R,-bad-flag" is interpreted as "-O=-R -bad-flag"). Also be +somewhat more restrictive in the general format of some flags. + +Thanks to Juho Nurminen of Mattermost for reporting this issue. + +Updates #60305 +Fixes #60511 +Fixes CVE-2023-29404 + +Change-Id: Icdffef2c0f644da50261cace6f43742783931cff +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1876275 +Reviewed-by: Ian Lance Taylor <iant@google.com> +Reviewed-by: Damien Neil <dneil@google.com> +(cherry picked from commit 896779503cf754cbdac24b61d4cc953b50fe2dde) +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1902225 +Run-TryBot: Roland Shoemaker <bracewell@google.com> +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1904342 +Reviewed-by: Michael Knyszek <mknyszek@google.com> +Reviewed-on: https://go-review.googlesource.com/c/go/+/501217 +Auto-Submit: Michael Knyszek <mknyszek@google.com> +Run-TryBot: David Chase <drchase@google.com> +TryBot-Bypass: Michael Knyszek <mknyszek@google.com> + +Upstream-Status: Backport [https://github.com/golang/go/commit/bf3c8ce03e175e870763901a3850bca01381a828] +CVE: CVE-2023-29404 +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> +--- + src/cmd/go/internal/work/security.go | 6 +++--- + src/cmd/go/internal/work/security_test.go | 5 +++++ + 2 files changed, 8 insertions(+), 3 deletions(-) + +diff --git a/src/cmd/go/internal/work/security.go b/src/cmd/go/internal/work/security.go +index a823b20..8acb6dc 100644 +--- a/src/cmd/go/internal/work/security.go ++++ b/src/cmd/go/internal/work/security.go +@@ -177,17 +177,17 @@ var validLinkerFlags = []*lazyregexp.Regexp{ + re(`-Wl,-Bdynamic`), + re(`-Wl,-berok`), + re(`-Wl,-Bstatic`), +- re(`-WL,-O([^@,\-][^,]*)?`), ++ re(`-Wl,-O[0-9]+`), + re(`-Wl,-d[ny]`), + re(`-Wl,--disable-new-dtags`), +- re(`-Wl,-e[=,][a-zA-Z0-9]*`), ++ re(`-Wl,-e[=,][a-zA-Z0-9]+`), + re(`-Wl,--enable-new-dtags`), + re(`-Wl,--end-group`), + re(`-Wl,--(no-)?export-dynamic`), + re(`-Wl,-framework,[^,@\-][^,]+`), + re(`-Wl,-headerpad_max_install_names`), + re(`-Wl,--no-undefined`), +- re(`-Wl,-R([^@\-][^,@]*$)`), ++ re(`-Wl,-R,?([^@\-,][^,@]*$)`), + re(`-Wl,--just-symbols[=,]([^,@\-][^,@]+)`), + re(`-Wl,-rpath(-link)?[=,]([^,@\-][^,]+)`), + re(`-Wl,-s`), +diff --git a/src/cmd/go/internal/work/security_test.go b/src/cmd/go/internal/work/security_test.go +index bd707ff..7b0b7d3 100644 +--- a/src/cmd/go/internal/work/security_test.go ++++ b/src/cmd/go/internal/work/security_test.go +@@ -220,6 +220,11 @@ var badLinkerFlags = [][]string{ + {"-Wl,-R,@foo"}, + {"-Wl,--just-symbols,@foo"}, + {"../x.o"}, ++ {"-Wl,-R,"}, ++ {"-Wl,-O"}, ++ {"-Wl,-e="}, ++ {"-Wl,-e,"}, ++ {"-Wl,-R,-flag"}, + } + + func TestCheckLinkerFlags(t *testing.T) { +-- +2.25.1 + diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-29405-1.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-29405-1.patch new file mode 100644 index 0000000000..70d50cc08a --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-29405-1.patch @@ -0,0 +1,112 @@ +From fa60c381ed06c12f9c27a7b50ca44c5f84f7f0f4 Mon Sep 17 00:00:00 2001 +From: Ian Lance Taylor <iant@golang.org> +Date: Thu, 4 May 2023 14:06:39 -0700 +Subject: [PATCH] [release-branch.go1.20] cmd/go,cmd/cgo: in _cgo_flags use one + line per flag + +The flags that we recorded in _cgo_flags did not use any quoting, +so a flag containing embedded spaces was mishandled. +Change the _cgo_flags format to put each flag on a separate line. +That is a simple format that does not require any quoting. + +As far as I can tell only cmd/go uses _cgo_flags, and it is only +used for gccgo. If this patch doesn't cause any trouble, then +in the next release we can change to only using _cgo_flags for gccgo. + +Thanks to Juho Nurminen of Mattermost for reporting this issue. + +Updates #60306 +Fixes #60514 +Fixes CVE-2023-29405 + +Change-Id: I36b6e188a44c80d7b9573efa577c386770bd2ba3 +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1875094 +Reviewed-by: Damien Neil <dneil@google.com> +Reviewed-by: Roland Shoemaker <bracewell@google.com> +(cherry picked from commit bcdfcadd5612212089d958bc352a6f6c90742dcc) +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1902228 +Run-TryBot: Roland Shoemaker <bracewell@google.com> +TryBot-Result: Security TryBots <security-trybots@go-security-trybots.iam.gserviceaccount.com> +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1904345 +Reviewed-by: Michael Knyszek <mknyszek@google.com> +Reviewed-on: https://go-review.googlesource.com/c/go/+/501220 +TryBot-Result: Gopher Robot <gobot@golang.org> +Run-TryBot: David Chase <drchase@google.com> +Auto-Submit: Michael Knyszek <mknyszek@google.com> +--- +Upstream-Status: Backport [https://github.com/golang/go/commit/fa60c381ed06c12f9c27a7b50ca44c5f84f7f0f4] +CVE: CVE-2023-29405 +Signed-off-by: Ashish Sharma <asharma@mvista.com> + + src/cmd/cgo/out.go | 4 +++- + src/cmd/go/internal/work/gccgo.go | 14 ++++++------- + .../go/testdata/script/gccgo_link_ldflags.txt | 20 +++++++++++++++++++ + 3 files changed, 29 insertions(+), 9 deletions(-) + create mode 100644 src/cmd/go/testdata/script/gccgo_link_ldflags.txt + +diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go +index d26f9e76a374a..d0c6fe3d4c2c2 100644 +--- a/src/cmd/cgo/out.go ++++ b/src/cmd/cgo/out.go +@@ -47,7 +47,9 @@ func (p *Package) writeDefs() { + + fflg := creat(*objDir + "_cgo_flags") + for k, v := range p.CgoFlags { +- fmt.Fprintf(fflg, "_CGO_%s=%s\n", k, strings.Join(v, " ")) ++ for _, arg := range v { ++ fmt.Fprintf(fflg, "_CGO_%s=%s\n", arg) ++ } + if k == "LDFLAGS" && !*gccgo { + for _, arg := range v { + fmt.Fprintf(fgo2, "//go:cgo_ldflag %q\n", arg) +diff --git a/src/cmd/go/internal/work/gccgo.go b/src/cmd/go/internal/work/gccgo.go +index 08a4c2d8166c7..a048b7f4eecef 100644 +--- a/src/cmd/go/internal/work/gccgo.go ++++ b/src/cmd/go/internal/work/gccgo.go +@@ -280,14 +280,12 @@ func (tools gccgoToolchain) link(b *Builder, root *Action, out, importcfg string + const ldflagsPrefix = "_CGO_LDFLAGS=" + for _, line := range strings.Split(string(flags), "\n") { + if strings.HasPrefix(line, ldflagsPrefix) { +- newFlags := strings.Fields(line[len(ldflagsPrefix):]) +- for _, flag := range newFlags { +- // Every _cgo_flags file has -g and -O2 in _CGO_LDFLAGS +- // but they don't mean anything to the linker so filter +- // them out. +- if flag != "-g" && !strings.HasPrefix(flag, "-O") { +- cgoldflags = append(cgoldflags, flag) +- } ++ flag := line[len(ldflagsPrefix):] ++ // Every _cgo_flags file has -g and -O2 in _CGO_LDFLAGS ++ // but they don't mean anything to the linker so filter ++ // them out. ++ if flag != "-g" && !strings.HasPrefix(flag, "-O") { ++ cgoldflags = append(cgoldflags, flag) + } + } + } +diff --git a/src/cmd/go/testdata/script/gccgo_link_ldflags.txt b/src/cmd/go/testdata/script/gccgo_link_ldflags.txt +new file mode 100644 +index 0000000000000..4e91ae56505b6 +--- /dev/null ++++ b/src/cmd/go/testdata/script/gccgo_link_ldflags.txt +@@ -0,0 +1,20 @@ ++# Test that #cgo LDFLAGS are properly quoted. ++# The #cgo LDFLAGS below should pass a string with spaces to -L, ++# as though searching a directory with a space in its name. ++# It should not pass --nosuchoption to the external linker. ++ ++[!cgo] skip ++ ++go build ++ ++[!exec:gccgo] skip ++ ++go build -compiler gccgo ++ ++-- go.mod -- ++module m ++-- cgo.go -- ++package main ++// #cgo LDFLAGS: -L "./ -Wl,--nosuchoption" ++import "C" ++func main() {} diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-29405-2.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-29405-2.patch new file mode 100644 index 0000000000..369eca581e --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-29405-2.patch @@ -0,0 +1,38 @@ +From 1008486a9ff979dbd21c7466eeb6abf378f9c637 Mon Sep 17 00:00:00 2001 +From: Ian Lance Taylor <iant@golang.org> +Date: Tue, 6 Jun 2023 12:51:17 -0700 +Subject: [PATCH] [release-branch.go1.20] cmd/cgo: correct _cgo_flags output + +For #60306 +For #60514 + +Change-Id: I3f5d14aee7d7195030e8872e42b1d97aa11d3582 +Reviewed-on: https://go-review.googlesource.com/c/go/+/501298 +Run-TryBot: Ian Lance Taylor <iant@golang.org> +TryBot-Result: Gopher Robot <gobot@golang.org> +Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> +Reviewed-by: David Chase <drchase@google.com> +Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org> +--- + +Upstream-Status: Backport [https://github.com/golang/go/commit/1008486a9ff979dbd21c7466eeb6abf378f9c637] +CVE: CVE-2023-29405 +Signed-off-by: Ashish Sharma <asharma@mvista.com> + + + src/cmd/cgo/out.go | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go +index d0c6fe3d4c2c2..a48f52105628a 100644 +--- a/src/cmd/cgo/out.go ++++ b/src/cmd/cgo/out.go +@@ -48,7 +48,7 @@ func (p *Package) writeDefs() { + fflg := creat(*objDir + "_cgo_flags") + for k, v := range p.CgoFlags { + for _, arg := range v { +- fmt.Fprintf(fflg, "_CGO_%s=%s\n", arg) ++ fmt.Fprintf(fflg, "_CGO_%s=%s\n", k, arg) + } + if k == "LDFLAGS" && !*gccgo { + for _, arg := range v { diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-29406-1.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-29406-1.patch new file mode 100644 index 0000000000..080def4682 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-29406-1.patch @@ -0,0 +1,212 @@ +From 5fa6923b1ea891400153d04ddf1545e23b40041b Mon Sep 17 00:00:00 2001 +From: Damien Neil <dneil@google.com> +Date: Wed, 28 Jun 2023 13:20:08 -0700 +Subject: [PATCH] [release-branch.go1.19] net/http: validate Host header before + sending + +Verify that the Host header we send is valid. +Avoids surprising behavior such as a Host of "go.dev\r\nX-Evil:oops" +adding an X-Evil header to HTTP/1 requests. + +Add a test, skip the test for HTTP/2. HTTP/2 is not vulnerable to +header injection in the way HTTP/1 is, but x/net/http2 doesn't validate +the header and will go into a retry loop when the server rejects it. +CL 506995 adds the necessary validation to x/net/http2. + +Updates #60374 +Fixes #61075 +For CVE-2023-29406 + +Change-Id: I05cb6866a9bead043101954dfded199258c6dd04 +Reviewed-on: https://go-review.googlesource.com/c/go/+/506996 +Reviewed-by: Tatiana Bradley <tatianabradley@google.com> +TryBot-Result: Gopher Robot <gobot@golang.org> +Run-TryBot: Damien Neil <dneil@google.com> +(cherry picked from commit 499458f7ca04087958987a33c2703c3ef03e27e2) +Reviewed-on: https://go-review.googlesource.com/c/go/+/507358 +Run-TryBot: Tatiana Bradley <tatianabradley@google.com> +Reviewed-by: Roland Shoemaker <roland@golang.org> + +Upstream-Status: Backport [https://github.com/golang/go/commit/5fa6923b1ea891400153d04ddf1545e23b40041b] +CVE: CVE-2023-29406 +Signed-off-by: Vivek Kumbhar <vkumbhar@mvista.com> +--- + src/net/http/http_test.go | 29 --------------------- + src/net/http/request.go | 47 ++++++++-------------------------- + src/net/http/request_test.go | 11 ++------ + src/net/http/transport_test.go | 18 +++++++++++++ + 4 files changed, 31 insertions(+), 74 deletions(-) + +diff --git a/src/net/http/http_test.go b/src/net/http/http_test.go +index f4ea52d..ea38cb4 100644 +--- a/src/net/http/http_test.go ++++ b/src/net/http/http_test.go +@@ -49,35 +49,6 @@ func TestForeachHeaderElement(t *testing.T) { + } + } + +-func TestCleanHost(t *testing.T) { +- tests := []struct { +- in, want string +- }{ +- {"www.google.com", "www.google.com"}, +- {"www.google.com foo", "www.google.com"}, +- {"www.google.com/foo", "www.google.com"}, +- {" first character is a space", ""}, +- {"[1::6]:8080", "[1::6]:8080"}, +- +- // Punycode: +- {"гофер.рф/foo", "xn--c1ae0ajs.xn--p1ai"}, +- {"bücher.de", "xn--bcher-kva.de"}, +- {"bücher.de:8080", "xn--bcher-kva.de:8080"}, +- // Verify we convert to lowercase before punycode: +- {"BÜCHER.de", "xn--bcher-kva.de"}, +- {"BÜCHER.de:8080", "xn--bcher-kva.de:8080"}, +- // Verify we normalize to NFC before punycode: +- {"gophér.nfc", "xn--gophr-esa.nfc"}, // NFC input; no work needed +- {"goph\u0065\u0301r.nfd", "xn--gophr-esa.nfd"}, // NFD input +- } +- for _, tt := range tests { +- got := cleanHost(tt.in) +- if tt.want != got { +- t.Errorf("cleanHost(%q) = %q, want %q", tt.in, got, tt.want) +- } +- } +-} +- + // Test that cmd/go doesn't link in the HTTP server. + // + // This catches accidental dependencies between the HTTP transport and +diff --git a/src/net/http/request.go b/src/net/http/request.go +index cb2edd2..2706300 100644 +--- a/src/net/http/request.go ++++ b/src/net/http/request.go +@@ -18,7 +18,6 @@ import ( + "io/ioutil" + "mime" + "mime/multipart" +- "net" + "net/http/httptrace" + "net/textproto" + "net/url" +@@ -26,7 +25,8 @@ import ( + "strconv" + "strings" + "sync" +- ++ ++ "golang.org/x/net/http/httpguts" + "golang.org/x/net/idna" + ) + +@@ -557,12 +557,19 @@ func (r *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, waitF + // is not given, use the host from the request URL. + // + // Clean the host, in case it arrives with unexpected stuff in it. +- host := cleanHost(r.Host) ++ host := r.Host + if host == "" { + if r.URL == nil { + return errMissingHost + } +- host = cleanHost(r.URL.Host) ++ host = r.URL.Host ++ } ++ host, err = httpguts.PunycodeHostPort(host) ++ if err != nil { ++ return err ++ } ++ if !httpguts.ValidHostHeader(host) { ++ return errors.New("http: invalid Host header") + } + + // According to RFC 6874, an HTTP client, proxy, or other +@@ -717,38 +724,6 @@ func idnaASCII(v string) (string, error) { + return idna.Lookup.ToASCII(v) + } + +-// cleanHost cleans up the host sent in request's Host header. +-// +-// It both strips anything after '/' or ' ', and puts the value +-// into Punycode form, if necessary. +-// +-// Ideally we'd clean the Host header according to the spec: +-// https://tools.ietf.org/html/rfc7230#section-5.4 (Host = uri-host [ ":" port ]") +-// https://tools.ietf.org/html/rfc7230#section-2.7 (uri-host -> rfc3986's host) +-// https://tools.ietf.org/html/rfc3986#section-3.2.2 (definition of host) +-// But practically, what we are trying to avoid is the situation in +-// issue 11206, where a malformed Host header used in the proxy context +-// would create a bad request. So it is enough to just truncate at the +-// first offending character. +-func cleanHost(in string) string { +- if i := strings.IndexAny(in, " /"); i != -1 { +- in = in[:i] +- } +- host, port, err := net.SplitHostPort(in) +- if err != nil { // input was just a host +- a, err := idnaASCII(in) +- if err != nil { +- return in // garbage in, garbage out +- } +- return a +- } +- a, err := idnaASCII(host) +- if err != nil { +- return in // garbage in, garbage out +- } +- return net.JoinHostPort(a, port) +-} +- + // removeZone removes IPv6 zone identifier from host. + // E.g., "[fe80::1%en0]:8080" to "[fe80::1]:8080" + func removeZone(host string) string { +diff --git a/src/net/http/request_test.go b/src/net/http/request_test.go +index 461d66e..0d417ff 100644 +--- a/src/net/http/request_test.go ++++ b/src/net/http/request_test.go +@@ -676,15 +676,8 @@ func TestRequestBadHost(t *testing.T) { + } + req.Host = "foo.com with spaces" + req.URL.Host = "foo.com with spaces" +- req.Write(logWrites{t, &got}) +- want := []string{ +- "GET /after HTTP/1.1\r\n", +- "Host: foo.com\r\n", +- "User-Agent: " + DefaultUserAgent + "\r\n", +- "\r\n", +- } +- if !reflect.DeepEqual(got, want) { +- t.Errorf("Writes = %q\n Want = %q", got, want) ++ if err := req.Write(logWrites{t, &got}); err == nil { ++ t.Errorf("Writing request with invalid Host: succeded, want error") + } + } + +diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go +index fa0c370..0afb6b9 100644 +--- a/src/net/http/transport_test.go ++++ b/src/net/http/transport_test.go +@@ -6249,3 +6249,21 @@ func TestIssue32441(t *testing.T) { + t.Error(err) + } + } ++ ++func TestRequestSanitization(t *testing.T) { ++ setParallel(t) ++ defer afterTest(t) ++ ++ ts := newClientServerTest(t, h1Mode, HandlerFunc(func(rw ResponseWriter, req *Request) { ++ if h, ok := req.Header["X-Evil"]; ok { ++ t.Errorf("request has X-Evil header: %q", h) ++ } ++ })).ts ++ defer ts.Close() ++ req, _ := NewRequest("GET", ts.URL, nil) ++ req.Host = "go.dev\r\nX-Evil:evil" ++ resp, _ := ts.Client().Do(req) ++ if resp != nil { ++ resp.Body.Close() ++ } ++} +-- +2.25.1 diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-29406-2.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-29406-2.patch new file mode 100644 index 0000000000..637f46a537 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-29406-2.patch @@ -0,0 +1,114 @@ +From c08a5fa413a34111c9a37fd9e545de27ab0978b1 Mon Sep 17 00:00:00 2001 +From: Damien Neil <dneil@google.com> +Date: Wed, 19 Jul 2023 10:30:46 -0700 +Subject: [PATCH] [release-branch.go1.19] net/http: permit requests with + invalid Host headers + +Historically, the Transport has silently truncated invalid +Host headers at the first '/' or ' ' character. CL 506996 changed +this behavior to reject invalid Host headers entirely. +Unfortunately, Docker appears to rely on the previous behavior. + +When sending a HTTP/1 request with an invalid Host, send an empty +Host header. This is safer than truncation: If you care about the +Host, then you should get the one you set; if you don't care, +then an empty Host should be fine. + +Continue to fully validate Host headers sent to a proxy, +since proxies generally can't productively forward requests +without a Host. + +For #60374 +Fixes #61431 +Fixes #61825 + +Change-Id: If170c7dd860aa20eb58fe32990fc93af832742b6 +Reviewed-on: https://go-review.googlesource.com/c/go/+/511155 +TryBot-Result: Gopher Robot <gobot@golang.org> +Reviewed-by: Roland Shoemaker <roland@golang.org> +Run-TryBot: Damien Neil <dneil@google.com> +(cherry picked from commit b9153f6ef338baee5fe02a867c8fbc83a8b29dd1) +Reviewed-on: https://go-review.googlesource.com/c/go/+/518855 +Auto-Submit: Dmitri Shuralyov <dmitshur@google.com> +Run-TryBot: Roland Shoemaker <roland@golang.org> +Reviewed-by: Russ Cox <rsc@golang.org> + +Upstream-Status: Backport [https://github.com/golang/go/commit/c08a5fa413a34111c9a37fd9e545de27ab0978b1] +CVE: CVE-2023-29406 +Signed-off-by: Ming Liu <liu.ming50@gmail.com> +--- + src/net/http/request.go | 23 ++++++++++++++++++++++- + src/net/http/request_test.go | 17 ++++++++++++----- + 2 files changed, 34 insertions(+), 6 deletions(-) + +diff --git a/src/net/http/request.go b/src/net/http/request.go +index 3100037386..91cb8a66b9 100644 +--- a/src/net/http/request.go ++++ b/src/net/http/request.go +@@ -582,8 +582,29 @@ func (r *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, waitF + if err != nil { + return err + } ++ // Validate that the Host header is a valid header in general, ++ // but don't validate the host itself. This is sufficient to avoid ++ // header or request smuggling via the Host field. ++ // The server can (and will, if it's a net/http server) reject ++ // the request if it doesn't consider the host valid. + if !httpguts.ValidHostHeader(host) { +- return errors.New("http: invalid Host header") ++ // Historically, we would truncate the Host header after '/' or ' '. ++ // Some users have relied on this truncation to convert a network ++ // address such as Unix domain socket path into a valid, ignored ++ // Host header (see https://go.dev/issue/61431). ++ // ++ // We don't preserve the truncation, because sending an altered ++ // header field opens a smuggling vector. Instead, zero out the ++ // Host header entirely if it isn't valid. (An empty Host is valid; ++ // see RFC 9112 Section 3.2.) ++ // ++ // Return an error if we're sending to a proxy, since the proxy ++ // probably can't do anything useful with an empty Host header. ++ if !usingProxy { ++ host = "" ++ } else { ++ return errors.New("http: invalid Host header") ++ } + } + + // According to RFC 6874, an HTTP client, proxy, or other +diff --git a/src/net/http/request_test.go b/src/net/http/request_test.go +index fddc85d6a9..dd1e2dc2a1 100644 +--- a/src/net/http/request_test.go ++++ b/src/net/http/request_test.go +@@ -770,16 +770,23 @@ func TestRequestWriteBufferedWriter(t *testing.T) { + } + } + +-func TestRequestBadHost(t *testing.T) { ++func TestRequestBadHostHeader(t *testing.T) { + got := []string{} + req, err := NewRequest("GET", "http://foo/after", nil) + if err != nil { + t.Fatal(err) + } +- req.Host = "foo.com with spaces" +- req.URL.Host = "foo.com with spaces" +- if err := req.Write(logWrites{t, &got}); err == nil { +- t.Errorf("Writing request with invalid Host: succeded, want error") ++ req.Host = "foo.com\nnewline" ++ req.URL.Host = "foo.com\nnewline" ++ req.Write(logWrites{t, &got}) ++ want := []string{ ++ "GET /after HTTP/1.1\r\n", ++ "Host: \r\n", ++ "User-Agent: " + DefaultUserAgent + "\r\n", ++ "\r\n", ++ } ++ if !reflect.DeepEqual(got, want) { ++ t.Errorf("Writes = %q\n Want = %q", got, want) + } + } + +-- +2.34.1 + diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-29409.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-29409.patch new file mode 100644 index 0000000000..00685cc180 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-29409.patch @@ -0,0 +1,175 @@ +From 2300f7ef07718f6be4d8aa8486c7de99836e233f Mon Sep 17 00:00:00 2001 +From: Roland Shoemaker <bracewell@google.com> +Date: Wed, 7 Jun 2023 15:27:13 -0700 +Subject: [PATCH] [release-branch.go1.19] crypto/tls: restrict RSA keys in + certificates to <= 8192 bits + +Extremely large RSA keys in certificate chains can cause a client/server +to expend significant CPU time verifying signatures. Limit this by +restricting the size of RSA keys transmitted during handshakes to <= +8192 bits. + +Based on a survey of publicly trusted RSA keys, there are currently only +three certificates in circulation with keys larger than this, and all +three appear to be test certificates that are not actively deployed. It +is possible there are larger keys in use in private PKIs, but we target +the web PKI, so causing breakage here in the interests of increasing the +default safety of users of crypto/tls seems reasonable. + +Thanks to Mateusz Poliwczak for reporting this issue. + +Updates #61460 +Fixes #61579 +Fixes CVE-2023-29409 + +Change-Id: Ie35038515a649199a36a12fc2c5df3af855dca6c +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1912161 +Reviewed-by: Damien Neil <dneil@google.com> +Reviewed-by: Tatiana Bradley <tatianabradley@google.com> +Run-TryBot: Roland Shoemaker <bracewell@google.com> +(cherry picked from commit d865c715d92887361e4bd5596e19e513f27781b7) +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1965487 +Reviewed-on: https://go-review.googlesource.com/c/go/+/514915 +Run-TryBot: David Chase <drchase@google.com> +Reviewed-by: Matthew Dempsky <mdempsky@google.com> +TryBot-Bypass: David Chase <drchase@google.com> + +Upstream-Status: Backport [https://github.com/golang/go/commit/2300f7ef07718f6be4d8aa8486c7de99836e233f] +CVE: CVE-2023-29409 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + src/crypto/tls/handshake_client.go | 8 +++ + src/crypto/tls/handshake_client_test.go | 78 +++++++++++++++++++++++++ + src/crypto/tls/handshake_server.go | 4 ++ + 3 files changed, 90 insertions(+) + +diff --git a/src/crypto/tls/handshake_client.go b/src/crypto/tls/handshake_client.go +index 4fb528c..ba33ea1 100644 +--- a/src/crypto/tls/handshake_client.go ++++ b/src/crypto/tls/handshake_client.go +@@ -788,6 +788,10 @@ func (hs *clientHandshakeState) sendFinished(out []byte) error { + return nil + } + ++// maxRSAKeySize is the maximum RSA key size in bits that we are willing ++// to verify the signatures of during a TLS handshake. ++const maxRSAKeySize = 8192 ++ + // verifyServerCertificate parses and verifies the provided chain, setting + // c.verifiedChains and c.peerCertificates or sending the appropriate alert. + func (c *Conn) verifyServerCertificate(certificates [][]byte) error { +@@ -798,6 +802,10 @@ func (c *Conn) verifyServerCertificate(certificates [][]byte) error { + c.sendAlert(alertBadCertificate) + return errors.New("tls: failed to parse certificate from server: " + err.Error()) + } ++ if cert.PublicKeyAlgorithm == x509.RSA && cert.PublicKey.(*rsa.PublicKey).N.BitLen() > maxRSAKeySize { ++ c.sendAlert(alertBadCertificate) ++ return fmt.Errorf("tls: server sent certificate containing RSA key larger than %d bits", maxRSAKeySize) ++ } + certs[i] = cert + } + +diff --git a/src/crypto/tls/handshake_client_test.go b/src/crypto/tls/handshake_client_test.go +index 6bd3c37..8d20b2b 100644 +--- a/src/crypto/tls/handshake_client_test.go ++++ b/src/crypto/tls/handshake_client_test.go +@@ -1984,3 +1984,81 @@ func TestCloseClientConnectionOnIdleServer(t *testing.T) { + t.Errorf("Error expected, but no error returned") + } + } ++ ++// discardConn wraps a net.Conn but discards all writes, but reports that they happened. ++type discardConn struct { ++ net.Conn ++} ++ ++func (dc *discardConn) Write(data []byte) (int, error) { ++ return len(data), nil ++} ++ ++// largeRSAKeyCertPEM contains a 8193 bit RSA key ++const largeRSAKeyCertPEM = `-----BEGIN CERTIFICATE----- ++MIIInjCCBIWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDEwd0ZXN0 ++aW5nMB4XDTIzMDYwNzIxMjMzNloXDTIzMDYwNzIzMjMzNlowEjEQMA4GA1UEAxMH ++dGVzdGluZzCCBCIwDQYJKoZIhvcNAQEBBQADggQPADCCBAoCggQBAWdHsf6Rh2Ca ++n2SQwn4t4OQrOjbLLdGE1pM6TBKKrHUFy62uEL8atNjlcfXIsa4aEu3xNGiqxqur ++ZectlkZbm0FkaaQ1Wr9oikDY3KfjuaXdPdO/XC/h8AKNxlDOylyXwUSK/CuYb+1j ++gy8yF5QFvVfwW/xwTlHmhUeSkVSQPosfQ6yXNNsmMzkd+ZPWLrfq4R+wiNtwYGu0 ++WSBcI/M9o8/vrNLnIppoiBJJ13j9CR1ToEAzOFh9wwRWLY10oZhoh1ONN1KQURx4 ++qedzvvP2DSjZbUccdvl2rBGvZpzfOiFdm1FCnxB0c72Cqx+GTHXBFf8bsa7KHky9 ++sNO1GUanbq17WoDNgwbY6H51bfShqv0CErxatwWox3we4EcAmFHPVTCYL1oWVMGo ++a3Eth91NZj+b/nGhF9lhHKGzXSv9brmLLkfvM1jA6XhNhA7BQ5Vz67lj2j3XfXdh ++t/BU5pBXbL4Ut4mIhT1YnKXAjX2/LF5RHQTE8Vwkx5JAEKZyUEGOReD/B+7GOrLp ++HduMT9vZAc5aR2k9I8qq1zBAzsL69lyQNAPaDYd1BIAjUety9gAYaSQffCgAgpRO ++Gt+DYvxS+7AT/yEd5h74MU2AH7KrAkbXOtlwupiGwhMVTstncDJWXMJqbBhyHPF8 ++3UmZH0hbL4PYmzSj9LDWQQXI2tv6vrCpfts3Cqhqxz9vRpgY7t1Wu6l/r+KxYYz3 ++1pcGpPvRmPh0DJm7cPTiXqPnZcPt+ulSaSdlxmd19OnvG5awp0fXhxryZVwuiT8G ++VDkhyARrxYrdjlINsZJZbQjO0t8ketXAELJOnbFXXzeCOosyOHkLwsqOO96AVJA8 ++45ZVL5m95ClGy0RSrjVIkXsxTAMVG6SPAqKwk6vmTdRGuSPS4rhgckPVDHmccmuq ++dfnT2YkX+wB2/M3oCgU+s30fAHGkbGZ0pCdNbFYFZLiH0iiMbTDl/0L/z7IdK0nH ++GLHVE7apPraKC6xl6rPWsD2iSfrmtIPQa0+rqbIVvKP5JdfJ8J4alI+OxFw/znQe ++V0/Rez0j22Fe119LZFFSXhRv+ZSvcq20xDwh00mzcumPWpYuCVPozA18yIhC9tNn ++ALHndz0tDseIdy9vC71jQWy9iwri3ueN0DekMMF8JGzI1Z6BAFzgyAx3DkHtwHg7 ++B7qD0jPG5hJ5+yt323fYgJsuEAYoZ8/jzZ01pkX8bt+UsVN0DGnSGsI2ktnIIk3J ++l+8krjmUy6EaW79nITwoOqaeHOIp8m3UkjEcoKOYrzHRKqRy+A09rY+m/cAQaafW ++4xp0Zv7qZPLwnu0jsqB4jD8Ll9yPB02ndsoV6U5PeHzTkVhPml19jKUAwFfs7TJg ++kXy+/xFhYVUCAwEAATANBgkqhkiG9w0BAQsFAAOCBAIAAQnZY77pMNeypfpba2WK ++aDasT7dk2JqP0eukJCVPTN24Zca+xJNPdzuBATm/8SdZK9lddIbjSnWRsKvTnO2r ++/rYdlPf3jM5uuJtb8+Uwwe1s+gszelGS9G/lzzq+ehWicRIq2PFcs8o3iQMfENiv ++qILJ+xjcrvms5ZPDNahWkfRx3KCg8Q+/at2n5p7XYjMPYiLKHnDC+RE2b1qT20IZ ++FhuK/fTWLmKbfYFNNga6GC4qcaZJ7x0pbm4SDTYp0tkhzcHzwKhidfNB5J2vNz6l ++Ur6wiYwamFTLqcOwWo7rdvI+sSn05WQBv0QZlzFX+OAu0l7WQ7yU+noOxBhjvHds ++14+r9qcQZg2q9kG+evopYZqYXRUNNlZKo9MRBXhfrISulFAc5lRFQIXMXnglvAu+ ++Ipz2gomEAOcOPNNVldhKAU94GAMJd/KfN0ZP7gX3YvPzuYU6XDhag5RTohXLm18w ++5AF+ES3DOQ6ixu3DTf0D+6qrDuK+prdX8ivcdTQVNOQ+MIZeGSc6NWWOTaMGJ3lg ++aZIxJUGdo6E7GBGiC1YTjgFKFbHzek1LRTh/LX3vbSudxwaG0HQxwsU9T4DWiMqa ++Fkf2KteLEUA6HrR+0XlAZrhwoqAmrJ+8lCFX3V0gE9lpENfVHlFXDGyx10DpTB28 ++DdjnY3F7EPWNzwf9P3oNT69CKW3Bk6VVr3ROOJtDxVu1ioWo3TaXltQ0VOnap2Pu ++sa5wfrpfwBDuAS9JCDg4ttNp2nW3F7tgXC6xPqw5pvGwUppEw9XNrqV8TZrxduuv ++rQ3NyZ7KSzIpmFlD3UwV/fGfz3UQmHS6Ng1evrUID9DjfYNfRqSGIGjDfxGtYD+j ++Z1gLJZuhjJpNtwBkKRtlNtrCWCJK2hidK/foxwD7kwAPo2I9FjpltxCRywZUs07X ++KwXTfBR9v6ij1LV6K58hFS+8ezZyZ05CeVBFkMQdclTOSfuPxlMkQOtjp8QWDj+F ++j/MYziT5KBkHvcbrjdRtUJIAi4N7zCsPZtjik918AK1WBNRVqPbrgq/XSEXMfuvs ++6JbfK0B76vdBDRtJFC1JsvnIrGbUztxXzyQwFLaR/AjVJqpVlysLWzPKWVX6/+SJ ++u1NQOl2E8P6ycyBsuGnO89p0S4F8cMRcI2X1XQsZ7/q0NBrOMaEp5T3SrWo9GiQ3 ++o2SBdbs3Y6MBPBtTu977Z/0RO63J3M5i2tjUiDfrFy7+VRLKr7qQ7JibohyB8QaR ++9tedgjn2f+of7PnP/PEl1cCphUZeHM7QKUMPT8dbqwmKtlYY43EHXcvNOT5IBk3X ++9lwJoZk/B2i+ZMRNSP34ztAwtxmasPt6RAWGQpWCn9qmttAHAnMfDqe7F7jVR6rS ++u58= ++-----END CERTIFICATE-----` ++ ++func TestHandshakeRSATooBig(t *testing.T) { ++ testCert, _ := pem.Decode([]byte(largeRSAKeyCertPEM)) ++ ++ c := &Conn{conn: &discardConn{}, config: testConfig.Clone()} ++ ++ expectedErr := "tls: server sent certificate containing RSA key larger than 8192 bits" ++ err := c.verifyServerCertificate([][]byte{testCert.Bytes}) ++ if err == nil || err.Error() != expectedErr { ++ t.Errorf("Conn.verifyServerCertificate unexpected error: want %q, got %q", expectedErr, err) ++ } ++ ++ expectedErr = "tls: client sent certificate containing RSA key larger than 8192 bits" ++ err = c.processCertsFromClient(Certificate{Certificate: [][]byte{testCert.Bytes}}) ++ if err == nil || err.Error() != expectedErr { ++ t.Errorf("Conn.processCertsFromClient unexpected error: want %q, got %q", expectedErr, err) ++ } ++} +diff --git a/src/crypto/tls/handshake_server.go b/src/crypto/tls/handshake_server.go +index b16415a..2e36840 100644 +--- a/src/crypto/tls/handshake_server.go ++++ b/src/crypto/tls/handshake_server.go +@@ -738,6 +738,10 @@ func (c *Conn) processCertsFromClient(certificate Certificate) error { + c.sendAlert(alertBadCertificate) + return errors.New("tls: failed to parse client certificate: " + err.Error()) + } ++ if certs[i].PublicKeyAlgorithm == x509.RSA && certs[i].PublicKey.(*rsa.PublicKey).N.BitLen() > maxRSAKeySize { ++ c.sendAlert(alertBadCertificate) ++ return fmt.Errorf("tls: client sent certificate containing RSA key larger than %d bits", maxRSAKeySize) ++ } + } + + if len(certs) == 0 && requiresClientCert(c.config.ClientAuth) { +-- +2.25.1 + diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-39318.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-39318.patch new file mode 100644 index 0000000000..00def8fcda --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-39318.patch @@ -0,0 +1,262 @@ +From 023b542edf38e2a1f87fcefb9f75ff2f99401b4c Mon Sep 17 00:00:00 2001 +From: Roland Shoemaker <bracewell@google.com> +Date: Thu, 3 Aug 2023 12:24:13 -0700 +Subject: [PATCH] [release-branch.go1.20] html/template: support HTML-like + comments in script contexts + +Per Appendix B.1.1 of the ECMAScript specification, support HTML-like +comments in script contexts. Also per section 12.5, support hashbang +comments. This brings our parsing in-line with how browsers treat these +comment types. + +Thanks to Takeshi Kaneko (GMO Cybersecurity by Ierae, Inc.) for +reporting this issue. + +Fixes #62196 +Fixes #62395 +Fixes CVE-2023-39318 + +Change-Id: Id512702c5de3ae46cf648e268cb10e1eb392a181 +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1976593 +Run-TryBot: Roland Shoemaker <bracewell@google.com> +Reviewed-by: Tatiana Bradley <tatianabradley@google.com> +Reviewed-by: Damien Neil <dneil@google.com> +Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2014620 +Reviewed-on: https://go-review.googlesource.com/c/go/+/526098 +Run-TryBot: Cherry Mui <cherryyz@google.com> +TryBot-Result: Gopher Robot <gobot@golang.org> + +Upstream-Status: Backport from [https://github.com/golang/go/commit/023b542edf38e2a1f87fcefb9f75ff2f99401b4c] +CVE: CVE-2023-39318 +Signed-off-by: Siddharth Doshi <sdoshi@mvista.com> +--- + src/html/template/context.go | 6 ++- + src/html/template/escape.go | 5 +- + src/html/template/escape_test.go | 10 ++++ + src/html/template/state_string.go | 26 +++++----- + src/html/template/transition.go | 80 ++++++++++++++++++++----------- + 5 files changed, 84 insertions(+), 43 deletions(-) + +diff --git a/src/html/template/context.go b/src/html/template/context.go +index 0b65313..4eb7891 100644 +--- a/src/html/template/context.go ++++ b/src/html/template/context.go +@@ -124,6 +124,10 @@ const ( + stateJSBlockCmt + // stateJSLineCmt occurs inside a JavaScript // line comment. + stateJSLineCmt ++ // stateJSHTMLOpenCmt occurs inside a JavaScript <!-- HTML-like comment. ++ stateJSHTMLOpenCmt ++ // stateJSHTMLCloseCmt occurs inside a JavaScript --> HTML-like comment. ++ stateJSHTMLCloseCmt + // stateCSS occurs inside a <style> element or style attribute. + stateCSS + // stateCSSDqStr occurs inside a CSS double quoted string. +@@ -149,7 +153,7 @@ const ( + // authors & maintainers, not for end-users or machines. + func isComment(s state) bool { + switch s { +- case stateHTMLCmt, stateJSBlockCmt, stateJSLineCmt, stateCSSBlockCmt, stateCSSLineCmt: ++ case stateHTMLCmt, stateJSBlockCmt, stateJSLineCmt, stateJSHTMLOpenCmt, stateJSHTMLCloseCmt, stateCSSBlockCmt, stateCSSLineCmt: + return true + } + return false +diff --git a/src/html/template/escape.go b/src/html/template/escape.go +index 435f912..ad2ec69 100644 +--- a/src/html/template/escape.go ++++ b/src/html/template/escape.go +@@ -698,9 +698,12 @@ func (e *escaper) escapeText(c context, n *parse.TextNode) context { + if c.state != c1.state && isComment(c1.state) && c1.delim == delimNone { + // Preserve the portion between written and the comment start. + cs := i1 - 2 +- if c1.state == stateHTMLCmt { ++ if c1.state == stateHTMLCmt || c1.state == stateJSHTMLOpenCmt { + // "<!--" instead of "/*" or "//" + cs -= 2 ++ } else if c1.state == stateJSHTMLCloseCmt { ++ // "-->" instead of "/*" or "//" ++ cs -= 1 + } + b.Write(s[written:cs]) + written = i1 +diff --git a/src/html/template/escape_test.go b/src/html/template/escape_test.go +index f550691..5f41e52 100644 +--- a/src/html/template/escape_test.go ++++ b/src/html/template/escape_test.go +@@ -503,6 +503,16 @@ func TestEscape(t *testing.T) { + "<script>var a/*b*///c\nd</script>", + "<script>var a \nd</script>", + }, ++ { ++ "JS HTML-like comments", ++ "<script>before <!-- beep\nbetween\nbefore-->boop\n</script>", ++ "<script>before \nbetween\nbefore\n</script>", ++ }, ++ { ++ "JS hashbang comment", ++ "<script>#! beep\n</script>", ++ "<script>\n</script>", ++ }, + { + "CSS comments", + "<style>p// paragraph\n" + +diff --git a/src/html/template/state_string.go b/src/html/template/state_string.go +index 05104be..b5cfe70 100644 +--- a/src/html/template/state_string.go ++++ b/src/html/template/state_string.go +@@ -25,21 +25,23 @@ func _() { + _ = x[stateJSRegexp-14] + _ = x[stateJSBlockCmt-15] + _ = x[stateJSLineCmt-16] +- _ = x[stateCSS-17] +- _ = x[stateCSSDqStr-18] +- _ = x[stateCSSSqStr-19] +- _ = x[stateCSSDqURL-20] +- _ = x[stateCSSSqURL-21] +- _ = x[stateCSSURL-22] +- _ = x[stateCSSBlockCmt-23] +- _ = x[stateCSSLineCmt-24] +- _ = x[stateError-25] +- _ = x[stateDead-26] ++ _ = x[stateJSHTMLOpenCmt-17] ++ _ = x[stateJSHTMLCloseCmt-18] ++ _ = x[stateCSS-19] ++ _ = x[stateCSSDqStr-20] ++ _ = x[stateCSSSqStr-21] ++ _ = x[stateCSSDqURL-22] ++ _ = x[stateCSSSqURL-23] ++ _ = x[stateCSSURL-24] ++ _ = x[stateCSSBlockCmt-25] ++ _ = x[stateCSSLineCmt-26] ++ _ = x[stateError-27] ++ _ = x[stateDead-28] + } + +-const _state_name = "stateTextstateTagstateAttrNamestateAfterNamestateBeforeValuestateHTMLCmtstateRCDATAstateAttrstateURLstateSrcsetstateJSstateJSDqStrstateJSSqStrstateJSBqStrstateJSRegexpstateJSBlockCmtstateJSLineCmtstateCSSstateCSSDqStrstateCSSSqStrstateCSSDqURLstateCSSSqURLstateCSSURLstateCSSBlockCmtstateCSSLineCmtstateErrorstateDead" ++const _state_name = "stateTextstateTagstateAttrNamestateAfterNamestateBeforeValuestateHTMLCmtstateRCDATAstateAttrstateURLstateSrcsetstateJSstateJSDqStrstateJSSqStrstateJSBqStrstateJSRegexpstateJSBlockCmtstateJSLineCmtstateJSHTMLOpenCmtstateJSHTMLCloseCmtstateCSSstateCSSDqStrstateCSSSqStrstateCSSDqURLstateCSSSqURLstateCSSURLstateCSSBlockCmtstateCSSLineCmtstateErrorstateDead" + +-var _state_index = [...]uint16{0, 9, 17, 30, 44, 60, 72, 83, 92, 100, 111, 118, 130, 142, 154, 167, 182, 196, 204, 217, 230, 243, 256, 267, 283, 298, 308, 317} ++var _state_index = [...]uint16{0, 9, 17, 30, 44, 60, 72, 83, 92, 100, 111, 118, 130, 142, 154, 167, 182, 196, 214, 233, 241, 254, 267, 280, 293, 304, 320, 335, 345, 354} + + func (i state) String() string { + if i >= state(len(_state_index)-1) { +diff --git a/src/html/template/transition.go b/src/html/template/transition.go +index 92eb351..12aa4c4 100644 +--- a/src/html/template/transition.go ++++ b/src/html/template/transition.go +@@ -14,32 +14,34 @@ import ( + // the updated context and the number of bytes consumed from the front of the + // input. + var transitionFunc = [...]func(context, []byte) (context, int){ +- stateText: tText, +- stateTag: tTag, +- stateAttrName: tAttrName, +- stateAfterName: tAfterName, +- stateBeforeValue: tBeforeValue, +- stateHTMLCmt: tHTMLCmt, +- stateRCDATA: tSpecialTagEnd, +- stateAttr: tAttr, +- stateURL: tURL, +- stateSrcset: tURL, +- stateJS: tJS, +- stateJSDqStr: tJSDelimited, +- stateJSSqStr: tJSDelimited, +- stateJSBqStr: tJSDelimited, +- stateJSRegexp: tJSDelimited, +- stateJSBlockCmt: tBlockCmt, +- stateJSLineCmt: tLineCmt, +- stateCSS: tCSS, +- stateCSSDqStr: tCSSStr, +- stateCSSSqStr: tCSSStr, +- stateCSSDqURL: tCSSStr, +- stateCSSSqURL: tCSSStr, +- stateCSSURL: tCSSStr, +- stateCSSBlockCmt: tBlockCmt, +- stateCSSLineCmt: tLineCmt, +- stateError: tError, ++ stateText: tText, ++ stateTag: tTag, ++ stateAttrName: tAttrName, ++ stateAfterName: tAfterName, ++ stateBeforeValue: tBeforeValue, ++ stateHTMLCmt: tHTMLCmt, ++ stateRCDATA: tSpecialTagEnd, ++ stateAttr: tAttr, ++ stateURL: tURL, ++ stateSrcset: tURL, ++ stateJS: tJS, ++ stateJSDqStr: tJSDelimited, ++ stateJSSqStr: tJSDelimited, ++ stateJSBqStr: tJSDelimited, ++ stateJSRegexp: tJSDelimited, ++ stateJSBlockCmt: tBlockCmt, ++ stateJSLineCmt: tLineCmt, ++ stateJSHTMLOpenCmt: tLineCmt, ++ stateJSHTMLCloseCmt: tLineCmt, ++ stateCSS: tCSS, ++ stateCSSDqStr: tCSSStr, ++ stateCSSSqStr: tCSSStr, ++ stateCSSDqURL: tCSSStr, ++ stateCSSSqURL: tCSSStr, ++ stateCSSURL: tCSSStr, ++ stateCSSBlockCmt: tBlockCmt, ++ stateCSSLineCmt: tLineCmt, ++ stateError: tError, + } + + var commentStart = []byte("<!--") +@@ -263,7 +265,7 @@ func tURL(c context, s []byte) (context, int) { + + // tJS is the context transition function for the JS state. + func tJS(c context, s []byte) (context, int) { +- i := bytes.IndexAny(s, "\"`'/") ++ i := bytes.IndexAny(s, "\"`'/<-#") + if i == -1 { + // Entire input is non string, comment, regexp tokens. + c.jsCtx = nextJSCtx(s, c.jsCtx) +@@ -293,6 +295,26 @@ func tJS(c context, s []byte) (context, int) { + err: errorf(ErrSlashAmbig, nil, 0, "'/' could start a division or regexp: %.32q", s[i:]), + }, len(s) + } ++ // ECMAScript supports HTML style comments for legacy reasons, see Appendix ++ // B.1.1 "HTML-like Comments". The handling of these comments is somewhat ++ // confusing. Multi-line comments are not supported, i.e. anything on lines ++ // between the opening and closing tokens is not considered a comment, but ++ // anything following the opening or closing token, on the same line, is ++ // ignored. As such we simply treat any line prefixed with "<!--" or "-->" ++ // as if it were actually prefixed with "//" and move on. ++ case '<': ++ if i+3 < len(s) && bytes.Equal(commentStart, s[i:i+4]) { ++ c.state, i = stateJSHTMLOpenCmt, i+3 ++ } ++ case '-': ++ if i+2 < len(s) && bytes.Equal(commentEnd, s[i:i+3]) { ++ c.state, i = stateJSHTMLCloseCmt, i+2 ++ } ++ // ECMAScript also supports "hashbang" comment lines, see Section 12.5. ++ case '#': ++ if i+1 < len(s) && s[i+1] == '!' { ++ c.state, i = stateJSLineCmt, i+1 ++ } + default: + panic("unreachable") + } +@@ -372,12 +394,12 @@ func tBlockCmt(c context, s []byte) (context, int) { + return c, i + 2 + } + +-// tLineCmt is the context transition function for //comment states. ++// tLineCmt is the context transition function for //comment states, and the JS HTML-like comment state. + func tLineCmt(c context, s []byte) (context, int) { + var lineTerminators string + var endState state + switch c.state { +- case stateJSLineCmt: ++ case stateJSLineCmt, stateJSHTMLOpenCmt, stateJSHTMLCloseCmt: + lineTerminators, endState = "\n\r\u2028\u2029", stateJS + case stateCSSLineCmt: + lineTerminators, endState = "\n\f\r", stateCSS +-- +2.24.4 + diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-39319.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-39319.patch new file mode 100644 index 0000000000..69106e3e05 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-39319.patch @@ -0,0 +1,230 @@ +From 2070531d2f53df88e312edace6c8dfc9686ab2f5 Mon Sep 17 00:00:00 2001 +From: Roland Shoemaker <bracewell@google.com> +Date: Thu, 3 Aug 2023 12:28:28 -0700 +Subject: [PATCH] [release-branch.go1.20] html/template: properly handle + special tags within the script context + +The HTML specification has incredibly complex rules for how to handle +"<!--", "<script", and "</script" when they appear within literals in +the script context. Rather than attempting to apply these restrictions +(which require a significantly more complex state machine) we apply +the workaround suggested in section 4.12.1.3 of the HTML specification [1]. + +More precisely, when "<!--", "<script", and "</script" appear within +literals (strings and regular expressions, ignoring comments since we +already elide their content) we replace the "<" with "\x3C". This avoids +the unintuitive behavior that using these tags within literals can cause, +by simply preventing the rendered content from triggering it. This may +break some correct usages of these tags, but on balance is more likely +to prevent XSS attacks where users are unknowingly either closing or not +closing the script blocks where they think they are. + +Thanks to Takeshi Kaneko (GMO Cybersecurity by Ierae, Inc.) for +reporting this issue. + +Fixes #62197 +Fixes #62397 +Fixes CVE-2023-39319 + +[1] https://html.spec.whatwg.org/#restrictions-for-contents-of-script-elements + +Change-Id: Iab57b0532694827e3eddf57a7497ba1fab1746dc +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1976594 +Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> +Reviewed-by: Tatiana Bradley <tatianabradley@google.com> +Reviewed-by: Damien Neil <dneil@google.com> +Run-TryBot: Roland Shoemaker <bracewell@google.com> +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2014621 +TryBot-Result: Security TryBots <security-trybots@go-security-trybots.iam.gserviceaccount.com> +Reviewed-on: https://go-review.googlesource.com/c/go/+/526099 +TryBot-Result: Gopher Robot <gobot@golang.org> +Run-TryBot: Cherry Mui <cherryyz@google.com> + +Upstream-Status: Backport from [https://github.com/golang/go/commit/2070531d2f53df88e312edace6c8dfc9686ab2f5] +CVE: CVE-2023-39319 +Signed-off-by: Siddharth Doshi <sdoshi@mvista.com> +--- + src/html/template/context.go | 14 ++++++++++ + src/html/template/escape.go | 26 ++++++++++++++++++ + src/html/template/escape_test.go | 47 +++++++++++++++++++++++++++++++- + src/html/template/transition.go | 15 ++++++++++ + 4 files changed, 101 insertions(+), 1 deletion(-) + +diff --git a/src/html/template/context.go b/src/html/template/context.go +index 4eb7891..feb6517 100644 +--- a/src/html/template/context.go ++++ b/src/html/template/context.go +@@ -168,6 +168,20 @@ func isInTag(s state) bool { + return false + } + ++// isInScriptLiteral returns true if s is one of the literal states within a ++// <script> tag, and as such occurances of "<!--", "<script", and "</script" ++// need to be treated specially. ++func isInScriptLiteral(s state) bool { ++ // Ignore the comment states (stateJSBlockCmt, stateJSLineCmt, ++ // stateJSHTMLOpenCmt, stateJSHTMLCloseCmt) because their content is already ++ // omitted from the output. ++ switch s { ++ case stateJSDqStr, stateJSSqStr, stateJSBqStr, stateJSRegexp: ++ return true ++ } ++ return false ++} ++ + // delim is the delimiter that will end the current HTML attribute. + type delim uint8 + +diff --git a/src/html/template/escape.go b/src/html/template/escape.go +index ad2ec69..de8cf6f 100644 +--- a/src/html/template/escape.go ++++ b/src/html/template/escape.go +@@ -10,6 +10,7 @@ import ( + "html" + "internal/godebug" + "io" ++ "regexp" + "text/template" + "text/template/parse" + ) +@@ -650,6 +651,26 @@ var delimEnds = [...]string{ + delimSpaceOrTagEnd: " \t\n\f\r>", + } + ++var ( ++ // Per WHATWG HTML specification, section 4.12.1.3, there are extremely ++ // complicated rules for how to handle the set of opening tags <!--, ++ // <script, and </script when they appear in JS literals (i.e. strings, ++ // regexs, and comments). The specification suggests a simple solution, ++ // rather than implementing the arcane ABNF, which involves simply escaping ++ // the opening bracket with \x3C. We use the below regex for this, since it ++ // makes doing the case-insensitive find-replace much simpler. ++ specialScriptTagRE = regexp.MustCompile("(?i)<(script|/script|!--)") ++ specialScriptTagReplacement = []byte("\\x3C$1") ++) ++ ++func containsSpecialScriptTag(s []byte) bool { ++ return specialScriptTagRE.Match(s) ++} ++ ++func escapeSpecialScriptTags(s []byte) []byte { ++ return specialScriptTagRE.ReplaceAll(s, specialScriptTagReplacement) ++} ++ + var doctypeBytes = []byte("<!DOCTYPE") + + // escapeText escapes a text template node. +@@ -708,6 +729,11 @@ func (e *escaper) escapeText(c context, n *parse.TextNode) context { + b.Write(s[written:cs]) + written = i1 + } ++ if isInScriptLiteral(c.state) && containsSpecialScriptTag(s[i:i1]) { ++ b.Write(s[written:i]) ++ b.Write(escapeSpecialScriptTags(s[i:i1])) ++ written = i1 ++ } + if i == i1 && c.state == c1.state { + panic(fmt.Sprintf("infinite loop from %v to %v on %q..%q", c, c1, s[:i], s[i:])) + } +diff --git a/src/html/template/escape_test.go b/src/html/template/escape_test.go +index 5f41e52..0cacb20 100644 +--- a/src/html/template/escape_test.go ++++ b/src/html/template/escape_test.go +@@ -513,6 +513,21 @@ func TestEscape(t *testing.T) { + "<script>#! beep\n</script>", + "<script>\n</script>", + }, ++ { ++ "Special tags in <script> string literals", ++ `<script>var a = "asd < 123 <!-- 456 < fgh <script jkl < 789 </script"</script>`, ++ `<script>var a = "asd < 123 \x3C!-- 456 < fgh \x3Cscript jkl < 789 \x3C/script"</script>`, ++ }, ++ { ++ "Special tags in <script> string literals (mixed case)", ++ `<script>var a = "<!-- <ScripT </ScripT"</script>`, ++ `<script>var a = "\x3C!-- \x3CScripT \x3C/ScripT"</script>`, ++ }, ++ { ++ "Special tags in <script> regex literals (mixed case)", ++ `<script>var a = /<!-- <ScripT </ScripT/</script>`, ++ `<script>var a = /\x3C!-- \x3CScripT \x3C/ScripT/</script>`, ++ }, + { + "CSS comments", + "<style>p// paragraph\n" + +@@ -1501,8 +1516,38 @@ func TestEscapeText(t *testing.T) { + context{state: stateJS, element: elementScript}, + }, + { ++ // <script and </script tags are escaped, so </script> should not ++ // cause us to exit the JS state. + `<script>document.write("<script>alert(1)</script>");`, +- context{state: stateText}, ++ context{state: stateJS, element: elementScript}, ++ }, ++ { ++ `<script>document.write("<script>`, ++ context{state: stateJSDqStr, element: elementScript}, ++ }, ++ { ++ `<script>document.write("<script>alert(1)</script>`, ++ context{state: stateJSDqStr, element: elementScript}, ++ }, ++ { ++ `<script>document.write("<script>alert(1)<!--`, ++ context{state: stateJSDqStr, element: elementScript}, ++ }, ++ { ++ `<script>document.write("<script>alert(1)</Script>");`, ++ context{state: stateJS, element: elementScript}, ++ }, ++ { ++ `<script>document.write("<!--");`, ++ context{state: stateJS, element: elementScript}, ++ }, ++ { ++ `<script>let a = /</script`, ++ context{state: stateJSRegexp, element: elementScript}, ++ }, ++ { ++ `<script>let a = /</script/`, ++ context{state: stateJS, element: elementScript, jsCtx: jsCtxDivOp}, + }, + { + `<script type="text/template">`, +diff --git a/src/html/template/transition.go b/src/html/template/transition.go +index 12aa4c4..3d2a37c 100644 +--- a/src/html/template/transition.go ++++ b/src/html/template/transition.go +@@ -214,6 +214,11 @@ var ( + // element states. + func tSpecialTagEnd(c context, s []byte) (context, int) { + if c.element != elementNone { ++ // script end tags ("</script") within script literals are ignored, so that ++ // we can properly escape them. ++ if c.element == elementScript && (isInScriptLiteral(c.state) || isComment(c.state)) { ++ return c, len(s) ++ } + if i := indexTagEnd(s, specialTagEndMarkers[c.element]); i != -1 { + return context{}, i + } +@@ -353,6 +358,16 @@ func tJSDelimited(c context, s []byte) (context, int) { + inCharset = true + case ']': + inCharset = false ++ case '/': ++ // If "</script" appears in a regex literal, the '/' should not ++ // close the regex literal, and it will later be escaped to ++ // "\x3C/script" in escapeText. ++ if i > 0 && i+7 <= len(s) && bytes.Compare(bytes.ToLower(s[i-1:i+7]), []byte("</script")) == 0 { ++ i++ ++ } else if !inCharset { ++ c.state, c.jsCtx = stateJS, jsCtxDivOp ++ return c, i + 1 ++ } + default: + // end delimiter + if !inCharset { +-- +2.24.4 + diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-39326.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-39326.patch new file mode 100644 index 0000000000..998af361e8 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-39326.patch @@ -0,0 +1,181 @@ +From 6446af942e2e2b161c4ec1b60d9703a2b55dc4dd Mon Sep 17 00:00:00 2001 +From: Damien Neil <dneil@google.com> +Date: Tue, 7 Nov 2023 10:47:56 -0800 +Subject: [PATCH] [release-branch.go1.20] net/http: limit chunked data overhead + +The chunked transfer encoding adds some overhead to +the content transferred. When writing one byte per +chunk, for example, there are five bytes of overhead +per byte of data transferred: "1\r\nX\r\n" to send "X". + +Chunks may include "chunk extensions", +which we skip over and do not use. +For example: "1;chunk extension here\r\nX\r\n". + +A malicious sender can use chunk extensions to add +about 4k of overhead per byte of data. +(The maximum chunk header line size we will accept.) + +Track the amount of overhead read in chunked data, +and produce an error if it seems excessive. + +Updates #64433 +Fixes #64434 +Fixes CVE-2023-39326 + +Change-Id: I40f8d70eb6f9575fb43f506eb19132ccedafcf39 +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2076135 +Reviewed-by: Tatiana Bradley <tatianabradley@google.com> +Reviewed-by: Roland Shoemaker <bracewell@google.com> +(cherry picked from commit 3473ae72ee66c60744665a24b2fde143e8964d4f) +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2095407 +Run-TryBot: Roland Shoemaker <bracewell@google.com> +TryBot-Result: Security TryBots <security-trybots@go-security-trybots.iam.gserviceaccount.com> +Reviewed-by: Damien Neil <dneil@google.com> +Reviewed-on: https://go-review.googlesource.com/c/go/+/547355 +Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> +LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> + +Upstream-Status: Backport [https://github.com/golang/go/commit/6446af942e2e2b161c4ec1b60d9703a2b55dc4dd] +CVE: CVE-2023-39326 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + src/net/http/internal/chunked.go | 36 +++++++++++++--- + src/net/http/internal/chunked_test.go | 59 +++++++++++++++++++++++++++ + 2 files changed, 89 insertions(+), 6 deletions(-) + +diff --git a/src/net/http/internal/chunked.go b/src/net/http/internal/chunked.go +index f06e572..ddbaacb 100644 +--- a/src/net/http/internal/chunked.go ++++ b/src/net/http/internal/chunked.go +@@ -39,7 +39,8 @@ type chunkedReader struct { + n uint64 // unread bytes in chunk + err error + buf [2]byte +- checkEnd bool // whether need to check for \r\n chunk footer ++ checkEnd bool // whether need to check for \r\n chunk footer ++ excess int64 // "excessive" chunk overhead, for malicious sender detection + } + + func (cr *chunkedReader) beginChunk() { +@@ -49,10 +50,38 @@ func (cr *chunkedReader) beginChunk() { + if cr.err != nil { + return + } ++ cr.excess += int64(len(line)) + 2 // header, plus \r\n after the chunk data ++ line = trimTrailingWhitespace(line) ++ line, cr.err = removeChunkExtension(line) ++ if cr.err != nil { ++ return ++ } + cr.n, cr.err = parseHexUint(line) + if cr.err != nil { + return + } ++ // A sender who sends one byte per chunk will send 5 bytes of overhead ++ // for every byte of data. ("1\r\nX\r\n" to send "X".) ++ // We want to allow this, since streaming a byte at a time can be legitimate. ++ // ++ // A sender can use chunk extensions to add arbitrary amounts of additional ++ // data per byte read. ("1;very long extension\r\nX\r\n" to send "X".) ++ // We don't want to disallow extensions (although we discard them), ++ // but we also don't want to allow a sender to reduce the signal/noise ratio ++ // arbitrarily. ++ // ++ // We track the amount of excess overhead read, ++ // and produce an error if it grows too large. ++ // ++ // Currently, we say that we're willing to accept 16 bytes of overhead per chunk, ++ // plus twice the amount of real data in the chunk. ++ cr.excess -= 16 + (2 * int64(cr.n)) ++ if cr.excess < 0 { ++ cr.excess = 0 ++ } ++ if cr.excess > 16*1024 { ++ cr.err = errors.New("chunked encoding contains too much non-data") ++ } + if cr.n == 0 { + cr.err = io.EOF + } +@@ -133,11 +162,6 @@ func readChunkLine(b *bufio.Reader) ([]byte, error) { + if len(p) >= maxLineLength { + return nil, ErrLineTooLong + } +- p = trimTrailingWhitespace(p) +- p, err = removeChunkExtension(p) +- if err != nil { +- return nil, err +- } + return p, nil + } + +diff --git a/src/net/http/internal/chunked_test.go b/src/net/http/internal/chunked_test.go +index d067165..b20747d 100644 +--- a/src/net/http/internal/chunked_test.go ++++ b/src/net/http/internal/chunked_test.go +@@ -212,3 +212,62 @@ func TestChunkReadPartial(t *testing.T) { + } + + } ++ ++func TestChunkReaderTooMuchOverhead(t *testing.T) { ++ // If the sender is sending 100x as many chunk header bytes as chunk data, ++ // we should reject the stream at some point. ++ chunk := []byte("1;") ++ for i := 0; i < 100; i++ { ++ chunk = append(chunk, 'a') // chunk extension ++ } ++ chunk = append(chunk, "\r\nX\r\n"...) ++ const bodylen = 1 << 20 ++ r := NewChunkedReader(&funcReader{f: func(i int) ([]byte, error) { ++ if i < bodylen { ++ return chunk, nil ++ } ++ return []byte("0\r\n"), nil ++ }}) ++ _, err := io.ReadAll(r) ++ if err == nil { ++ t.Fatalf("successfully read body with excessive overhead; want error") ++ } ++} ++ ++func TestChunkReaderByteAtATime(t *testing.T) { ++ // Sending one byte per chunk should not trip the excess-overhead detection. ++ const bodylen = 1 << 20 ++ r := NewChunkedReader(&funcReader{f: func(i int) ([]byte, error) { ++ if i < bodylen { ++ return []byte("1\r\nX\r\n"), nil ++ } ++ return []byte("0\r\n"), nil ++ }}) ++ got, err := io.ReadAll(r) ++ if err != nil { ++ t.Errorf("unexpected error: %v", err) ++ } ++ if len(got) != bodylen { ++ t.Errorf("read %v bytes, want %v", len(got), bodylen) ++ } ++} ++ ++type funcReader struct { ++ f func(iteration int) ([]byte, error) ++ i int ++ b []byte ++ err error ++} ++ ++func (r *funcReader) Read(p []byte) (n int, err error) { ++ if len(r.b) == 0 && r.err == nil { ++ r.b, r.err = r.f(r.i) ++ r.i++ ++ } ++ n = copy(p, r.b) ++ r.b = r.b[n:] ++ if len(r.b) > 0 { ++ return n, nil ++ } ++ return n, r.err ++} +-- +2.25.1 + diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-45287-pre1.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-45287-pre1.patch new file mode 100644 index 0000000000..4d65180253 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-45287-pre1.patch @@ -0,0 +1,393 @@ +From 9baafabac9a84813a336f068862207d2bb06d255 Mon Sep 17 00:00:00 2001 +From: Filippo Valsorda <filippo@golang.org> +Date: Wed, 1 Apr 2020 17:25:40 -0400 +Subject: [PATCH] crypto/rsa: refactor RSA-PSS signing and verification + +Cleaned up for readability and consistency. + +There is one tiny behavioral change: when PSSSaltLengthEqualsHash is +used and both hash and opts.Hash were set, hash.Size() was used for the +salt length instead of opts.Hash.Size(). That's clearly wrong because +opts.Hash is documented to override hash. + +Change-Id: I3e25dad933961eac827c6d2e3bbfe45fc5a6fb0e +Reviewed-on: https://go-review.googlesource.com/c/go/+/226937 +Run-TryBot: Filippo Valsorda <filippo@golang.org> +TryBot-Result: Gobot Gobot <gobot@golang.org> +Reviewed-by: Katie Hockman <katie@golang.org> + +Upstream-Status: Backport [https://github.com/golang/go/commit/9baafabac9a84813a336f068862207d2bb06d255] +CVE: CVE-2023-45287 #Dependency Patch1 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + src/crypto/rsa/pss.go | 173 ++++++++++++++++++++++-------------------- + src/crypto/rsa/rsa.go | 9 ++- + 2 files changed, 96 insertions(+), 86 deletions(-) + +diff --git a/src/crypto/rsa/pss.go b/src/crypto/rsa/pss.go +index 3ff0c2f4d0076..f9844d87329a8 100644 +--- a/src/crypto/rsa/pss.go ++++ b/src/crypto/rsa/pss.go +@@ -4,9 +4,7 @@ + + package rsa + +-// This file implements the PSS signature scheme [1]. +-// +-// [1] https://www.emc.com/collateral/white-papers/h11300-pkcs-1v2-2-rsa-cryptography-standard-wp.pdf ++// This file implements the RSASSA-PSS signature scheme according to RFC 8017. + + import ( + "bytes" +@@ -17,8 +15,22 @@ import ( + "math/big" + ) + ++// Per RFC 8017, Section 9.1 ++// ++// EM = MGF1 xor DB || H( 8*0x00 || mHash || salt ) || 0xbc ++// ++// where ++// ++// DB = PS || 0x01 || salt ++// ++// and PS can be empty so ++// ++// emLen = dbLen + hLen + 1 = psLen + sLen + hLen + 2 ++// ++ + func emsaPSSEncode(mHash []byte, emBits int, salt []byte, hash hash.Hash) ([]byte, error) { +- // See [1], section 9.1.1 ++ // See RFC 8017, Section 9.1.1. ++ + hLen := hash.Size() + sLen := len(salt) + emLen := (emBits + 7) / 8 +@@ -30,7 +42,7 @@ func emsaPSSEncode(mHash []byte, emBits int, salt []byte, hash hash.Hash) ([]byt + // 2. Let mHash = Hash(M), an octet string of length hLen. + + if len(mHash) != hLen { +- return nil, errors.New("crypto/rsa: input must be hashed message") ++ return nil, errors.New("crypto/rsa: input must be hashed with given hash") + } + + // 3. If emLen < hLen + sLen + 2, output "encoding error" and stop. +@@ -40,8 +52,9 @@ func emsaPSSEncode(mHash []byte, emBits int, salt []byte, hash hash.Hash) ([]byt + } + + em := make([]byte, emLen) +- db := em[:emLen-sLen-hLen-2+1+sLen] +- h := em[emLen-sLen-hLen-2+1+sLen : emLen-1] ++ psLen := emLen - sLen - hLen - 2 ++ db := em[:psLen+1+sLen] ++ h := em[psLen+1+sLen : emLen-1] + + // 4. Generate a random octet string salt of length sLen; if sLen = 0, + // then salt is the empty string. +@@ -69,8 +82,8 @@ func emsaPSSEncode(mHash []byte, emBits int, salt []byte, hash hash.Hash) ([]byt + // 8. Let DB = PS || 0x01 || salt; DB is an octet string of length + // emLen - hLen - 1. + +- db[emLen-sLen-hLen-2] = 0x01 +- copy(db[emLen-sLen-hLen-1:], salt) ++ db[psLen] = 0x01 ++ copy(db[psLen+1:], salt) + + // 9. Let dbMask = MGF(H, emLen - hLen - 1). + // +@@ -81,47 +94,57 @@ func emsaPSSEncode(mHash []byte, emBits int, salt []byte, hash hash.Hash) ([]byt + // 11. Set the leftmost 8 * emLen - emBits bits of the leftmost octet in + // maskedDB to zero. + +- db[0] &= (0xFF >> uint(8*emLen-emBits)) ++ db[0] &= 0xff >> (8*emLen - emBits) + + // 12. Let EM = maskedDB || H || 0xbc. +- em[emLen-1] = 0xBC ++ em[emLen-1] = 0xbc + + // 13. Output EM. + return em, nil + } + + func emsaPSSVerify(mHash, em []byte, emBits, sLen int, hash hash.Hash) error { ++ // See RFC 8017, Section 9.1.2. ++ ++ hLen := hash.Size() ++ if sLen == PSSSaltLengthEqualsHash { ++ sLen = hLen ++ } ++ emLen := (emBits + 7) / 8 ++ if emLen != len(em) { ++ return errors.New("rsa: internal error: inconsistent length") ++ } ++ + // 1. If the length of M is greater than the input limitation for the + // hash function (2^61 - 1 octets for SHA-1), output "inconsistent" + // and stop. + // + // 2. Let mHash = Hash(M), an octet string of length hLen. +- hLen := hash.Size() + if hLen != len(mHash) { + return ErrVerification + } + + // 3. If emLen < hLen + sLen + 2, output "inconsistent" and stop. +- emLen := (emBits + 7) / 8 + if emLen < hLen+sLen+2 { + return ErrVerification + } + + // 4. If the rightmost octet of EM does not have hexadecimal value + // 0xbc, output "inconsistent" and stop. +- if em[len(em)-1] != 0xBC { ++ if em[emLen-1] != 0xbc { + return ErrVerification + } + + // 5. Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, and + // let H be the next hLen octets. + db := em[:emLen-hLen-1] +- h := em[emLen-hLen-1 : len(em)-1] ++ h := em[emLen-hLen-1 : emLen-1] + + // 6. If the leftmost 8 * emLen - emBits bits of the leftmost octet in + // maskedDB are not all equal to zero, output "inconsistent" and + // stop. +- if em[0]&(0xFF<<uint(8-(8*emLen-emBits))) != 0 { ++ var bitMask byte = 0xff >> (8*emLen - emBits) ++ if em[0] & ^bitMask != 0 { + return ErrVerification + } + +@@ -132,37 +155,30 @@ func emsaPSSVerify(mHash, em []byte, emBits, sLen int, hash hash.Hash) error { + + // 9. Set the leftmost 8 * emLen - emBits bits of the leftmost octet in DB + // to zero. +- db[0] &= (0xFF >> uint(8*emLen-emBits)) ++ db[0] &= bitMask + ++ // If we don't know the salt length, look for the 0x01 delimiter. + if sLen == PSSSaltLengthAuto { +- FindSaltLength: +- for sLen = emLen - (hLen + 2); sLen >= 0; sLen-- { +- switch db[emLen-hLen-sLen-2] { +- case 1: +- break FindSaltLength +- case 0: +- continue +- default: +- return ErrVerification +- } +- } +- if sLen < 0 { ++ psLen := bytes.IndexByte(db, 0x01) ++ if psLen < 0 { + return ErrVerification + } +- } else { +- // 10. If the emLen - hLen - sLen - 2 leftmost octets of DB are not zero +- // or if the octet at position emLen - hLen - sLen - 1 (the leftmost +- // position is "position 1") does not have hexadecimal value 0x01, +- // output "inconsistent" and stop. +- for _, e := range db[:emLen-hLen-sLen-2] { +- if e != 0x00 { +- return ErrVerification +- } +- } +- if db[emLen-hLen-sLen-2] != 0x01 { ++ sLen = len(db) - psLen - 1 ++ } ++ ++ // 10. If the emLen - hLen - sLen - 2 leftmost octets of DB are not zero ++ // or if the octet at position emLen - hLen - sLen - 1 (the leftmost ++ // position is "position 1") does not have hexadecimal value 0x01, ++ // output "inconsistent" and stop. ++ psLen := emLen - hLen - sLen - 2 ++ for _, e := range db[:psLen] { ++ if e != 0x00 { + return ErrVerification + } + } ++ if db[psLen] != 0x01 { ++ return ErrVerification ++ } + + // 11. Let salt be the last sLen octets of DB. + salt := db[len(db)-sLen:] +@@ -181,19 +197,19 @@ func emsaPSSVerify(mHash, em []byte, emBits, sLen int, hash hash.Hash) error { + h0 := hash.Sum(nil) + + // 14. If H = H', output "consistent." Otherwise, output "inconsistent." +- if !bytes.Equal(h0, h) { ++ if !bytes.Equal(h0, h) { // TODO: constant time? + return ErrVerification + } + return nil + } + +-// signPSSWithSalt calculates the signature of hashed using PSS [1] with specified salt. ++// signPSSWithSalt calculates the signature of hashed using PSS with specified salt. + // Note that hashed must be the result of hashing the input message using the + // given hash function. salt is a random sequence of bytes whose length will be + // later used to verify the signature. + func signPSSWithSalt(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed, salt []byte) (s []byte, err error) { +- nBits := priv.N.BitLen() +- em, err := emsaPSSEncode(hashed, nBits-1, salt, hash.New()) ++ emBits := priv.N.BitLen() - 1 ++ em, err := emsaPSSEncode(hashed, emBits, salt, hash.New()) + if err != nil { + return + } +@@ -202,7 +218,7 @@ func signPSSWithSalt(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed, + if err != nil { + return + } +- s = make([]byte, (nBits+7)/8) ++ s = make([]byte, priv.Size()) + copyWithLeftPad(s, c.Bytes()) + return + } +@@ -223,16 +239,15 @@ type PSSOptions struct { + // PSSSaltLength constants. + SaltLength int + +- // Hash, if not zero, overrides the hash function passed to SignPSS. +- // This is the only way to specify the hash function when using the +- // crypto.Signer interface. ++ // Hash is the hash function used to generate the message digest. If not ++ // zero, it overrides the hash function passed to SignPSS. It's required ++ // when using PrivateKey.Sign. + Hash crypto.Hash + } + +-// HashFunc returns pssOpts.Hash so that PSSOptions implements +-// crypto.SignerOpts. +-func (pssOpts *PSSOptions) HashFunc() crypto.Hash { +- return pssOpts.Hash ++// HashFunc returns opts.Hash so that PSSOptions implements crypto.SignerOpts. ++func (opts *PSSOptions) HashFunc() crypto.Hash { ++ return opts.Hash + } + + func (opts *PSSOptions) saltLength() int { +@@ -242,56 +257,50 @@ func (opts *PSSOptions) saltLength() int { + return opts.SaltLength + } + +-// SignPSS calculates the signature of hashed using RSASSA-PSS [1]. +-// Note that hashed must be the result of hashing the input message using the +-// given hash function. The opts argument may be nil, in which case sensible +-// defaults are used. +-func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte, opts *PSSOptions) ([]byte, error) { ++// SignPSS calculates the signature of digest using PSS. ++// ++// digest must be the result of hashing the input message using the given hash ++// function. The opts argument may be nil, in which case sensible defaults are ++// used. If opts.Hash is set, it overrides hash. ++func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, digest []byte, opts *PSSOptions) ([]byte, error) { ++ if opts != nil && opts.Hash != 0 { ++ hash = opts.Hash ++ } ++ + saltLength := opts.saltLength() + switch saltLength { + case PSSSaltLengthAuto: +- saltLength = (priv.N.BitLen()+7)/8 - 2 - hash.Size() ++ saltLength = priv.Size() - 2 - hash.Size() + case PSSSaltLengthEqualsHash: + saltLength = hash.Size() + } + +- if opts != nil && opts.Hash != 0 { +- hash = opts.Hash +- } +- + salt := make([]byte, saltLength) + if _, err := io.ReadFull(rand, salt); err != nil { + return nil, err + } +- return signPSSWithSalt(rand, priv, hash, hashed, salt) ++ return signPSSWithSalt(rand, priv, hash, digest, salt) + } + + // VerifyPSS verifies a PSS signature. +-// hashed is the result of hashing the input message using the given hash +-// function and sig is the signature. A valid signature is indicated by +-// returning a nil error. The opts argument may be nil, in which case sensible +-// defaults are used. +-func VerifyPSS(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte, opts *PSSOptions) error { +- return verifyPSS(pub, hash, hashed, sig, opts.saltLength()) +-} +- +-// verifyPSS verifies a PSS signature with the given salt length. +-func verifyPSS(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte, saltLen int) error { +- nBits := pub.N.BitLen() +- if len(sig) != (nBits+7)/8 { ++// ++// A valid signature is indicated by returning a nil error. digest must be the ++// result of hashing the input message using the given hash function. The opts ++// argument may be nil, in which case sensible defaults are used. opts.Hash is ++// ignored. ++func VerifyPSS(pub *PublicKey, hash crypto.Hash, digest []byte, sig []byte, opts *PSSOptions) error { ++ if len(sig) != pub.Size() { + return ErrVerification + } + s := new(big.Int).SetBytes(sig) + m := encrypt(new(big.Int), pub, s) +- emBits := nBits - 1 ++ emBits := pub.N.BitLen() - 1 + emLen := (emBits + 7) / 8 +- if emLen < len(m.Bytes()) { ++ emBytes := m.Bytes() ++ if emLen < len(emBytes) { + return ErrVerification + } + em := make([]byte, emLen) +- copyWithLeftPad(em, m.Bytes()) +- if saltLen == PSSSaltLengthEqualsHash { +- saltLen = hash.Size() +- } +- return emsaPSSVerify(hashed, em, emBits, saltLen, hash.New()) ++ copyWithLeftPad(em, emBytes) ++ return emsaPSSVerify(digest, em, emBits, opts.saltLength(), hash.New()) + } +diff --git a/src/crypto/rsa/rsa.go b/src/crypto/rsa/rsa.go +index 5a42990640164..b4bfa13defbdf 100644 +--- a/src/crypto/rsa/rsa.go ++++ b/src/crypto/rsa/rsa.go +@@ -2,7 +2,7 @@ + // Use of this source code is governed by a BSD-style + // license that can be found in the LICENSE file. + +-// Package rsa implements RSA encryption as specified in PKCS#1. ++// Package rsa implements RSA encryption as specified in PKCS#1 and RFC 8017. + // + // RSA is a single, fundamental operation that is used in this package to + // implement either public-key encryption or public-key signatures. +@@ -10,13 +10,13 @@ + // The original specification for encryption and signatures with RSA is PKCS#1 + // and the terms "RSA encryption" and "RSA signatures" by default refer to + // PKCS#1 version 1.5. However, that specification has flaws and new designs +-// should use version two, usually called by just OAEP and PSS, where ++// should use version 2, usually called by just OAEP and PSS, where + // possible. + // + // Two sets of interfaces are included in this package. When a more abstract + // interface isn't necessary, there are functions for encrypting/decrypting + // with v1.5/OAEP and signing/verifying with v1.5/PSS. If one needs to abstract +-// over the public-key primitive, the PrivateKey struct implements the ++// over the public key primitive, the PrivateKey type implements the + // Decrypter and Signer interfaces from the crypto package. + // + // The RSA operations in this package are not implemented using constant-time algorithms. +@@ -111,7 +111,8 @@ func (priv *PrivateKey) Public() crypto.PublicKey { + + // Sign signs digest with priv, reading randomness from rand. If opts is a + // *PSSOptions then the PSS algorithm will be used, otherwise PKCS#1 v1.5 will +-// be used. ++// be used. digest must be the result of hashing the input message using ++// opts.HashFunc(). + // + // This method implements crypto.Signer, which is an interface to support keys + // where the private part is kept in, for example, a hardware module. Common diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-45287-pre2.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-45287-pre2.patch new file mode 100644 index 0000000000..1327b44545 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-45287-pre2.patch @@ -0,0 +1,401 @@ +From c9d5f60eaa4450ccf1ce878d55b4c6a12843f2f3 Mon Sep 17 00:00:00 2001 +From: Filippo Valsorda <filippo@golang.org> +Date: Mon, 27 Apr 2020 21:52:38 -0400 +Subject: [PATCH] math/big: add (*Int).FillBytes + +Replaced almost every use of Bytes with FillBytes. + +Note that the approved proposal was for + + func (*Int) FillBytes(buf []byte) + +while this implements + + func (*Int) FillBytes(buf []byte) []byte + +because the latter was far nicer to use in all callsites. + +Fixes #35833 + +Change-Id: Ia912df123e5d79b763845312ea3d9a8051343c0a +Reviewed-on: https://go-review.googlesource.com/c/go/+/230397 +Reviewed-by: Robert Griesemer <gri@golang.org> + +Upstream-Status: Backport [https://github.com/golang/go/commit/c9d5f60eaa4450ccf1ce878d55b4c6a12843f2f3] +CVE: CVE-2023-45287 #Dependency Patch2 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + src/crypto/elliptic/elliptic.go | 13 ++++---- + src/crypto/rsa/pkcs1v15.go | 20 +++--------- + src/crypto/rsa/pss.go | 17 +++++------ + src/crypto/rsa/rsa.go | 32 +++---------------- + src/crypto/tls/key_schedule.go | 7 ++--- + src/crypto/x509/sec1.go | 7 ++--- + src/math/big/int.go | 15 +++++++++ + src/math/big/int_test.go | 54 +++++++++++++++++++++++++++++++++ + src/math/big/nat.go | 15 ++++++--- + 9 files changed, 106 insertions(+), 74 deletions(-) + +diff --git a/src/crypto/elliptic/elliptic.go b/src/crypto/elliptic/elliptic.go +index e2f71cdb63bab..bd5168c5fd842 100644 +--- a/src/crypto/elliptic/elliptic.go ++++ b/src/crypto/elliptic/elliptic.go +@@ -277,7 +277,7 @@ var mask = []byte{0xff, 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f} + func GenerateKey(curve Curve, rand io.Reader) (priv []byte, x, y *big.Int, err error) { + N := curve.Params().N + bitSize := N.BitLen() +- byteLen := (bitSize + 7) >> 3 ++ byteLen := (bitSize + 7) / 8 + priv = make([]byte, byteLen) + + for x == nil { +@@ -304,15 +304,14 @@ func GenerateKey(curve Curve, rand io.Reader) (priv []byte, x, y *big.Int, err e + + // Marshal converts a point into the uncompressed form specified in section 4.3.6 of ANSI X9.62. + func Marshal(curve Curve, x, y *big.Int) []byte { +- byteLen := (curve.Params().BitSize + 7) >> 3 ++ byteLen := (curve.Params().BitSize + 7) / 8 + + ret := make([]byte, 1+2*byteLen) + ret[0] = 4 // uncompressed point + +- xBytes := x.Bytes() +- copy(ret[1+byteLen-len(xBytes):], xBytes) +- yBytes := y.Bytes() +- copy(ret[1+2*byteLen-len(yBytes):], yBytes) ++ x.FillBytes(ret[1 : 1+byteLen]) ++ y.FillBytes(ret[1+byteLen : 1+2*byteLen]) ++ + return ret + } + +@@ -320,7 +319,7 @@ func Marshal(curve Curve, x, y *big.Int) []byte { + // It is an error if the point is not in uncompressed form or is not on the curve. + // On error, x = nil. + func Unmarshal(curve Curve, data []byte) (x, y *big.Int) { +- byteLen := (curve.Params().BitSize + 7) >> 3 ++ byteLen := (curve.Params().BitSize + 7) / 8 + if len(data) != 1+2*byteLen { + return + } +diff --git a/src/crypto/rsa/pkcs1v15.go b/src/crypto/rsa/pkcs1v15.go +index 499242ffc5b57..3208119ae1ff4 100644 +--- a/src/crypto/rsa/pkcs1v15.go ++++ b/src/crypto/rsa/pkcs1v15.go +@@ -61,8 +61,7 @@ func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) ([]byte, error) + m := new(big.Int).SetBytes(em) + c := encrypt(new(big.Int), pub, m) + +- copyWithLeftPad(em, c.Bytes()) +- return em, nil ++ return c.FillBytes(em), nil + } + + // DecryptPKCS1v15 decrypts a plaintext using RSA and the padding scheme from PKCS#1 v1.5. +@@ -150,7 +149,7 @@ func decryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (valid + return + } + +- em = leftPad(m.Bytes(), k) ++ em = m.FillBytes(make([]byte, k)) + firstByteIsZero := subtle.ConstantTimeByteEq(em[0], 0) + secondByteIsTwo := subtle.ConstantTimeByteEq(em[1], 2) + +@@ -256,8 +255,7 @@ func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []b + return nil, err + } + +- copyWithLeftPad(em, c.Bytes()) +- return em, nil ++ return c.FillBytes(em), nil + } + + // VerifyPKCS1v15 verifies an RSA PKCS#1 v1.5 signature. +@@ -286,7 +284,7 @@ func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) + + c := new(big.Int).SetBytes(sig) + m := encrypt(new(big.Int), pub, c) +- em := leftPad(m.Bytes(), k) ++ em := m.FillBytes(make([]byte, k)) + // EM = 0x00 || 0x01 || PS || 0x00 || T + + ok := subtle.ConstantTimeByteEq(em[0], 0) +@@ -323,13 +321,3 @@ func pkcs1v15HashInfo(hash crypto.Hash, inLen int) (hashLen int, prefix []byte, + } + return + } +- +-// copyWithLeftPad copies src to the end of dest, padding with zero bytes as +-// needed. +-func copyWithLeftPad(dest, src []byte) { +- numPaddingBytes := len(dest) - len(src) +- for i := 0; i < numPaddingBytes; i++ { +- dest[i] = 0 +- } +- copy(dest[numPaddingBytes:], src) +-} +diff --git a/src/crypto/rsa/pss.go b/src/crypto/rsa/pss.go +index f9844d87329a8..b2adbedb28fa8 100644 +--- a/src/crypto/rsa/pss.go ++++ b/src/crypto/rsa/pss.go +@@ -207,20 +207,19 @@ func emsaPSSVerify(mHash, em []byte, emBits, sLen int, hash hash.Hash) error { + // Note that hashed must be the result of hashing the input message using the + // given hash function. salt is a random sequence of bytes whose length will be + // later used to verify the signature. +-func signPSSWithSalt(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed, salt []byte) (s []byte, err error) { ++func signPSSWithSalt(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed, salt []byte) ([]byte, error) { + emBits := priv.N.BitLen() - 1 + em, err := emsaPSSEncode(hashed, emBits, salt, hash.New()) + if err != nil { +- return ++ return nil, err + } + m := new(big.Int).SetBytes(em) + c, err := decryptAndCheck(rand, priv, m) + if err != nil { +- return ++ return nil, err + } +- s = make([]byte, priv.Size()) +- copyWithLeftPad(s, c.Bytes()) +- return ++ s := make([]byte, priv.Size()) ++ return c.FillBytes(s), nil + } + + const ( +@@ -296,11 +295,9 @@ func VerifyPSS(pub *PublicKey, hash crypto.Hash, digest []byte, sig []byte, opts + m := encrypt(new(big.Int), pub, s) + emBits := pub.N.BitLen() - 1 + emLen := (emBits + 7) / 8 +- emBytes := m.Bytes() +- if emLen < len(emBytes) { ++ if m.BitLen() > emLen*8 { + return ErrVerification + } +- em := make([]byte, emLen) +- copyWithLeftPad(em, emBytes) ++ em := m.FillBytes(make([]byte, emLen)) + return emsaPSSVerify(digest, em, emBits, opts.saltLength(), hash.New()) + } +diff --git a/src/crypto/rsa/rsa.go b/src/crypto/rsa/rsa.go +index b4bfa13defbdf..28eb5926c1a54 100644 +--- a/src/crypto/rsa/rsa.go ++++ b/src/crypto/rsa/rsa.go +@@ -416,16 +416,9 @@ func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, l + m := new(big.Int) + m.SetBytes(em) + c := encrypt(new(big.Int), pub, m) +- out := c.Bytes() + +- if len(out) < k { +- // If the output is too small, we need to left-pad with zeros. +- t := make([]byte, k) +- copy(t[k-len(out):], out) +- out = t +- } +- +- return out, nil ++ out := make([]byte, k) ++ return c.FillBytes(out), nil + } + + // ErrDecryption represents a failure to decrypt a message. +@@ -597,12 +590,9 @@ func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext + lHash := hash.Sum(nil) + hash.Reset() + +- // Converting the plaintext number to bytes will strip any +- // leading zeros so we may have to left pad. We do this unconditionally +- // to avoid leaking timing information. (Although we still probably +- // leak the number of leading zeros. It's not clear that we can do +- // anything about this.) +- em := leftPad(m.Bytes(), k) ++ // We probably leak the number of leading zeros. ++ // It's not clear that we can do anything about this. ++ em := m.FillBytes(make([]byte, k)) + + firstByteIsZero := subtle.ConstantTimeByteEq(em[0], 0) + +@@ -643,15 +633,3 @@ func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext + + return rest[index+1:], nil + } +- +-// leftPad returns a new slice of length size. The contents of input are right +-// aligned in the new slice. +-func leftPad(input []byte, size int) (out []byte) { +- n := len(input) +- if n > size { +- n = size +- } +- out = make([]byte, size) +- copy(out[len(out)-n:], input) +- return +-} +diff --git a/src/crypto/tls/key_schedule.go b/src/crypto/tls/key_schedule.go +index 2aab323202f7d..314016979afb8 100644 +--- a/src/crypto/tls/key_schedule.go ++++ b/src/crypto/tls/key_schedule.go +@@ -173,11 +173,8 @@ func (p *nistParameters) SharedKey(peerPublicKey []byte) []byte { + } + + xShared, _ := curve.ScalarMult(x, y, p.privateKey) +- sharedKey := make([]byte, (curve.Params().BitSize+7)>>3) +- xBytes := xShared.Bytes() +- copy(sharedKey[len(sharedKey)-len(xBytes):], xBytes) +- +- return sharedKey ++ sharedKey := make([]byte, (curve.Params().BitSize+7)/8) ++ return xShared.FillBytes(sharedKey) + } + + type x25519Parameters struct { +diff --git a/src/crypto/x509/sec1.go b/src/crypto/x509/sec1.go +index 0bfb90cd5464a..52c108ff1d624 100644 +--- a/src/crypto/x509/sec1.go ++++ b/src/crypto/x509/sec1.go +@@ -52,13 +52,10 @@ func MarshalECPrivateKey(key *ecdsa.PrivateKey) ([]byte, error) { + // marshalECPrivateKey marshals an EC private key into ASN.1, DER format and + // sets the curve ID to the given OID, or omits it if OID is nil. + func marshalECPrivateKeyWithOID(key *ecdsa.PrivateKey, oid asn1.ObjectIdentifier) ([]byte, error) { +- privateKeyBytes := key.D.Bytes() +- paddedPrivateKey := make([]byte, (key.Curve.Params().N.BitLen()+7)/8) +- copy(paddedPrivateKey[len(paddedPrivateKey)-len(privateKeyBytes):], privateKeyBytes) +- ++ privateKey := make([]byte, (key.Curve.Params().N.BitLen()+7)/8) + return asn1.Marshal(ecPrivateKey{ + Version: 1, +- PrivateKey: paddedPrivateKey, ++ PrivateKey: key.D.FillBytes(privateKey), + NamedCurveOID: oid, + PublicKey: asn1.BitString{Bytes: elliptic.Marshal(key.Curve, key.X, key.Y)}, + }) +diff --git a/src/math/big/int.go b/src/math/big/int.go +index 8816cf5266cc4..65f32487b58c0 100644 +--- a/src/math/big/int.go ++++ b/src/math/big/int.go +@@ -447,11 +447,26 @@ func (z *Int) SetBytes(buf []byte) *Int { + } + + // Bytes returns the absolute value of x as a big-endian byte slice. ++// ++// To use a fixed length slice, or a preallocated one, use FillBytes. + func (x *Int) Bytes() []byte { + buf := make([]byte, len(x.abs)*_S) + return buf[x.abs.bytes(buf):] + } + ++// FillBytes sets buf to the absolute value of x, storing it as a zero-extended ++// big-endian byte slice, and returns buf. ++// ++// If the absolute value of x doesn't fit in buf, FillBytes will panic. ++func (x *Int) FillBytes(buf []byte) []byte { ++ // Clear whole buffer. (This gets optimized into a memclr.) ++ for i := range buf { ++ buf[i] = 0 ++ } ++ x.abs.bytes(buf) ++ return buf ++} ++ + // BitLen returns the length of the absolute value of x in bits. + // The bit length of 0 is 0. + func (x *Int) BitLen() int { +diff --git a/src/math/big/int_test.go b/src/math/big/int_test.go +index e3a1587b3f0ad..3c8557323a032 100644 +--- a/src/math/big/int_test.go ++++ b/src/math/big/int_test.go +@@ -1840,3 +1840,57 @@ func BenchmarkDiv(b *testing.B) { + }) + } + } ++ ++func TestFillBytes(t *testing.T) { ++ checkResult := func(t *testing.T, buf []byte, want *Int) { ++ t.Helper() ++ got := new(Int).SetBytes(buf) ++ if got.CmpAbs(want) != 0 { ++ t.Errorf("got 0x%x, want 0x%x: %x", got, want, buf) ++ } ++ } ++ panics := func(f func()) (panic bool) { ++ defer func() { panic = recover() != nil }() ++ f() ++ return ++ } ++ ++ for _, n := range []string{ ++ "0", ++ "1000", ++ "0xffffffff", ++ "-0xffffffff", ++ "0xffffffffffffffff", ++ "0x10000000000000000", ++ "0xabababababababababababababababababababababababababa", ++ "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", ++ } { ++ t.Run(n, func(t *testing.T) { ++ t.Logf(n) ++ x, ok := new(Int).SetString(n, 0) ++ if !ok { ++ panic("invalid test entry") ++ } ++ ++ // Perfectly sized buffer. ++ byteLen := (x.BitLen() + 7) / 8 ++ buf := make([]byte, byteLen) ++ checkResult(t, x.FillBytes(buf), x) ++ ++ // Way larger, checking all bytes get zeroed. ++ buf = make([]byte, 100) ++ for i := range buf { ++ buf[i] = 0xff ++ } ++ checkResult(t, x.FillBytes(buf), x) ++ ++ // Too small. ++ if byteLen > 0 { ++ buf = make([]byte, byteLen-1) ++ if !panics(func() { x.FillBytes(buf) }) { ++ t.Errorf("expected panic for small buffer and value %x", x) ++ } ++ } ++ }) ++ } ++} +diff --git a/src/math/big/nat.go b/src/math/big/nat.go +index c31ec5156b81d..6a3989bf9d82b 100644 +--- a/src/math/big/nat.go ++++ b/src/math/big/nat.go +@@ -1476,19 +1476,26 @@ func (z nat) expNNMontgomery(x, y, m nat) nat { + } + + // bytes writes the value of z into buf using big-endian encoding. +-// len(buf) must be >= len(z)*_S. The value of z is encoded in the +-// slice buf[i:]. The number i of unused bytes at the beginning of +-// buf is returned as result. ++// The value of z is encoded in the slice buf[i:]. If the value of z ++// cannot be represented in buf, bytes panics. The number i of unused ++// bytes at the beginning of buf is returned as result. + func (z nat) bytes(buf []byte) (i int) { + i = len(buf) + for _, d := range z { + for j := 0; j < _S; j++ { + i-- +- buf[i] = byte(d) ++ if i >= 0 { ++ buf[i] = byte(d) ++ } else if byte(d) != 0 { ++ panic("math/big: buffer too small to fit value") ++ } + d >>= 8 + } + } + ++ if i < 0 { ++ i = 0 ++ } + for i < len(buf) && buf[i] == 0 { + i++ + } diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-45287-pre3.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-45287-pre3.patch new file mode 100644 index 0000000000..ae9fcc170c --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-45287-pre3.patch @@ -0,0 +1,86 @@ +From 8f676144ad7b7c91adb0c6e1ec89aaa6283c6807 Mon Sep 17 00:00:00 2001 +From: Himanshu Kishna Srivastava <28himanshu@gmail.com> +Date: Tue, 16 Mar 2021 22:37:46 +0530 +Subject: [PATCH] crypto/rsa: fix salt length calculation with + PSSSaltLengthAuto + +When PSSSaltLength is set, the maximum salt length must equal: + + (modulus_key_size - 1 + 7)/8 - hash_length - 2 +and for example, with a 4096 bit modulus key, and a SHA-1 hash, +it should be: + + (4096 -1 + 7)/8 - 20 - 2 = 490 +Previously we'd encounter this error: + + crypto/rsa: key size too small for PSS signature + +Fixes #42741 + +Change-Id: I18bb82c41c511d564b3f4c443f4b3a38ab010ac5 +Reviewed-on: https://go-review.googlesource.com/c/go/+/302230 +Reviewed-by: Emmanuel Odeke <emmanuel@orijtech.com> +Reviewed-by: Filippo Valsorda <filippo@golang.org> +Trust: Emmanuel Odeke <emmanuel@orijtech.com> +Run-TryBot: Emmanuel Odeke <emmanuel@orijtech.com> +TryBot-Result: Go Bot <gobot@golang.org> + +Upstream-Status: Backport [https://github.com/golang/go/commit/8f676144ad7b7c91adb0c6e1ec89aaa6283c6807] +CVE: CVE-2023-45287 #Dependency Patch3 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + src/crypto/rsa/pss.go | 2 +- + src/crypto/rsa/pss_test.go | 20 +++++++++++++++++++- + 2 files changed, 20 insertions(+), 2 deletions(-) + +diff --git a/src/crypto/rsa/pss.go b/src/crypto/rsa/pss.go +index b2adbedb28fa8..814522de8181f 100644 +--- a/src/crypto/rsa/pss.go ++++ b/src/crypto/rsa/pss.go +@@ -269,7 +269,7 @@ func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, digest []byte, + saltLength := opts.saltLength() + switch saltLength { + case PSSSaltLengthAuto: +- saltLength = priv.Size() - 2 - hash.Size() ++ saltLength = (priv.N.BitLen()-1+7)/8 - 2 - hash.Size() + case PSSSaltLengthEqualsHash: + saltLength = hash.Size() + } +diff --git a/src/crypto/rsa/pss_test.go b/src/crypto/rsa/pss_test.go +index dfa8d8bb5ad02..c3a6d468497cd 100644 +--- a/src/crypto/rsa/pss_test.go ++++ b/src/crypto/rsa/pss_test.go +@@ -12,7 +12,7 @@ import ( + _ "crypto/md5" + "crypto/rand" + "crypto/sha1" +- _ "crypto/sha256" ++ "crypto/sha256" + "encoding/hex" + "math/big" + "os" +@@ -233,6 +233,24 @@ func TestPSSSigning(t *testing.T) { + } + } + ++func TestSignWithPSSSaltLengthAuto(t *testing.T) { ++ key, err := GenerateKey(rand.Reader, 513) ++ if err != nil { ++ t.Fatal(err) ++ } ++ digest := sha256.Sum256([]byte("message")) ++ signature, err := key.Sign(rand.Reader, digest[:], &PSSOptions{ ++ SaltLength: PSSSaltLengthAuto, ++ Hash: crypto.SHA256, ++ }) ++ if err != nil { ++ t.Fatal(err) ++ } ++ if len(signature) == 0 { ++ t.Fatal("empty signature returned") ++ } ++} ++ + func bigFromHex(hex string) *big.Int { + n, ok := new(big.Int).SetString(hex, 16) + if !ok { diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-45287.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-45287.patch new file mode 100644 index 0000000000..90a74255db --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-45287.patch @@ -0,0 +1,1697 @@ +From 8a81fdf165facdcefa06531de5af98a4db343035 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?L=C3=BAc=C3=A1s=20Meier?= <cronokirby@gmail.com> +Date: Tue, 8 Jun 2021 21:36:06 +0200 +Subject: [PATCH] crypto/rsa: replace big.Int for encryption and decryption + +Infamously, big.Int does not provide constant-time arithmetic, making +its use in cryptographic code quite tricky. RSA uses big.Int +pervasively, in its public API, for key generation, precomputation, and +for encryption and decryption. This is a known problem. One mitigation, +blinding, is already in place during decryption. This helps mitigate the +very leaky exponentiation operation. Because big.Int is fundamentally +not constant-time, it's unfortunately difficult to guarantee that +mitigations like these are completely effective. + +This patch removes the use of big.Int for encryption and decryption, +replacing it with an internal nat type instead. Signing and verification +are also affected, because they depend on encryption and decryption. + +Overall, this patch degrades performance by 55% for private key +operations, and 4-5x for (much faster) public key operations. +(Signatures do both, so the slowdown is worse than decryption.) + +name old time/op new time/op delta +DecryptPKCS1v15/2048-8 1.50ms ± 0% 2.34ms ± 0% +56.44% (p=0.000 n=8+10) +DecryptPKCS1v15/3072-8 4.40ms ± 0% 6.79ms ± 0% +54.33% (p=0.000 n=10+9) +DecryptPKCS1v15/4096-8 9.31ms ± 0% 15.14ms ± 0% +62.60% (p=0.000 n=10+10) +EncryptPKCS1v15/2048-8 8.16µs ± 0% 355.58µs ± 0% +4258.90% (p=0.000 n=10+9) +DecryptOAEP/2048-8 1.50ms ± 0% 2.34ms ± 0% +55.68% (p=0.000 n=10+9) +EncryptOAEP/2048-8 8.51µs ± 0% 355.95µs ± 0% +4082.75% (p=0.000 n=10+9) +SignPKCS1v15/2048-8 1.51ms ± 0% 2.69ms ± 0% +77.94% (p=0.000 n=10+10) +VerifyPKCS1v15/2048-8 7.25µs ± 0% 354.34µs ± 0% +4789.52% (p=0.000 n=9+9) +SignPSS/2048-8 1.51ms ± 0% 2.70ms ± 0% +78.80% (p=0.000 n=9+10) +VerifyPSS/2048-8 8.27µs ± 1% 355.65µs ± 0% +4199.39% (p=0.000 n=10+10) + +Keep in mind that this is without any assembly at all, and that further +improvements are likely possible. I think having a review of the logic +and the cryptography would be a good idea at this stage, before we +complicate the code too much through optimization. + +The bulk of the work is in nat.go. This introduces two new types: nat, +representing natural numbers, and modulus, representing moduli used in +modular arithmetic. + +A nat has an "announced size", which may be larger than its "true size", +the number of bits needed to represent this number. Operations on a nat +will only ever leak its announced size, never its true size, or other +information about its value. The size of a nat is always clear based on +how its value is set. For example, x.mod(y, m) will make the announced +size of x match that of m, since x is reduced modulo m. + +Operations assume that the announced size of the operands match what's +expected (with a few exceptions). For example, x.modAdd(y, m) assumes +that x and y have the same announced size as m, and that they're reduced +modulo m. + +Nats are represented over unsatured bits.UintSize - 1 bit limbs. This +means that we can't reuse the assembly routines for big.Int, which use +saturated bits.UintSize limbs. The advantage of unsaturated limbs is +that it makes Montgomery multiplication faster, by needing fewer +registers in a hot loop. This makes exponentiation faster, which +consists of many Montgomery multiplications. + +Moduli use nat internally. Unlike nat, the true size of a modulus always +matches its announced size. When creating a modulus, any zero padding is +removed. Moduli will also precompute constants when created, which is +another reason why having a separate type is desirable. + +Updates #20654 + +Co-authored-by: Filippo Valsorda <filippo@golang.org> +Change-Id: I73b61f87d58ab912e80a9644e255d552cbadcced +Reviewed-on: https://go-review.googlesource.com/c/go/+/326012 +Run-TryBot: Filippo Valsorda <filippo@golang.org> +TryBot-Result: Gopher Robot <gobot@golang.org> +Reviewed-by: Roland Shoemaker <roland@golang.org> +Reviewed-by: Joedian Reid <joedian@golang.org> + +Upstream-Status: Backport [https://github.com/golang/go/commit/8a81fdf165facdcefa06531de5af98a4db343035] +CVE: CVE-2023-45287 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + src/crypto/rsa/example_test.go | 21 +- + src/crypto/rsa/nat.go | 626 +++++++++++++++++++++++++++++++++ + src/crypto/rsa/nat_test.go | 384 ++++++++++++++++++++ + src/crypto/rsa/pkcs1v15.go | 47 +-- + src/crypto/rsa/pss.go | 50 ++- + src/crypto/rsa/pss_test.go | 10 +- + src/crypto/rsa/rsa.go | 174 ++++----- + 7 files changed, 1143 insertions(+), 169 deletions(-) + create mode 100644 src/crypto/rsa/nat.go + create mode 100644 src/crypto/rsa/nat_test.go + +diff --git a/src/crypto/rsa/example_test.go b/src/crypto/rsa/example_test.go +index 1435b70..1963609 100644 +--- a/src/crypto/rsa/example_test.go ++++ b/src/crypto/rsa/example_test.go +@@ -12,7 +12,6 @@ import ( + "crypto/sha256" + "encoding/hex" + "fmt" +- "io" + "os" + ) + +@@ -36,21 +35,17 @@ import ( + // a buffer that contains a random key. Thus, if the RSA result isn't + // well-formed, the implementation uses a random key in constant time. + func ExampleDecryptPKCS1v15SessionKey() { +- // crypto/rand.Reader is a good source of entropy for blinding the RSA +- // operation. +- rng := rand.Reader +- + // The hybrid scheme should use at least a 16-byte symmetric key. Here + // we read the random key that will be used if the RSA decryption isn't + // well-formed. + key := make([]byte, 32) +- if _, err := io.ReadFull(rng, key); err != nil { ++ if _, err := rand.Read(key); err != nil { + panic("RNG failure") + } + + rsaCiphertext, _ := hex.DecodeString("aabbccddeeff") + +- if err := DecryptPKCS1v15SessionKey(rng, rsaPrivateKey, rsaCiphertext, key); err != nil { ++ if err := DecryptPKCS1v15SessionKey(nil, rsaPrivateKey, rsaCiphertext, key); err != nil { + // Any errors that result will be “public” – meaning that they + // can be determined without any secret information. (For + // instance, if the length of key is impossible given the RSA +@@ -86,10 +81,6 @@ func ExampleDecryptPKCS1v15SessionKey() { + } + + func ExampleSignPKCS1v15() { +- // crypto/rand.Reader is a good source of entropy for blinding the RSA +- // operation. +- rng := rand.Reader +- + message := []byte("message to be signed") + + // Only small messages can be signed directly; thus the hash of a +@@ -99,7 +90,7 @@ func ExampleSignPKCS1v15() { + // of writing (2016). + hashed := sha256.Sum256(message) + +- signature, err := SignPKCS1v15(rng, rsaPrivateKey, crypto.SHA256, hashed[:]) ++ signature, err := SignPKCS1v15(nil, rsaPrivateKey, crypto.SHA256, hashed[:]) + if err != nil { + fmt.Fprintf(os.Stderr, "Error from signing: %s\n", err) + return +@@ -151,11 +142,7 @@ func ExampleDecryptOAEP() { + ciphertext, _ := hex.DecodeString("4d1ee10e8f286390258c51a5e80802844c3e6358ad6690b7285218a7c7ed7fc3a4c7b950fbd04d4b0239cc060dcc7065ca6f84c1756deb71ca5685cadbb82be025e16449b905c568a19c088a1abfad54bf7ecc67a7df39943ec511091a34c0f2348d04e058fcff4d55644de3cd1d580791d4524b92f3e91695582e6e340a1c50b6c6d78e80b4e42c5b4d45e479b492de42bbd39cc642ebb80226bb5200020d501b24a37bcc2ec7f34e596b4fd6b063de4858dbf5a4e3dd18e262eda0ec2d19dbd8e890d672b63d368768360b20c0b6b8592a438fa275e5fa7f60bef0dd39673fd3989cc54d2cb80c08fcd19dacbc265ee1c6014616b0e04ea0328c2a04e73460") + label := []byte("orders") + +- // crypto/rand.Reader is a good source of entropy for blinding the RSA +- // operation. +- rng := rand.Reader +- +- plaintext, err := DecryptOAEP(sha256.New(), rng, test2048Key, ciphertext, label) ++ plaintext, err := DecryptOAEP(sha256.New(), nil, test2048Key, ciphertext, label) + if err != nil { + fmt.Fprintf(os.Stderr, "Error from decryption: %s\n", err) + return +diff --git a/src/crypto/rsa/nat.go b/src/crypto/rsa/nat.go +new file mode 100644 +index 0000000..da521c2 +--- /dev/null ++++ b/src/crypto/rsa/nat.go +@@ -0,0 +1,626 @@ ++// Copyright 2021 The Go Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style ++// license that can be found in the LICENSE file. ++ ++package rsa ++ ++import ( ++ "math/big" ++ "math/bits" ++) ++ ++const ( ++ // _W is the number of bits we use for our limbs. ++ _W = bits.UintSize - 1 ++ // _MASK selects _W bits from a full machine word. ++ _MASK = (1 << _W) - 1 ++) ++ ++// choice represents a constant-time boolean. The value of choice is always ++// either 1 or 0. We use an int instead of bool in order to make decisions in ++// constant time by turning it into a mask. ++type choice uint ++ ++func not(c choice) choice { return 1 ^ c } ++ ++const yes = choice(1) ++const no = choice(0) ++ ++// ctSelect returns x if on == 1, and y if on == 0. The execution time of this ++// function does not depend on its inputs. If on is any value besides 1 or 0, ++// the result is undefined. ++func ctSelect(on choice, x, y uint) uint { ++ // When on == 1, mask is 0b111..., otherwise mask is 0b000... ++ mask := -uint(on) ++ // When mask is all zeros, we just have y, otherwise, y cancels with itself. ++ return y ^ (mask & (y ^ x)) ++} ++ ++// ctEq returns 1 if x == y, and 0 otherwise. The execution time of this ++// function does not depend on its inputs. ++func ctEq(x, y uint) choice { ++ // If x != y, then either x - y or y - x will generate a carry. ++ _, c1 := bits.Sub(x, y, 0) ++ _, c2 := bits.Sub(y, x, 0) ++ return not(choice(c1 | c2)) ++} ++ ++// ctGeq returns 1 if x >= y, and 0 otherwise. The execution time of this ++// function does not depend on its inputs. ++func ctGeq(x, y uint) choice { ++ // If x < y, then x - y generates a carry. ++ _, carry := bits.Sub(x, y, 0) ++ return not(choice(carry)) ++} ++ ++// nat represents an arbitrary natural number ++// ++// Each nat has an announced length, which is the number of limbs it has stored. ++// Operations on this number are allowed to leak this length, but will not leak ++// any information about the values contained in those limbs. ++type nat struct { ++ // limbs is a little-endian representation in base 2^W with ++ // W = bits.UintSize - 1. The top bit is always unset between operations. ++ // ++ // The top bit is left unset to optimize Montgomery multiplication, in the ++ // inner loop of exponentiation. Using fully saturated limbs would leave us ++ // working with 129-bit numbers on 64-bit platforms, wasting a lot of space, ++ // and thus time. ++ limbs []uint ++} ++ ++// expand expands x to n limbs, leaving its value unchanged. ++func (x *nat) expand(n int) *nat { ++ for len(x.limbs) > n { ++ if x.limbs[len(x.limbs)-1] != 0 { ++ panic("rsa: internal error: shrinking nat") ++ } ++ x.limbs = x.limbs[:len(x.limbs)-1] ++ } ++ if cap(x.limbs) < n { ++ newLimbs := make([]uint, n) ++ copy(newLimbs, x.limbs) ++ x.limbs = newLimbs ++ return x ++ } ++ extraLimbs := x.limbs[len(x.limbs):n] ++ for i := range extraLimbs { ++ extraLimbs[i] = 0 ++ } ++ x.limbs = x.limbs[:n] ++ return x ++} ++ ++// reset returns a zero nat of n limbs, reusing x's storage if n <= cap(x.limbs). ++func (x *nat) reset(n int) *nat { ++ if cap(x.limbs) < n { ++ x.limbs = make([]uint, n) ++ return x ++ } ++ for i := range x.limbs { ++ x.limbs[i] = 0 ++ } ++ x.limbs = x.limbs[:n] ++ return x ++} ++ ++// clone returns a new nat, with the same value and announced length as x. ++func (x *nat) clone() *nat { ++ out := &nat{make([]uint, len(x.limbs))} ++ copy(out.limbs, x.limbs) ++ return out ++} ++ ++// natFromBig creates a new natural number from a big.Int. ++// ++// The announced length of the resulting nat is based on the actual bit size of ++// the input, ignoring leading zeroes. ++func natFromBig(x *big.Int) *nat { ++ xLimbs := x.Bits() ++ bitSize := bigBitLen(x) ++ requiredLimbs := (bitSize + _W - 1) / _W ++ ++ out := &nat{make([]uint, requiredLimbs)} ++ outI := 0 ++ shift := 0 ++ for i := range xLimbs { ++ xi := uint(xLimbs[i]) ++ out.limbs[outI] |= (xi << shift) & _MASK ++ outI++ ++ if outI == requiredLimbs { ++ return out ++ } ++ out.limbs[outI] = xi >> (_W - shift) ++ shift++ // this assumes bits.UintSize - _W = 1 ++ if shift == _W { ++ shift = 0 ++ outI++ ++ } ++ } ++ return out ++} ++ ++// fillBytes sets bytes to x as a zero-extended big-endian byte slice. ++// ++// If bytes is not long enough to contain the number or at least len(x.limbs)-1 ++// limbs, or has zero length, fillBytes will panic. ++func (x *nat) fillBytes(bytes []byte) []byte { ++ if len(bytes) == 0 { ++ panic("nat: fillBytes invoked with too small buffer") ++ } ++ for i := range bytes { ++ bytes[i] = 0 ++ } ++ shift := 0 ++ outI := len(bytes) - 1 ++ for i, limb := range x.limbs { ++ remainingBits := _W ++ for remainingBits >= 8 { ++ bytes[outI] |= byte(limb) << shift ++ consumed := 8 - shift ++ limb >>= consumed ++ remainingBits -= consumed ++ shift = 0 ++ outI-- ++ if outI < 0 { ++ if limb != 0 || i < len(x.limbs)-1 { ++ panic("nat: fillBytes invoked with too small buffer") ++ } ++ return bytes ++ } ++ } ++ bytes[outI] = byte(limb) ++ shift = remainingBits ++ } ++ return bytes ++} ++ ++// natFromBytes converts a slice of big-endian bytes into a nat. ++// ++// The announced length of the output depends on the length of bytes. Unlike ++// big.Int, creating a nat will not remove leading zeros. ++func natFromBytes(bytes []byte) *nat { ++ bitSize := len(bytes) * 8 ++ requiredLimbs := (bitSize + _W - 1) / _W ++ ++ out := &nat{make([]uint, requiredLimbs)} ++ outI := 0 ++ shift := 0 ++ for i := len(bytes) - 1; i >= 0; i-- { ++ bi := bytes[i] ++ out.limbs[outI] |= uint(bi) << shift ++ shift += 8 ++ if shift >= _W { ++ shift -= _W ++ out.limbs[outI] &= _MASK ++ outI++ ++ if shift > 0 { ++ out.limbs[outI] = uint(bi) >> (8 - shift) ++ } ++ } ++ } ++ return out ++} ++ ++// cmpEq returns 1 if x == y, and 0 otherwise. ++// ++// Both operands must have the same announced length. ++func (x *nat) cmpEq(y *nat) choice { ++ // Eliminate bounds checks in the loop. ++ size := len(x.limbs) ++ xLimbs := x.limbs[:size] ++ yLimbs := y.limbs[:size] ++ ++ equal := yes ++ for i := 0; i < size; i++ { ++ equal &= ctEq(xLimbs[i], yLimbs[i]) ++ } ++ return equal ++} ++ ++// cmpGeq returns 1 if x >= y, and 0 otherwise. ++// ++// Both operands must have the same announced length. ++func (x *nat) cmpGeq(y *nat) choice { ++ // Eliminate bounds checks in the loop. ++ size := len(x.limbs) ++ xLimbs := x.limbs[:size] ++ yLimbs := y.limbs[:size] ++ ++ var c uint ++ for i := 0; i < size; i++ { ++ c = (xLimbs[i] - yLimbs[i] - c) >> _W ++ } ++ // If there was a carry, then subtracting y underflowed, so ++ // x is not greater than or equal to y. ++ return not(choice(c)) ++} ++ ++// assign sets x <- y if on == 1, and does nothing otherwise. ++// ++// Both operands must have the same announced length. ++func (x *nat) assign(on choice, y *nat) *nat { ++ // Eliminate bounds checks in the loop. ++ size := len(x.limbs) ++ xLimbs := x.limbs[:size] ++ yLimbs := y.limbs[:size] ++ ++ for i := 0; i < size; i++ { ++ xLimbs[i] = ctSelect(on, yLimbs[i], xLimbs[i]) ++ } ++ return x ++} ++ ++// add computes x += y if on == 1, and does nothing otherwise. It returns the ++// carry of the addition regardless of on. ++// ++// Both operands must have the same announced length. ++func (x *nat) add(on choice, y *nat) (c uint) { ++ // Eliminate bounds checks in the loop. ++ size := len(x.limbs) ++ xLimbs := x.limbs[:size] ++ yLimbs := y.limbs[:size] ++ ++ for i := 0; i < size; i++ { ++ res := xLimbs[i] + yLimbs[i] + c ++ xLimbs[i] = ctSelect(on, res&_MASK, xLimbs[i]) ++ c = res >> _W ++ } ++ return ++} ++ ++// sub computes x -= y if on == 1, and does nothing otherwise. It returns the ++// borrow of the subtraction regardless of on. ++// ++// Both operands must have the same announced length. ++func (x *nat) sub(on choice, y *nat) (c uint) { ++ // Eliminate bounds checks in the loop. ++ size := len(x.limbs) ++ xLimbs := x.limbs[:size] ++ yLimbs := y.limbs[:size] ++ ++ for i := 0; i < size; i++ { ++ res := xLimbs[i] - yLimbs[i] - c ++ xLimbs[i] = ctSelect(on, res&_MASK, xLimbs[i]) ++ c = res >> _W ++ } ++ return ++} ++ ++// modulus is used for modular arithmetic, precomputing relevant constants. ++// ++// Moduli are assumed to be odd numbers. Moduli can also leak the exact ++// number of bits needed to store their value, and are stored without padding. ++// ++// Their actual value is still kept secret. ++type modulus struct { ++ // The underlying natural number for this modulus. ++ // ++ // This will be stored without any padding, and shouldn't alias with any ++ // other natural number being used. ++ nat *nat ++ leading int // number of leading zeros in the modulus ++ m0inv uint // -nat.limbs[0]⁻¹ mod _W ++} ++ ++// minusInverseModW computes -x⁻¹ mod _W with x odd. ++// ++// This operation is used to precompute a constant involved in Montgomery ++// multiplication. ++func minusInverseModW(x uint) uint { ++ // Every iteration of this loop doubles the least-significant bits of ++ // correct inverse in y. The first three bits are already correct (1⁻¹ = 1, ++ // 3⁻¹ = 3, 5⁻¹ = 5, and 7⁻¹ = 7 mod 8), so doubling five times is enough ++ // for 61 bits (and wastes only one iteration for 31 bits). ++ // ++ // See https://crypto.stackexchange.com/a/47496. ++ y := x ++ for i := 0; i < 5; i++ { ++ y = y * (2 - x*y) ++ } ++ return (1 << _W) - (y & _MASK) ++} ++ ++// modulusFromNat creates a new modulus from a nat. ++// ++// The nat should be odd, nonzero, and the number of significant bits in the ++// number should be leakable. The nat shouldn't be reused. ++func modulusFromNat(nat *nat) *modulus { ++ m := &modulus{} ++ m.nat = nat ++ size := len(m.nat.limbs) ++ for m.nat.limbs[size-1] == 0 { ++ size-- ++ } ++ m.nat.limbs = m.nat.limbs[:size] ++ m.leading = _W - bitLen(m.nat.limbs[size-1]) ++ m.m0inv = minusInverseModW(m.nat.limbs[0]) ++ return m ++} ++ ++// bitLen is a version of bits.Len that only leaks the bit length of n, but not ++// its value. bits.Len and bits.LeadingZeros use a lookup table for the ++// low-order bits on some architectures. ++func bitLen(n uint) int { ++ var len int ++ // We assume, here and elsewhere, that comparison to zero is constant time ++ // with respect to different non-zero values. ++ for n != 0 { ++ len++ ++ n >>= 1 ++ } ++ return len ++} ++ ++// bigBitLen is a version of big.Int.BitLen that only leaks the bit length of x, ++// but not its value. big.Int.BitLen uses bits.Len. ++func bigBitLen(x *big.Int) int { ++ xLimbs := x.Bits() ++ fullLimbs := len(xLimbs) - 1 ++ topLimb := uint(xLimbs[len(xLimbs)-1]) ++ return fullLimbs*bits.UintSize + bitLen(topLimb) ++} ++ ++// modulusSize returns the size of m in bytes. ++func modulusSize(m *modulus) int { ++ bits := len(m.nat.limbs)*_W - int(m.leading) ++ return (bits + 7) / 8 ++} ++ ++// shiftIn calculates x = x << _W + y mod m. ++// ++// This assumes that x is already reduced mod m, and that y < 2^_W. ++func (x *nat) shiftIn(y uint, m *modulus) *nat { ++ d := new(nat).resetFor(m) ++ ++ // Eliminate bounds checks in the loop. ++ size := len(m.nat.limbs) ++ xLimbs := x.limbs[:size] ++ dLimbs := d.limbs[:size] ++ mLimbs := m.nat.limbs[:size] ++ ++ // Each iteration of this loop computes x = 2x + b mod m, where b is a bit ++ // from y. Effectively, it left-shifts x and adds y one bit at a time, ++ // reducing it every time. ++ // ++ // To do the reduction, each iteration computes both 2x + b and 2x + b - m. ++ // The next iteration (and finally the return line) will use either result ++ // based on whether the subtraction underflowed. ++ needSubtraction := no ++ for i := _W - 1; i >= 0; i-- { ++ carry := (y >> i) & 1 ++ var borrow uint ++ for i := 0; i < size; i++ { ++ l := ctSelect(needSubtraction, dLimbs[i], xLimbs[i]) ++ ++ res := l<<1 + carry ++ xLimbs[i] = res & _MASK ++ carry = res >> _W ++ ++ res = xLimbs[i] - mLimbs[i] - borrow ++ dLimbs[i] = res & _MASK ++ borrow = res >> _W ++ } ++ // See modAdd for how carry (aka overflow), borrow (aka underflow), and ++ // needSubtraction relate. ++ needSubtraction = ctEq(carry, borrow) ++ } ++ return x.assign(needSubtraction, d) ++} ++ ++// mod calculates out = x mod m. ++// ++// This works regardless how large the value of x is. ++// ++// The output will be resized to the size of m and overwritten. ++func (out *nat) mod(x *nat, m *modulus) *nat { ++ out.resetFor(m) ++ // Working our way from the most significant to the least significant limb, ++ // we can insert each limb at the least significant position, shifting all ++ // previous limbs left by _W. This way each limb will get shifted by the ++ // correct number of bits. We can insert at least N - 1 limbs without ++ // overflowing m. After that, we need to reduce every time we shift. ++ i := len(x.limbs) - 1 ++ // For the first N - 1 limbs we can skip the actual shifting and position ++ // them at the shifted position, which starts at min(N - 2, i). ++ start := len(m.nat.limbs) - 2 ++ if i < start { ++ start = i ++ } ++ for j := start; j >= 0; j-- { ++ out.limbs[j] = x.limbs[i] ++ i-- ++ } ++ // We shift in the remaining limbs, reducing modulo m each time. ++ for i >= 0 { ++ out.shiftIn(x.limbs[i], m) ++ i-- ++ } ++ return out ++} ++ ++// expandFor ensures out has the right size to work with operations modulo m. ++// ++// This assumes that out has as many or fewer limbs than m, or that the extra ++// limbs are all zero (which may happen when decoding a value that has leading ++// zeroes in its bytes representation that spill over the limb threshold). ++func (out *nat) expandFor(m *modulus) *nat { ++ return out.expand(len(m.nat.limbs)) ++} ++ ++// resetFor ensures out has the right size to work with operations modulo m. ++// ++// out is zeroed and may start at any size. ++func (out *nat) resetFor(m *modulus) *nat { ++ return out.reset(len(m.nat.limbs)) ++} ++ ++// modSub computes x = x - y mod m. ++// ++// The length of both operands must be the same as the modulus. Both operands ++// must already be reduced modulo m. ++func (x *nat) modSub(y *nat, m *modulus) *nat { ++ underflow := x.sub(yes, y) ++ // If the subtraction underflowed, add m. ++ x.add(choice(underflow), m.nat) ++ return x ++} ++ ++// modAdd computes x = x + y mod m. ++// ++// The length of both operands must be the same as the modulus. Both operands ++// must already be reduced modulo m. ++func (x *nat) modAdd(y *nat, m *modulus) *nat { ++ overflow := x.add(yes, y) ++ underflow := not(x.cmpGeq(m.nat)) // x < m ++ ++ // Three cases are possible: ++ // ++ // - overflow = 0, underflow = 0 ++ // ++ // In this case, addition fits in our limbs, but we can still subtract away ++ // m without an underflow, so we need to perform the subtraction to reduce ++ // our result. ++ // ++ // - overflow = 0, underflow = 1 ++ // ++ // The addition fits in our limbs, but we can't subtract m without ++ // underflowing. The result is already reduced. ++ // ++ // - overflow = 1, underflow = 1 ++ // ++ // The addition does not fit in our limbs, and the subtraction's borrow ++ // would cancel out with the addition's carry. We need to subtract m to ++ // reduce our result. ++ // ++ // The overflow = 1, underflow = 0 case is not possible, because y is at ++ // most m - 1, and if adding m - 1 overflows, then subtracting m must ++ // necessarily underflow. ++ needSubtraction := ctEq(overflow, uint(underflow)) ++ ++ x.sub(needSubtraction, m.nat) ++ return x ++} ++ ++// montgomeryRepresentation calculates x = x * R mod m, with R = 2^(_W * n) and ++// n = len(m.nat.limbs). ++// ++// Faster Montgomery multiplication replaces standard modular multiplication for ++// numbers in this representation. ++// ++// This assumes that x is already reduced mod m. ++func (x *nat) montgomeryRepresentation(m *modulus) *nat { ++ for i := 0; i < len(m.nat.limbs); i++ { ++ x.shiftIn(0, m) // x = x * 2^_W mod m ++ } ++ return x ++} ++ ++// montgomeryMul calculates d = a * b / R mod m, with R = 2^(_W * n) and ++// n = len(m.nat.limbs), using the Montgomery Multiplication technique. ++// ++// All inputs should be the same length, not aliasing d, and already ++// reduced modulo m. d will be resized to the size of m and overwritten. ++func (d *nat) montgomeryMul(a *nat, b *nat, m *modulus) *nat { ++ // See https://bearssl.org/bigint.html#montgomery-reduction-and-multiplication ++ // for a description of the algorithm. ++ ++ // Eliminate bounds checks in the loop. ++ size := len(m.nat.limbs) ++ aLimbs := a.limbs[:size] ++ bLimbs := b.limbs[:size] ++ dLimbs := d.resetFor(m).limbs[:size] ++ mLimbs := m.nat.limbs[:size] ++ ++ var overflow uint ++ for i := 0; i < size; i++ { ++ f := ((dLimbs[0] + aLimbs[i]*bLimbs[0]) * m.m0inv) & _MASK ++ carry := uint(0) ++ for j := 0; j < size; j++ { ++ // z = d[j] + a[i] * b[j] + f * m[j] + carry <= 2^(2W+1) - 2^(W+1) + 2^W ++ hi, lo := bits.Mul(aLimbs[i], bLimbs[j]) ++ z_lo, c := bits.Add(dLimbs[j], lo, 0) ++ z_hi, _ := bits.Add(0, hi, c) ++ hi, lo = bits.Mul(f, mLimbs[j]) ++ z_lo, c = bits.Add(z_lo, lo, 0) ++ z_hi, _ = bits.Add(z_hi, hi, c) ++ z_lo, c = bits.Add(z_lo, carry, 0) ++ z_hi, _ = bits.Add(z_hi, 0, c) ++ if j > 0 { ++ dLimbs[j-1] = z_lo & _MASK ++ } ++ carry = z_hi<<1 | z_lo>>_W // carry <= 2^(W+1) - 2 ++ } ++ z := overflow + carry // z <= 2^(W+1) - 1 ++ dLimbs[size-1] = z & _MASK ++ overflow = z >> _W // overflow <= 1 ++ } ++ // See modAdd for how overflow, underflow, and needSubtraction relate. ++ underflow := not(d.cmpGeq(m.nat)) // d < m ++ needSubtraction := ctEq(overflow, uint(underflow)) ++ d.sub(needSubtraction, m.nat) ++ ++ return d ++} ++ ++// modMul calculates x *= y mod m. ++// ++// x and y must already be reduced modulo m, they must share its announced ++// length, and they may not alias. ++func (x *nat) modMul(y *nat, m *modulus) *nat { ++ // A Montgomery multiplication by a value out of the Montgomery domain ++ // takes the result out of Montgomery representation. ++ xR := x.clone().montgomeryRepresentation(m) // xR = x * R mod m ++ return x.montgomeryMul(xR, y, m) // x = xR * y / R mod m ++} ++ ++// exp calculates out = x^e mod m. ++// ++// The exponent e is represented in big-endian order. The output will be resized ++// to the size of m and overwritten. x must already be reduced modulo m. ++func (out *nat) exp(x *nat, e []byte, m *modulus) *nat { ++ // We use a 4 bit window. For our RSA workload, 4 bit windows are faster ++ // than 2 bit windows, but use an extra 12 nats worth of scratch space. ++ // Using bit sizes that don't divide 8 are more complex to implement. ++ table := make([]*nat, (1<<4)-1) // table[i] = x ^ (i+1) ++ table[0] = x.clone().montgomeryRepresentation(m) ++ for i := 1; i < len(table); i++ { ++ table[i] = new(nat).expandFor(m) ++ table[i].montgomeryMul(table[i-1], table[0], m) ++ } ++ ++ out.resetFor(m) ++ out.limbs[0] = 1 ++ out.montgomeryRepresentation(m) ++ t0 := new(nat).expandFor(m) ++ t1 := new(nat).expandFor(m) ++ for _, b := range e { ++ for _, j := range []int{4, 0} { ++ // Square four times. ++ t1.montgomeryMul(out, out, m) ++ out.montgomeryMul(t1, t1, m) ++ t1.montgomeryMul(out, out, m) ++ out.montgomeryMul(t1, t1, m) ++ ++ // Select x^k in constant time from the table. ++ k := uint((b >> j) & 0b1111) ++ for i := range table { ++ t0.assign(ctEq(k, uint(i+1)), table[i]) ++ } ++ ++ // Multiply by x^k, discarding the result if k = 0. ++ t1.montgomeryMul(out, t0, m) ++ out.assign(not(ctEq(k, 0)), t1) ++ } ++ } ++ ++ // By Montgomery multiplying with 1 not in Montgomery representation, we ++ // convert out back from Montgomery representation, because it works out to ++ // dividing by R. ++ t0.assign(yes, out) ++ t1.resetFor(m) ++ t1.limbs[0] = 1 ++ out.montgomeryMul(t0, t1, m) ++ ++ return out ++} +diff --git a/src/crypto/rsa/nat_test.go b/src/crypto/rsa/nat_test.go +new file mode 100644 +index 0000000..3e6eb10 +--- /dev/null ++++ b/src/crypto/rsa/nat_test.go +@@ -0,0 +1,384 @@ ++// Copyright 2021 The Go Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style ++// license that can be found in the LICENSE file. ++ ++package rsa ++ ++import ( ++ "bytes" ++ "math/big" ++ "math/bits" ++ "math/rand" ++ "reflect" ++ "testing" ++ "testing/quick" ++) ++ ++// Generate generates an even nat. It's used by testing/quick to produce random ++// *nat values for quick.Check invocations. ++func (*nat) Generate(r *rand.Rand, size int) reflect.Value { ++ limbs := make([]uint, size) ++ for i := 0; i < size; i++ { ++ limbs[i] = uint(r.Uint64()) & ((1 << _W) - 2) ++ } ++ return reflect.ValueOf(&nat{limbs}) ++} ++ ++func testModAddCommutative(a *nat, b *nat) bool { ++ mLimbs := make([]uint, len(a.limbs)) ++ for i := 0; i < len(mLimbs); i++ { ++ mLimbs[i] = _MASK ++ } ++ m := modulusFromNat(&nat{mLimbs}) ++ aPlusB := a.clone() ++ aPlusB.modAdd(b, m) ++ bPlusA := b.clone() ++ bPlusA.modAdd(a, m) ++ return aPlusB.cmpEq(bPlusA) == 1 ++} ++ ++func TestModAddCommutative(t *testing.T) { ++ err := quick.Check(testModAddCommutative, &quick.Config{}) ++ if err != nil { ++ t.Error(err) ++ } ++} ++ ++func testModSubThenAddIdentity(a *nat, b *nat) bool { ++ mLimbs := make([]uint, len(a.limbs)) ++ for i := 0; i < len(mLimbs); i++ { ++ mLimbs[i] = _MASK ++ } ++ m := modulusFromNat(&nat{mLimbs}) ++ original := a.clone() ++ a.modSub(b, m) ++ a.modAdd(b, m) ++ return a.cmpEq(original) == 1 ++} ++ ++func TestModSubThenAddIdentity(t *testing.T) { ++ err := quick.Check(testModSubThenAddIdentity, &quick.Config{}) ++ if err != nil { ++ t.Error(err) ++ } ++} ++ ++func testMontgomeryRoundtrip(a *nat) bool { ++ one := &nat{make([]uint, len(a.limbs))} ++ one.limbs[0] = 1 ++ aPlusOne := a.clone() ++ aPlusOne.add(1, one) ++ m := modulusFromNat(aPlusOne) ++ monty := a.clone() ++ monty.montgomeryRepresentation(m) ++ aAgain := monty.clone() ++ aAgain.montgomeryMul(monty, one, m) ++ return a.cmpEq(aAgain) == 1 ++} ++ ++func TestMontgomeryRoundtrip(t *testing.T) { ++ err := quick.Check(testMontgomeryRoundtrip, &quick.Config{}) ++ if err != nil { ++ t.Error(err) ++ } ++} ++ ++func TestFromBig(t *testing.T) { ++ expected := []byte{0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} ++ theBig := new(big.Int).SetBytes(expected) ++ actual := natFromBig(theBig).fillBytes(make([]byte, len(expected))) ++ if !bytes.Equal(actual, expected) { ++ t.Errorf("%+x != %+x", actual, expected) ++ } ++} ++ ++func TestFillBytes(t *testing.T) { ++ xBytes := []byte{0xAA, 0xFF, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88} ++ x := natFromBytes(xBytes) ++ for l := 20; l >= len(xBytes); l-- { ++ buf := make([]byte, l) ++ rand.Read(buf) ++ actual := x.fillBytes(buf) ++ expected := make([]byte, l) ++ copy(expected[l-len(xBytes):], xBytes) ++ if !bytes.Equal(actual, expected) { ++ t.Errorf("%d: %+v != %+v", l, actual, expected) ++ } ++ } ++ for l := len(xBytes) - 1; l >= 0; l-- { ++ (func() { ++ defer func() { ++ if recover() == nil { ++ t.Errorf("%d: expected panic", l) ++ } ++ }() ++ x.fillBytes(make([]byte, l)) ++ })() ++ } ++} ++ ++func TestFromBytes(t *testing.T) { ++ f := func(xBytes []byte) bool { ++ if len(xBytes) == 0 { ++ return true ++ } ++ actual := natFromBytes(xBytes).fillBytes(make([]byte, len(xBytes))) ++ if !bytes.Equal(actual, xBytes) { ++ t.Errorf("%+x != %+x", actual, xBytes) ++ return false ++ } ++ return true ++ } ++ ++ err := quick.Check(f, &quick.Config{}) ++ if err != nil { ++ t.Error(err) ++ } ++ ++ f([]byte{0xFF, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}) ++ f(bytes.Repeat([]byte{0xFF}, _W)) ++} ++ ++func TestShiftIn(t *testing.T) { ++ if bits.UintSize != 64 { ++ t.Skip("examples are only valid in 64 bit") ++ } ++ examples := []struct { ++ m, x, expected []byte ++ y uint64 ++ }{{ ++ m: []byte{13}, ++ x: []byte{0}, ++ y: 0x7FFF_FFFF_FFFF_FFFF, ++ expected: []byte{7}, ++ }, { ++ m: []byte{13}, ++ x: []byte{7}, ++ y: 0x7FFF_FFFF_FFFF_FFFF, ++ expected: []byte{11}, ++ }, { ++ m: []byte{0x06, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d}, ++ x: make([]byte, 9), ++ y: 0x7FFF_FFFF_FFFF_FFFF, ++ expected: []byte{0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, ++ }, { ++ m: []byte{0x06, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d}, ++ x: []byte{0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, ++ y: 0, ++ expected: []byte{0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08}, ++ }} ++ ++ for i, tt := range examples { ++ m := modulusFromNat(natFromBytes(tt.m)) ++ got := natFromBytes(tt.x).expandFor(m).shiftIn(uint(tt.y), m) ++ if got.cmpEq(natFromBytes(tt.expected).expandFor(m)) != 1 { ++ t.Errorf("%d: got %x, expected %x", i, got, tt.expected) ++ } ++ } ++} ++ ++func TestModulusAndNatSizes(t *testing.T) { ++ // These are 126 bit (2 * _W on 64-bit architectures) values, serialized as ++ // 128 bits worth of bytes. If leading zeroes are stripped, they fit in two ++ // limbs, if they are not, they fit in three. This can be a problem because ++ // modulus strips leading zeroes and nat does not. ++ m := modulusFromNat(natFromBytes([]byte{ ++ 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff})) ++ x := natFromBytes([]byte{ ++ 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe}) ++ x.expandFor(m) // must not panic for shrinking ++} ++ ++func TestExpand(t *testing.T) { ++ sliced := []uint{1, 2, 3, 4} ++ examples := []struct { ++ in []uint ++ n int ++ out []uint ++ }{{ ++ []uint{1, 2}, ++ 4, ++ []uint{1, 2, 0, 0}, ++ }, { ++ sliced[:2], ++ 4, ++ []uint{1, 2, 0, 0}, ++ }, { ++ []uint{1, 2}, ++ 2, ++ []uint{1, 2}, ++ }, { ++ []uint{1, 2, 0}, ++ 2, ++ []uint{1, 2}, ++ }} ++ ++ for i, tt := range examples { ++ got := (&nat{tt.in}).expand(tt.n) ++ if len(got.limbs) != len(tt.out) || got.cmpEq(&nat{tt.out}) != 1 { ++ t.Errorf("%d: got %x, expected %x", i, got, tt.out) ++ } ++ } ++} ++ ++func TestMod(t *testing.T) { ++ m := modulusFromNat(natFromBytes([]byte{0x06, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d})) ++ x := natFromBytes([]byte{0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}) ++ out := new(nat) ++ out.mod(x, m) ++ expected := natFromBytes([]byte{0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09}) ++ if out.cmpEq(expected) != 1 { ++ t.Errorf("%+v != %+v", out, expected) ++ } ++} ++ ++func TestModSub(t *testing.T) { ++ m := modulusFromNat(&nat{[]uint{13}}) ++ x := &nat{[]uint{6}} ++ y := &nat{[]uint{7}} ++ x.modSub(y, m) ++ expected := &nat{[]uint{12}} ++ if x.cmpEq(expected) != 1 { ++ t.Errorf("%+v != %+v", x, expected) ++ } ++ x.modSub(y, m) ++ expected = &nat{[]uint{5}} ++ if x.cmpEq(expected) != 1 { ++ t.Errorf("%+v != %+v", x, expected) ++ } ++} ++ ++func TestModAdd(t *testing.T) { ++ m := modulusFromNat(&nat{[]uint{13}}) ++ x := &nat{[]uint{6}} ++ y := &nat{[]uint{7}} ++ x.modAdd(y, m) ++ expected := &nat{[]uint{0}} ++ if x.cmpEq(expected) != 1 { ++ t.Errorf("%+v != %+v", x, expected) ++ } ++ x.modAdd(y, m) ++ expected = &nat{[]uint{7}} ++ if x.cmpEq(expected) != 1 { ++ t.Errorf("%+v != %+v", x, expected) ++ } ++} ++ ++func TestExp(t *testing.T) { ++ m := modulusFromNat(&nat{[]uint{13}}) ++ x := &nat{[]uint{3}} ++ out := &nat{[]uint{0}} ++ out.exp(x, []byte{12}, m) ++ expected := &nat{[]uint{1}} ++ if out.cmpEq(expected) != 1 { ++ t.Errorf("%+v != %+v", out, expected) ++ } ++} ++ ++func makeBenchmarkModulus() *modulus { ++ m := make([]uint, 32) ++ for i := 0; i < 32; i++ { ++ m[i] = _MASK ++ } ++ return modulusFromNat(&nat{limbs: m}) ++} ++ ++func makeBenchmarkValue() *nat { ++ x := make([]uint, 32) ++ for i := 0; i < 32; i++ { ++ x[i] = _MASK - 1 ++ } ++ return &nat{limbs: x} ++} ++ ++func makeBenchmarkExponent() []byte { ++ e := make([]byte, 256) ++ for i := 0; i < 32; i++ { ++ e[i] = 0xFF ++ } ++ return e ++} ++ ++func BenchmarkModAdd(b *testing.B) { ++ x := makeBenchmarkValue() ++ y := makeBenchmarkValue() ++ m := makeBenchmarkModulus() ++ ++ b.ResetTimer() ++ for i := 0; i < b.N; i++ { ++ x.modAdd(y, m) ++ } ++} ++ ++func BenchmarkModSub(b *testing.B) { ++ x := makeBenchmarkValue() ++ y := makeBenchmarkValue() ++ m := makeBenchmarkModulus() ++ ++ b.ResetTimer() ++ for i := 0; i < b.N; i++ { ++ x.modSub(y, m) ++ } ++} ++ ++func BenchmarkMontgomeryRepr(b *testing.B) { ++ x := makeBenchmarkValue() ++ m := makeBenchmarkModulus() ++ ++ b.ResetTimer() ++ for i := 0; i < b.N; i++ { ++ x.montgomeryRepresentation(m) ++ } ++} ++ ++func BenchmarkMontgomeryMul(b *testing.B) { ++ x := makeBenchmarkValue() ++ y := makeBenchmarkValue() ++ out := makeBenchmarkValue() ++ m := makeBenchmarkModulus() ++ ++ b.ResetTimer() ++ for i := 0; i < b.N; i++ { ++ out.montgomeryMul(x, y, m) ++ } ++} ++ ++func BenchmarkModMul(b *testing.B) { ++ x := makeBenchmarkValue() ++ y := makeBenchmarkValue() ++ m := makeBenchmarkModulus() ++ ++ b.ResetTimer() ++ for i := 0; i < b.N; i++ { ++ x.modMul(y, m) ++ } ++} ++ ++func BenchmarkExpBig(b *testing.B) { ++ out := new(big.Int) ++ exponentBytes := makeBenchmarkExponent() ++ x := new(big.Int).SetBytes(exponentBytes) ++ e := new(big.Int).SetBytes(exponentBytes) ++ n := new(big.Int).SetBytes(exponentBytes) ++ one := new(big.Int).SetUint64(1) ++ n.Add(n, one) ++ ++ b.ResetTimer() ++ for i := 0; i < b.N; i++ { ++ out.Exp(x, e, n) ++ } ++} ++ ++func BenchmarkExp(b *testing.B) { ++ x := makeBenchmarkValue() ++ e := makeBenchmarkExponent() ++ out := makeBenchmarkValue() ++ m := makeBenchmarkModulus() ++ ++ b.ResetTimer() ++ for i := 0; i < b.N; i++ { ++ out.exp(x, e, m) ++ } ++} +diff --git a/src/crypto/rsa/pkcs1v15.go b/src/crypto/rsa/pkcs1v15.go +index a216be3..ce89f92 100644 +--- a/src/crypto/rsa/pkcs1v15.go ++++ b/src/crypto/rsa/pkcs1v15.go +@@ -9,7 +9,6 @@ import ( + "crypto/subtle" + "errors" + "io" +- "math/big" + + "crypto/internal/randutil" + ) +@@ -58,14 +57,11 @@ func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) ([]byte, error) + em[len(em)-len(msg)-1] = 0 + copy(mm, msg) + +- m := new(big.Int).SetBytes(em) +- c := encrypt(new(big.Int), pub, m) +- +- return c.FillBytes(em), nil ++ return encrypt(pub, em), nil + } + + // DecryptPKCS1v15 decrypts a plaintext using RSA and the padding scheme from PKCS#1 v1.5. +-// If rand != nil, it uses RSA blinding to avoid timing side-channel attacks. ++// The rand parameter is legacy and ignored, and it can be as nil. + // + // Note that whether this function returns an error or not discloses secret + // information. If an attacker can cause this function to run repeatedly and +@@ -76,7 +72,7 @@ func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) ([]byt + if err := checkPub(&priv.PublicKey); err != nil { + return nil, err + } +- valid, out, index, err := decryptPKCS1v15(rand, priv, ciphertext) ++ valid, out, index, err := decryptPKCS1v15(priv, ciphertext) + if err != nil { + return nil, err + } +@@ -87,7 +83,7 @@ func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) ([]byt + } + + // DecryptPKCS1v15SessionKey decrypts a session key using RSA and the padding scheme from PKCS#1 v1.5. +-// If rand != nil, it uses RSA blinding to avoid timing side-channel attacks. ++// The rand parameter is legacy and ignored, and it can be as nil. + // It returns an error if the ciphertext is the wrong length or if the + // ciphertext is greater than the public modulus. Otherwise, no error is + // returned. If the padding is valid, the resulting plaintext message is copied +@@ -114,7 +110,7 @@ func DecryptPKCS1v15SessionKey(rand io.Reader, priv *PrivateKey, ciphertext []by + return ErrDecryption + } + +- valid, em, index, err := decryptPKCS1v15(rand, priv, ciphertext) ++ valid, em, index, err := decryptPKCS1v15(priv, ciphertext) + if err != nil { + return err + } +@@ -130,26 +126,24 @@ func DecryptPKCS1v15SessionKey(rand io.Reader, priv *PrivateKey, ciphertext []by + return nil + } + +-// decryptPKCS1v15 decrypts ciphertext using priv and blinds the operation if +-// rand is not nil. It returns one or zero in valid that indicates whether the +-// plaintext was correctly structured. In either case, the plaintext is +-// returned in em so that it may be read independently of whether it was valid +-// in order to maintain constant memory access patterns. If the plaintext was +-// valid then index contains the index of the original message in em. +-func decryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (valid int, em []byte, index int, err error) { ++// decryptPKCS1v15 decrypts ciphertext using priv. It returns one or zero in ++// valid that indicates whether the plaintext was correctly structured. ++// In either case, the plaintext is returned in em so that it may be read ++// independently of whether it was valid in order to maintain constant memory ++// access patterns. If the plaintext was valid then index contains the index of ++// the original message in em, to allow constant time padding removal. ++func decryptPKCS1v15(priv *PrivateKey, ciphertext []byte) (valid int, em []byte, index int, err error) { + k := priv.Size() + if k < 11 { + err = ErrDecryption + return + } + +- c := new(big.Int).SetBytes(ciphertext) +- m, err := decrypt(rand, priv, c) ++ em, err = decrypt(priv, ciphertext) + if err != nil { + return + } + +- em = m.FillBytes(make([]byte, k)) + firstByteIsZero := subtle.ConstantTimeByteEq(em[0], 0) + secondByteIsTwo := subtle.ConstantTimeByteEq(em[1], 2) + +@@ -221,8 +215,7 @@ var hashPrefixes = map[crypto.Hash][]byte{ + // function. If hash is zero, hashed is signed directly. This isn't + // advisable except for interoperability. + // +-// If rand is not nil then RSA blinding will be used to avoid timing +-// side-channel attacks. ++// The rand parameter is legacy and ignored, and it can be as nil. + // + // This function is deterministic. Thus, if the set of possible + // messages is small, an attacker may be able to build a map from +@@ -249,13 +242,7 @@ func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []b + copy(em[k-tLen:k-hashLen], prefix) + copy(em[k-hashLen:k], hashed) + +- m := new(big.Int).SetBytes(em) +- c, err := decryptAndCheck(rand, priv, m) +- if err != nil { +- return nil, err +- } +- +- return c.FillBytes(em), nil ++ return decryptAndCheck(priv, em) + } + + // VerifyPKCS1v15 verifies an RSA PKCS#1 v1.5 signature. +@@ -275,9 +262,7 @@ func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) + return ErrVerification + } + +- c := new(big.Int).SetBytes(sig) +- m := encrypt(new(big.Int), pub, c) +- em := m.FillBytes(make([]byte, k)) ++ em := encrypt(pub, sig) + // EM = 0x00 || 0x01 || PS || 0x00 || T + + ok := subtle.ConstantTimeByteEq(em[0], 0) +diff --git a/src/crypto/rsa/pss.go b/src/crypto/rsa/pss.go +index 814522d..eaba4be 100644 +--- a/src/crypto/rsa/pss.go ++++ b/src/crypto/rsa/pss.go +@@ -12,7 +12,6 @@ import ( + "errors" + "hash" + "io" +- "math/big" + ) + + // Per RFC 8017, Section 9.1 +@@ -207,19 +206,27 @@ func emsaPSSVerify(mHash, em []byte, emBits, sLen int, hash hash.Hash) error { + // Note that hashed must be the result of hashing the input message using the + // given hash function. salt is a random sequence of bytes whose length will be + // later used to verify the signature. +-func signPSSWithSalt(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed, salt []byte) ([]byte, error) { +- emBits := priv.N.BitLen() - 1 ++func signPSSWithSalt(priv *PrivateKey, hash crypto.Hash, hashed, salt []byte) ([]byte, error) { ++ emBits := bigBitLen(priv.N) - 1 + em, err := emsaPSSEncode(hashed, emBits, salt, hash.New()) + if err != nil { + return nil, err + } +- m := new(big.Int).SetBytes(em) +- c, err := decryptAndCheck(rand, priv, m) +- if err != nil { +- return nil, err ++ ++ // RFC 8017: "Note that the octet length of EM will be one less than k if ++ // modBits - 1 is divisible by 8 and equal to k otherwise, where k is the ++ // length in octets of the RSA modulus n." ++ // ++ // This is extremely annoying, as all other encrypt and decrypt inputs are ++ // always the exact same size as the modulus. Since it only happens for ++ // weird modulus sizes, fix it by padding inefficiently. ++ if emLen, k := len(em), priv.Size(); emLen < k { ++ emNew := make([]byte, k) ++ copy(emNew[k-emLen:], em) ++ em = emNew + } +- s := make([]byte, priv.Size()) +- return c.FillBytes(s), nil ++ ++ return decryptAndCheck(priv, em) + } + + const ( +@@ -269,7 +276,7 @@ func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, digest []byte, + saltLength := opts.saltLength() + switch saltLength { + case PSSSaltLengthAuto: +- saltLength = (priv.N.BitLen()-1+7)/8 - 2 - hash.Size() ++ saltLength = (bigBitLen(priv.N)-1+7)/8 - 2 - hash.Size() + case PSSSaltLengthEqualsHash: + saltLength = hash.Size() + } +@@ -278,7 +285,7 @@ func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, digest []byte, + if _, err := io.ReadFull(rand, salt); err != nil { + return nil, err + } +- return signPSSWithSalt(rand, priv, hash, digest, salt) ++ return signPSSWithSalt(priv, hash, digest, salt) + } + + // VerifyPSS verifies a PSS signature. +@@ -291,13 +298,22 @@ func VerifyPSS(pub *PublicKey, hash crypto.Hash, digest []byte, sig []byte, opts + if len(sig) != pub.Size() { + return ErrVerification + } +- s := new(big.Int).SetBytes(sig) +- m := encrypt(new(big.Int), pub, s) +- emBits := pub.N.BitLen() - 1 ++ ++ emBits := bigBitLen(pub.N) - 1 + emLen := (emBits + 7) / 8 +- if m.BitLen() > emLen*8 { +- return ErrVerification ++ em := encrypt(pub, sig) ++ ++ // Like in signPSSWithSalt, deal with mismatches between emLen and the size ++ // of the modulus. The spec would have us wire emLen into the encoding ++ // function, but we'd rather always encode to the size of the modulus and ++ // then strip leading zeroes if necessary. This only happens for weird ++ // modulus sizes anyway. ++ for len(em) > emLen && len(em) > 0 { ++ if em[0] != 0 { ++ return ErrVerification ++ } ++ em = em[1:] + } +- em := m.FillBytes(make([]byte, emLen)) ++ + return emsaPSSVerify(digest, em, emBits, opts.saltLength(), hash.New()) + } +diff --git a/src/crypto/rsa/pss_test.go b/src/crypto/rsa/pss_test.go +index c3a6d46..d018b43 100644 +--- a/src/crypto/rsa/pss_test.go ++++ b/src/crypto/rsa/pss_test.go +@@ -233,7 +233,10 @@ func TestPSSSigning(t *testing.T) { + } + } + +-func TestSignWithPSSSaltLengthAuto(t *testing.T) { ++func TestPSS513(t *testing.T) { ++ // See Issue 42741, and separately, RFC 8017: "Note that the octet length of ++ // EM will be one less than k if modBits - 1 is divisible by 8 and equal to ++ // k otherwise, where k is the length in octets of the RSA modulus n." + key, err := GenerateKey(rand.Reader, 513) + if err != nil { + t.Fatal(err) +@@ -246,8 +249,9 @@ func TestSignWithPSSSaltLengthAuto(t *testing.T) { + if err != nil { + t.Fatal(err) + } +- if len(signature) == 0 { +- t.Fatal("empty signature returned") ++ err = VerifyPSS(&key.PublicKey, crypto.SHA256, digest[:], signature, nil) ++ if err != nil { ++ t.Error(err) + } + } + +diff --git a/src/crypto/rsa/rsa.go b/src/crypto/rsa/rsa.go +index 5a00ed2..29d9d31 100644 +--- a/src/crypto/rsa/rsa.go ++++ b/src/crypto/rsa/rsa.go +@@ -19,13 +19,17 @@ + // over the public key primitive, the PrivateKey type implements the + // Decrypter and Signer interfaces from the crypto package. + // +-// The RSA operations in this package are not implemented using constant-time algorithms. ++// Operations in this package are implemented using constant-time algorithms, ++// except for [GenerateKey], [PrivateKey.Precompute], and [PrivateKey.Validate]. ++// Every other operation only leaks the bit size of the involved values, which ++// all depend on the selected key size. + package rsa + + import ( + "crypto" + "crypto/rand" + "crypto/subtle" ++ "encoding/binary" + "errors" + "hash" + "io" +@@ -35,7 +39,6 @@ import ( + "crypto/internal/randutil" + ) + +-var bigZero = big.NewInt(0) + var bigOne = big.NewInt(1) + + // A PublicKey represents the public part of an RSA key. +@@ -47,7 +50,7 @@ type PublicKey struct { + // Size returns the modulus size in bytes. Raw signatures and ciphertexts + // for or by this public key will have the same size. + func (pub *PublicKey) Size() int { +- return (pub.N.BitLen() + 7) / 8 ++ return (bigBitLen(pub.N) + 7) / 8 + } + + // OAEPOptions is an interface for passing options to OAEP decryption using the +@@ -351,10 +354,19 @@ func mgf1XOR(out []byte, hash hash.Hash, seed []byte) { + // too large for the size of the public key. + var ErrMessageTooLong = errors.New("crypto/rsa: message too long for RSA public key size") + +-func encrypt(c *big.Int, pub *PublicKey, m *big.Int) *big.Int { +- e := big.NewInt(int64(pub.E)) +- c.Exp(m, e, pub.N) +- return c ++func encrypt(pub *PublicKey, plaintext []byte) []byte { ++ ++ N := modulusFromNat(natFromBig(pub.N)) ++ m := natFromBytes(plaintext).expandFor(N) ++ ++ e := make([]byte, 8) ++ binary.BigEndian.PutUint64(e, uint64(pub.E)) ++ for len(e) > 1 && e[0] == 0 { ++ e = e[1:] ++ } ++ ++ out := make([]byte, modulusSize(N)) ++ return new(nat).exp(m, e, N).fillBytes(out) + } + + // EncryptOAEP encrypts the given message with RSA-OAEP. +@@ -404,12 +416,7 @@ func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, l + mgf1XOR(db, hash, seed) + mgf1XOR(seed, hash, db) + +- m := new(big.Int) +- m.SetBytes(em) +- c := encrypt(new(big.Int), pub, m) +- +- out := make([]byte, k) +- return c.FillBytes(out), nil ++ return encrypt(pub, em), nil + } + + // ErrDecryption represents a failure to decrypt a message. +@@ -451,98 +458,71 @@ func (priv *PrivateKey) Precompute() { + } + } + +-// decrypt performs an RSA decryption, resulting in a plaintext integer. If a +-// random source is given, RSA blinding is used. +-func decrypt(random io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err error) { +- // TODO(agl): can we get away with reusing blinds? +- if c.Cmp(priv.N) > 0 { +- err = ErrDecryption +- return ++// decrypt performs an RSA decryption of ciphertext into out. ++func decrypt(priv *PrivateKey, ciphertext []byte) ([]byte, error) { ++ ++ N := modulusFromNat(natFromBig(priv.N)) ++ c := natFromBytes(ciphertext).expandFor(N) ++ if c.cmpGeq(N.nat) == 1 { ++ return nil, ErrDecryption + } + if priv.N.Sign() == 0 { + return nil, ErrDecryption + } + +- var ir *big.Int +- if random != nil { +- randutil.MaybeReadByte(random) +- +- // Blinding enabled. Blinding involves multiplying c by r^e. +- // Then the decryption operation performs (m^e * r^e)^d mod n +- // which equals mr mod n. The factor of r can then be removed +- // by multiplying by the multiplicative inverse of r. +- +- var r *big.Int +- ir = new(big.Int) +- for { +- r, err = rand.Int(random, priv.N) +- if err != nil { +- return +- } +- if r.Cmp(bigZero) == 0 { +- r = bigOne +- } +- ok := ir.ModInverse(r, priv.N) +- if ok != nil { +- break +- } +- } +- bigE := big.NewInt(int64(priv.E)) +- rpowe := new(big.Int).Exp(r, bigE, priv.N) // N != 0 +- cCopy := new(big.Int).Set(c) +- cCopy.Mul(cCopy, rpowe) +- cCopy.Mod(cCopy, priv.N) +- c = cCopy +- } +- ++ // Note that because our private decryption exponents are stored as big.Int, ++ // we potentially leak the exact number of bits of these exponents. This ++ // isn't great, but should be fine. + if priv.Precomputed.Dp == nil { +- m = new(big.Int).Exp(c, priv.D, priv.N) +- } else { +- // We have the precalculated values needed for the CRT. +- m = new(big.Int).Exp(c, priv.Precomputed.Dp, priv.Primes[0]) +- m2 := new(big.Int).Exp(c, priv.Precomputed.Dq, priv.Primes[1]) +- m.Sub(m, m2) +- if m.Sign() < 0 { +- m.Add(m, priv.Primes[0]) +- } +- m.Mul(m, priv.Precomputed.Qinv) +- m.Mod(m, priv.Primes[0]) +- m.Mul(m, priv.Primes[1]) +- m.Add(m, m2) +- +- for i, values := range priv.Precomputed.CRTValues { +- prime := priv.Primes[2+i] +- m2.Exp(c, values.Exp, prime) +- m2.Sub(m2, m) +- m2.Mul(m2, values.Coeff) +- m2.Mod(m2, prime) +- if m2.Sign() < 0 { +- m2.Add(m2, prime) +- } +- m2.Mul(m2, values.R) +- m.Add(m, m2) +- } +- } +- +- if ir != nil { +- // Unblind. +- m.Mul(m, ir) +- m.Mod(m, priv.N) +- } +- +- return ++ out := make([]byte, modulusSize(N)) ++ return new(nat).exp(c, priv.D.Bytes(), N).fillBytes(out), nil ++ } ++ ++ t0 := new(nat) ++ P := modulusFromNat(natFromBig(priv.Primes[0])) ++ Q := modulusFromNat(natFromBig(priv.Primes[1])) ++ // m = c ^ Dp mod p ++ m := new(nat).exp(t0.mod(c, P), priv.Precomputed.Dp.Bytes(), P) ++ // m2 = c ^ Dq mod q ++ m2 := new(nat).exp(t0.mod(c, Q), priv.Precomputed.Dq.Bytes(), Q) ++ // m = m - m2 mod p ++ m.modSub(t0.mod(m2, P), P) ++ // m = m * Qinv mod p ++ m.modMul(natFromBig(priv.Precomputed.Qinv).expandFor(P), P) ++ // m = m * q mod N ++ m.expandFor(N).modMul(t0.mod(Q.nat, N), N) ++ // m = m + m2 mod N ++ m.modAdd(m2.expandFor(N), N) ++ ++ for i, values := range priv.Precomputed.CRTValues { ++ p := modulusFromNat(natFromBig(priv.Primes[2+i])) ++ // m2 = c ^ Exp mod p ++ m2.exp(t0.mod(c, p), values.Exp.Bytes(), p) ++ // m2 = m2 - m mod p ++ m2.modSub(t0.mod(m, p), p) ++ // m2 = m2 * Coeff mod p ++ m2.modMul(natFromBig(values.Coeff).expandFor(p), p) ++ // m2 = m2 * R mod N ++ R := natFromBig(values.R).expandFor(N) ++ m2.expandFor(N).modMul(R, N) ++ // m = m + m2 mod N ++ m.modAdd(m2, N) ++ } ++ ++ out := make([]byte, modulusSize(N)) ++ return m.fillBytes(out), nil + } + +-func decryptAndCheck(random io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err error) { +- m, err = decrypt(random, priv, c) ++func decryptAndCheck(priv *PrivateKey, ciphertext []byte) (m []byte, err error) { ++ m, err = decrypt(priv, ciphertext) + if err != nil { + return nil, err + } + + // In order to defend against errors in the CRT computation, m^e is + // calculated, which should match the original ciphertext. +- check := encrypt(new(big.Int), &priv.PublicKey, m) +- if c.Cmp(check) != 0 { ++ check := encrypt(&priv.PublicKey, m) ++ if subtle.ConstantTimeCompare(ciphertext, check) != 1 { + return nil, errors.New("rsa: internal error") + } + return m, nil +@@ -554,9 +534,7 @@ func decryptAndCheck(random io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int + // Encryption and decryption of a given message must use the same hash function + // and sha256.New() is a reasonable choice. + // +-// The random parameter, if not nil, is used to blind the private-key operation +-// and avoid timing side-channel attacks. Blinding is purely internal to this +-// function – the random data need not match that used when encrypting. ++// The random parameter is legacy and ignored, and it can be as nil. + // + // The label parameter must match the value given when encrypting. See + // EncryptOAEP for details. +@@ -570,9 +548,7 @@ func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext + return nil, ErrDecryption + } + +- c := new(big.Int).SetBytes(ciphertext) +- +- m, err := decrypt(random, priv, c) ++ em, err := decrypt(priv, ciphertext) + if err != nil { + return nil, err + } +@@ -581,10 +557,6 @@ func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext + lHash := hash.Sum(nil) + hash.Reset() + +- // We probably leak the number of leading zeros. +- // It's not clear that we can do anything about this. +- em := m.FillBytes(make([]byte, k)) +- + firstByteIsZero := subtle.ConstantTimeByteEq(em[0], 0) + + seed := em[1 : hash.Size()+1] +-- +2.25.1 + diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-45289.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-45289.patch new file mode 100644 index 0000000000..13d3510504 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-45289.patch @@ -0,0 +1,121 @@ +From 20586c0dbe03d144f914155f879fa5ee287591a1 Mon Sep 17 00:00:00 2001 +From: Damien Neil <dneil@google.com> +Date: Thu, 11 Jan 2024 11:31:57 -0800 +Subject: [PATCH] [release-branch.go1.21] net/http, net/http/cookiejar: avoid + subdomain matches on IPv6 zones + +When deciding whether to forward cookies or sensitive headers +across a redirect, do not attempt to interpret an IPv6 address +as a domain name. + +Avoids a case where a maliciously-crafted redirect to an +IPv6 address with a scoped addressing zone could be +misinterpreted as a within-domain redirect. For example, +we could interpret "::1%.www.example.com" as a subdomain +of "www.example.com". + +Thanks to Juho Nurminen of Mattermost for reporting this issue. + +Fixes CVE-2023-45289 +Fixes #65385 +For #65065 + +Change-Id: I8f463f59f0e700c8a18733d2b264a8bcb3a19599 +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2131938 +Reviewed-by: Tatiana Bradley <tatianabradley@google.com> +Reviewed-by: Roland Shoemaker <bracewell@google.com> +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2173775 +Reviewed-by: Carlos Amedee <amedee@google.com> +Reviewed-on: https://go-review.googlesource.com/c/go/+/569239 +Reviewed-by: Carlos Amedee <carlos@golang.org> +Auto-Submit: Michael Knyszek <mknyszek@google.com> +TryBot-Bypass: Michael Knyszek <mknyszek@google.com> + +Upstream-Status: Backport [https://github.com/golang/go/commit/20586c0dbe03d144f914155f879fa5ee287591a1] +CVE: CVE-2023-45289 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + src/net/http/client.go | 6 ++++++ + src/net/http/client_test.go | 1 + + src/net/http/cookiejar/jar.go | 7 +++++++ + src/net/http/cookiejar/jar_test.go | 10 ++++++++++ + 4 files changed, 24 insertions(+) + +diff --git a/src/net/http/client.go b/src/net/http/client.go +index a496f1c..2031834 100644 +--- a/src/net/http/client.go ++++ b/src/net/http/client.go +@@ -973,6 +973,12 @@ func isDomainOrSubdomain(sub, parent string) bool { + if sub == parent { + return true + } ++ // If sub contains a :, it's probably an IPv6 address (and is definitely not a hostname). ++ // Don't check the suffix in this case, to avoid matching the contents of a IPv6 zone. ++ // For example, "::1%.www.example.com" is not a subdomain of "www.example.com". ++ if strings.ContainsAny(sub, ":%") { ++ return false ++ } + // If sub is "foo.example.com" and parent is "example.com", + // that means sub must end in "."+parent. + // Do it without allocating. +diff --git a/src/net/http/client_test.go b/src/net/http/client_test.go +index 2b4f53f..442fe35 100644 +--- a/src/net/http/client_test.go ++++ b/src/net/http/client_test.go +@@ -1703,6 +1703,7 @@ func TestShouldCopyHeaderOnRedirect(t *testing.T) { + {"cookie2", "http://foo.com/", "http://bar.com/", false}, + {"authorization", "http://foo.com/", "http://bar.com/", false}, + {"www-authenticate", "http://foo.com/", "http://bar.com/", false}, ++ {"authorization", "http://foo.com/", "http://[::1%25.foo.com]/", false}, + + // But subdomains should work: + {"www-authenticate", "http://foo.com/", "http://foo.com/", true}, +diff --git a/src/net/http/cookiejar/jar.go b/src/net/http/cookiejar/jar.go +index 9f19917..18cbfc2 100644 +--- a/src/net/http/cookiejar/jar.go ++++ b/src/net/http/cookiejar/jar.go +@@ -356,6 +356,13 @@ func jarKey(host string, psl PublicSuffixList) string { + + // isIP reports whether host is an IP address. + func isIP(host string) bool { ++ if strings.ContainsAny(host, ":%") { ++ // Probable IPv6 address. ++ // Hostnames can't contain : or %, so this is definitely not a valid host. ++ // Treating it as an IP is the more conservative option, and avoids the risk ++ // of interpeting ::1%.www.example.com as a subtomain of www.example.com. ++ return true ++ } + return net.ParseIP(host) != nil + } + +diff --git a/src/net/http/cookiejar/jar_test.go b/src/net/http/cookiejar/jar_test.go +index 47fb1ab..fd8d40e 100644 +--- a/src/net/http/cookiejar/jar_test.go ++++ b/src/net/http/cookiejar/jar_test.go +@@ -251,6 +251,7 @@ var isIPTests = map[string]bool{ + "127.0.0.1": true, + "1.2.3.4": true, + "2001:4860:0:2001::68": true, ++ "::1%zone": true, + "example.com": false, + "1.1.1.300": false, + "www.foo.bar.net": false, +@@ -613,6 +614,15 @@ var basicsTests = [...]jarTest{ + {"http://www.host.test:1234/", "a=1"}, + }, + }, ++ { ++ "IPv6 zone is not treated as a host.", ++ "https://example.com/", ++ []string{"a=1"}, ++ "a=1", ++ []query{ ++ {"https://[::1%25.example.com]:80/", ""}, ++ }, ++ }, + } + + func TestBasics(t *testing.T) { +-- +2.25.1 + diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-45290.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-45290.patch new file mode 100644 index 0000000000..ddc2f67c96 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-45290.patch @@ -0,0 +1,271 @@ +From bf80213b121074f4ad9b449410a4d13bae5e9be0 Mon Sep 17 00:00:00 2001 +From: Damien Neil <dneil@google.com> +Date: Tue, 16 Jan 2024 15:37:52 -0800 +Subject: [PATCH] [release-branch.go1.21] net/textproto, mime/multipart: avoid + unbounded read in MIME header + +mime/multipart.Reader.ReadForm allows specifying the maximum amount +of memory that will be consumed by the form. While this limit is +correctly applied to the parsed form data structure, it was not +being applied to individual header lines in a form. + +For example, when presented with a form containing a header line +that never ends, ReadForm will continue to read the line until it +runs out of memory. + +Limit the amount of data consumed when reading a header. + +Fixes CVE-2023-45290 +Fixes #65389 +For #65383 + +Change-Id: I7f9264d25752009e95f6b2c80e3d76aaf321d658 +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2134435 +Reviewed-by: Roland Shoemaker <bracewell@google.com> +Reviewed-by: Tatiana Bradley <tatianabradley@google.com> +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2173776 +Reviewed-by: Carlos Amedee <amedee@google.com> +Reviewed-on: https://go-review.googlesource.com/c/go/+/569240 +Auto-Submit: Michael Knyszek <mknyszek@google.com> +LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> +Reviewed-by: Carlos Amedee <carlos@golang.org> + +Upstream-Status: Backport [https://github.com/golang/go/commit/bf80213b121074f4ad9b449410a4d13bae5e9be0] +CVE: CVE-2023-45290 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + src/mime/multipart/formdata_test.go | 42 +++++++++++++++++++++++++ + src/net/textproto/reader.go | 48 ++++++++++++++++++++--------- + src/net/textproto/reader_test.go | 12 ++++++++ + 3 files changed, 87 insertions(+), 15 deletions(-) + +diff --git a/src/mime/multipart/formdata_test.go b/src/mime/multipart/formdata_test.go +index c78eeb7..f729da6 100644 +--- a/src/mime/multipart/formdata_test.go ++++ b/src/mime/multipart/formdata_test.go +@@ -421,6 +421,48 @@ func TestReadFormLimits(t *testing.T) { + } + } + ++func TestReadFormEndlessHeaderLine(t *testing.T) { ++ for _, test := range []struct { ++ name string ++ prefix string ++ }{{ ++ name: "name", ++ prefix: "X-", ++ }, { ++ name: "value", ++ prefix: "X-Header: ", ++ }, { ++ name: "continuation", ++ prefix: "X-Header: foo\r\n ", ++ }} { ++ t.Run(test.name, func(t *testing.T) { ++ const eol = "\r\n" ++ s := `--boundary` + eol ++ s += `Content-Disposition: form-data; name="a"` + eol ++ s += `Content-Type: text/plain` + eol ++ s += test.prefix ++ fr := io.MultiReader( ++ strings.NewReader(s), ++ neverendingReader('X'), ++ ) ++ r := NewReader(fr, "boundary") ++ _, err := r.ReadForm(1 << 20) ++ if err != ErrMessageTooLarge { ++ t.Fatalf("ReadForm(1 << 20): %v, want ErrMessageTooLarge", err) ++ } ++ }) ++ } ++} ++ ++type neverendingReader byte ++ ++func (r neverendingReader) Read(p []byte) (n int, err error) { ++ for i := range p { ++ p[i] = byte(r) ++ } ++ return len(p), nil ++} ++ + func BenchmarkReadForm(b *testing.B) { + for _, test := range []struct { + name string +diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go +index ad2d777..cea6613 100644 +--- a/src/net/textproto/reader.go ++++ b/src/net/textproto/reader.go +@@ -17,6 +17,10 @@ import ( + "sync" + ) + ++// TODO: This should be a distinguishable error (ErrMessageTooLarge) ++// to allow mime/multipart to detect it. ++var errMessageTooLarge = errors.New("message too large") ++ + // A Reader implements convenience methods for reading requests + // or responses from a text protocol network connection. + type Reader struct { +@@ -38,13 +42,13 @@ func NewReader(r *bufio.Reader) *Reader { + // ReadLine reads a single line from r, + // eliding the final \n or \r\n from the returned string. + func (r *Reader) ReadLine() (string, error) { +- line, err := r.readLineSlice() ++ line, err := r.readLineSlice(-1) + return string(line), err + } + + // ReadLineBytes is like ReadLine but returns a []byte instead of a string. + func (r *Reader) ReadLineBytes() ([]byte, error) { +- line, err := r.readLineSlice() ++ line, err := r.readLineSlice(-1) + if line != nil { + buf := make([]byte, len(line)) + copy(buf, line) +@@ -53,7 +57,10 @@ func (r *Reader) ReadLineBytes() ([]byte, error) { + return line, err + } + +-func (r *Reader) readLineSlice() ([]byte, error) { ++// readLineSlice reads a single line from r, ++// up to lim bytes long (or unlimited if lim is less than 0), ++// eliding the final \r or \r\n from the returned string. ++func (r *Reader) readLineSlice(lim int64) ([]byte, error) { + r.closeDot() + var line []byte + for { +@@ -61,6 +68,9 @@ func (r *Reader) readLineSlice() ([]byte, error) { + if err != nil { + return nil, err + } ++ if lim >= 0 && int64(len(line))+int64(len(l)) > lim { ++ return nil, errMessageTooLarge ++ } + // Avoid the copy if the first call produced a full line. + if line == nil && !more { + return l, nil +@@ -93,7 +103,7 @@ func (r *Reader) readLineSlice() ([]byte, error) { + // A line consisting of only white space is never continued. + // + func (r *Reader) ReadContinuedLine() (string, error) { +- line, err := r.readContinuedLineSlice(noValidation) ++ line, err := r.readContinuedLineSlice(-1, noValidation) + return string(line), err + } + +@@ -114,7 +124,7 @@ func trim(s []byte) []byte { + // ReadContinuedLineBytes is like ReadContinuedLine but + // returns a []byte instead of a string. + func (r *Reader) ReadContinuedLineBytes() ([]byte, error) { +- line, err := r.readContinuedLineSlice(noValidation) ++ line, err := r.readContinuedLineSlice(-1, noValidation) + if line != nil { + buf := make([]byte, len(line)) + copy(buf, line) +@@ -127,13 +137,14 @@ func (r *Reader) ReadContinuedLineBytes() ([]byte, error) { + // returning a byte slice with all lines. The validateFirstLine function + // is run on the first read line, and if it returns an error then this + // error is returned from readContinuedLineSlice. +-func (r *Reader) readContinuedLineSlice(validateFirstLine func([]byte) error) ([]byte, error) { ++// It reads up to lim bytes of data (or unlimited if lim is less than 0). ++func (r *Reader) readContinuedLineSlice(lim int64, validateFirstLine func([]byte) error) ([]byte, error) { + if validateFirstLine == nil { + return nil, fmt.Errorf("missing validateFirstLine func") + } + + // Read the first line. +- line, err := r.readLineSlice() ++ line, err := r.readLineSlice(lim) + if err != nil { + return nil, err + } +@@ -161,13 +172,21 @@ func (r *Reader) readContinuedLineSlice(validateFirstLine func([]byte) error) ([ + // copy the slice into buf. + r.buf = append(r.buf[:0], trim(line)...) + ++ if lim < 0 { ++ lim = math.MaxInt64 ++ } ++ lim -= int64(len(r.buf)) ++ + // Read continuation lines. + for r.skipSpace() > 0 { +- line, err := r.readLineSlice() ++ r.buf = append(r.buf, ' ') ++ if int64(len(r.buf)) >= lim { ++ return nil, errMessageTooLarge ++ } ++ line, err := r.readLineSlice(lim - int64(len(r.buf))) + if err != nil { + break + } +- r.buf = append(r.buf, ' ') + r.buf = append(r.buf, trim(line)...) + } + return r.buf, nil +@@ -512,7 +531,8 @@ func readMIMEHeader(r *Reader, maxMemory, maxHeaders int64) (MIMEHeader, error) + + // The first line cannot start with a leading space. + if buf, err := r.R.Peek(1); err == nil && (buf[0] == ' ' || buf[0] == '\t') { +- line, err := r.readLineSlice() ++ const errorLimit = 80 // arbitrary limit on how much of the line we'll quote ++ line, err := r.readLineSlice(errorLimit) + if err != nil { + return m, err + } +@@ -520,7 +540,7 @@ func readMIMEHeader(r *Reader, maxMemory, maxHeaders int64) (MIMEHeader, error) + } + + for { +- kv, err := r.readContinuedLineSlice(mustHaveFieldNameColon) ++ kv, err := r.readContinuedLineSlice(maxMemory, mustHaveFieldNameColon) + if len(kv) == 0 { + return m, err + } +@@ -541,7 +561,7 @@ func readMIMEHeader(r *Reader, maxMemory, maxHeaders int64) (MIMEHeader, error) + + maxHeaders-- + if maxHeaders < 0 { +- return nil, errors.New("message too large") ++ return nil, errMessageTooLarge + } + + // backport 5c55ac9bf1e5f779220294c843526536605f42ab +@@ -567,9 +587,7 @@ func readMIMEHeader(r *Reader, maxMemory, maxHeaders int64) (MIMEHeader, error) + } + maxMemory -= int64(len(value)) + if maxMemory < 0 { +- // TODO: This should be a distinguishable error (ErrMessageTooLarge) +- // to allow mime/multipart to detect it. +- return m, errors.New("message too large") ++ return m, errMessageTooLarge + } + if vv == nil && len(strs) > 0 { + // More than likely this will be a single-element key. +diff --git a/src/net/textproto/reader_test.go b/src/net/textproto/reader_test.go +index 3ae0de1..db1ed91 100644 +--- a/src/net/textproto/reader_test.go ++++ b/src/net/textproto/reader_test.go +@@ -34,6 +34,18 @@ func TestReadLine(t *testing.T) { + } + } + ++func TestReadLineLongLine(t *testing.T) { ++ line := strings.Repeat("12345", 10000) ++ r := reader(line + "\r\n") ++ s, err := r.ReadLine() ++ if err != nil { ++ t.Fatalf("Line 1: %v", err) ++ } ++ if s != line { ++ t.Fatalf("%v-byte line does not match expected %v-byte line", len(s), len(line)) ++ } ++} ++ + func TestReadContinuedLine(t *testing.T) { + r := reader("line1\nline\n 2\nline3\n") + s, err := r.ReadContinuedLine() +-- +2.25.1 + diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2024-24784.patch b/meta/recipes-devtools/go/go-1.14/CVE-2024-24784.patch new file mode 100644 index 0000000000..e9d9d972b9 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2024-24784.patch @@ -0,0 +1,205 @@ +From 5330cd225ba54c7dc78c1b46dcdf61a4671a632c Mon Sep 17 00:00:00 2001 +From: Roland Shoemaker <bracewell@google.com> +Date: Wed, 10 Jan 2024 11:02:14 -0800 +Subject: [PATCH] [release-branch.go1.22] net/mail: properly handle special + characters in phrase and obs-phrase + +Fixes a couple of misalignments with RFC 5322 which introduce +significant diffs between (mostly) conformant parsers. + +This change reverts the changes made in CL50911, which allowed certain +special RFC 5322 characters to appear unquoted in the "phrase" syntax. +It is unclear why this change was made in the first place, and created +a divergence from comformant parsers. In particular this resulted in +treating comments in display names incorrectly. + +Additionally properly handle trailing malformed comments in the group +syntax. + +For #65083 +Fixed #65849 + +Change-Id: I00dddc044c6ae3381154e43236632604c390f672 +Reviewed-on: https://go-review.googlesource.com/c/go/+/555596 +Reviewed-by: Damien Neil <dneil@google.com> +LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> +Reviewed-on: https://go-review.googlesource.com/c/go/+/566215 +Reviewed-by: Carlos Amedee <carlos@golang.org> + +Upstream-Status: Backport [https://github.com/golang/go/commit/5330cd225ba54c7dc78c1b46dcdf61a4671a632c] +CVE: CVE-2024-24784 +Signed-off-by: Ashish Sharma <asharma@mvista.com> + + src/net/mail/message.go | 30 +++++++++++++++------------ + src/net/mail/message_test.go | 40 ++++++++++++++++++++++++++---------- + 2 files changed, 46 insertions(+), 24 deletions(-) + +diff --git a/src/net/mail/message.go b/src/net/mail/message.go +index af516fc30f470..fc2a9e46f811b 100644 +--- a/src/net/mail/message.go ++++ b/src/net/mail/message.go +@@ -280,7 +280,7 @@ func (a *Address) String() string { + // Add quotes if needed + quoteLocal := false + for i, r := range local { +- if isAtext(r, false, false) { ++ if isAtext(r, false) { + continue + } + if r == '.' { +@@ -444,7 +444,7 @@ func (p *addrParser) parseAddress(handleGroup bool) ([]*Address, error) { + if !p.consume('<') { + atext := true + for _, r := range displayName { +- if !isAtext(r, true, false) { ++ if !isAtext(r, true) { + atext = false + break + } +@@ -479,7 +479,9 @@ func (p *addrParser) consumeGroupList() ([]*Address, error) { + // handle empty group. + p.skipSpace() + if p.consume(';') { +- p.skipCFWS() ++ if !p.skipCFWS() { ++ return nil, errors.New("mail: misformatted parenthetical comment") ++ } + return group, nil + } + +@@ -496,7 +498,9 @@ func (p *addrParser) consumeGroupList() ([]*Address, error) { + return nil, errors.New("mail: misformatted parenthetical comment") + } + if p.consume(';') { +- p.skipCFWS() ++ if !p.skipCFWS() { ++ return nil, errors.New("mail: misformatted parenthetical comment") ++ } + break + } + if !p.consume(',') { +@@ -566,6 +570,12 @@ func (p *addrParser) consumePhrase() (phrase string, err error) { + var words []string + var isPrevEncoded bool + for { ++ // obs-phrase allows CFWS after one word ++ if len(words) > 0 { ++ if !p.skipCFWS() { ++ return "", errors.New("mail: misformatted parenthetical comment") ++ } ++ } + // word = atom / quoted-string + var word string + p.skipSpace() +@@ -661,7 +671,6 @@ Loop: + // If dot is true, consumeAtom parses an RFC 5322 dot-atom instead. + // If permissive is true, consumeAtom will not fail on: + // - leading/trailing/double dots in the atom (see golang.org/issue/4938) +-// - special characters (RFC 5322 3.2.3) except '<', '>', ':' and '"' (see golang.org/issue/21018) + func (p *addrParser) consumeAtom(dot bool, permissive bool) (atom string, err error) { + i := 0 + +@@ -672,7 +681,7 @@ Loop: + case size == 1 && r == utf8.RuneError: + return "", fmt.Errorf("mail: invalid utf-8 in address: %q", p.s) + +- case size == 0 || !isAtext(r, dot, permissive): ++ case size == 0 || !isAtext(r, dot): + break Loop + + default: +@@ -850,18 +859,13 @@ func (e charsetError) Error() string { + + // isAtext reports whether r is an RFC 5322 atext character. + // If dot is true, period is included. +-// If permissive is true, RFC 5322 3.2.3 specials is included, +-// except '<', '>', ':' and '"'. +-func isAtext(r rune, dot, permissive bool) bool { ++func isAtext(r rune, dot bool) bool { + switch r { + case '.': + return dot + + // RFC 5322 3.2.3. specials +- case '(', ')', '[', ']', ';', '@', '\\', ',': +- return permissive +- +- case '<', '>', '"', ':': ++ case '(', ')', '<', '>', '[', ']', ':', ';', '@', '\\', ',', '"': // RFC 5322 3.2.3. specials + return false + } + return isVchar(r) +diff --git a/src/net/mail/message_test.go b/src/net/mail/message_test.go +index 1e1bb4092f659..1f2f62afbf406 100644 +--- a/src/net/mail/message_test.go ++++ b/src/net/mail/message_test.go +@@ -385,8 +385,11 @@ func TestAddressParsingError(t *testing.T) { + 13: {"group not closed: null@example.com", "expected comma"}, + 14: {"group: first@example.com, second@example.com;", "group with multiple addresses"}, + 15: {"john.doe", "missing '@' or angle-addr"}, +- 16: {"john.doe@", "no angle-addr"}, ++ 16: {"john.doe@", "missing '@' or angle-addr"}, + 17: {"John Doe@foo.bar", "no angle-addr"}, ++ 18: {" group: null@example.com; (asd", "misformatted parenthetical comment"}, ++ 19: {" group: ; (asd", "misformatted parenthetical comment"}, ++ 20: {`(John) Doe <jdoe@machine.example>`, "missing word in phrase:"}, + } + + for i, tc := range mustErrTestCases { +@@ -436,24 +439,19 @@ func TestAddressParsing(t *testing.T) { + Address: "john.q.public@example.com", + }}, + }, +- { +- `"John (middle) Doe" <jdoe@machine.example>`, +- []*Address{{ +- Name: "John (middle) Doe", +- Address: "jdoe@machine.example", +- }}, +- }, ++ // Comment in display name + { + `John (middle) Doe <jdoe@machine.example>`, + []*Address{{ +- Name: "John (middle) Doe", ++ Name: "John Doe", + Address: "jdoe@machine.example", + }}, + }, ++ // Display name is quoted string, so comment is not a comment + { +- `John !@M@! Doe <jdoe@machine.example>`, ++ `"John (middle) Doe" <jdoe@machine.example>`, + []*Address{{ +- Name: "John !@M@! Doe", ++ Name: "John (middle) Doe", + Address: "jdoe@machine.example", + }}, + }, +@@ -788,6 +786,26 @@ func TestAddressParsing(t *testing.T) { + }, + }, + }, ++ // Comment in group display name ++ { ++ `group (comment:): a@example.com, b@example.com;`, ++ []*Address{ ++ { ++ Address: "a@example.com", ++ }, ++ { ++ Address: "b@example.com", ++ }, ++ }, ++ }, ++ { ++ `x(:"):"@a.example;("@b.example;`, ++ []*Address{ ++ { ++ Address: `@a.example;(@b.example`, ++ }, ++ }, ++ }, + } + for _, test := range tests { + if len(test.exp) == 1 { diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2024-24785.patch b/meta/recipes-devtools/go/go-1.14/CVE-2024-24785.patch new file mode 100644 index 0000000000..1398a2ca48 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2024-24785.patch @@ -0,0 +1,197 @@ +From 3643147a29352ca2894fd5d0d2069bc4b4335a7e Mon Sep 17 00:00:00 2001 +From: Roland Shoemaker <roland@golang.org> +Date: Wed, 14 Feb 2024 17:18:36 -0800 +Subject: [PATCH] [release-branch.go1.21] html/template: escape additional + tokens in MarshalJSON errors + +Escape "</script" and "<!--" in errors returned from MarshalJSON errors +when attempting to marshal types in script blocks. This prevents any +user controlled content from prematurely terminating the script block. + +Updates #65697 +Fixes #65968 + +Change-Id: Icf0e26c54ea7d9c1deed0bff11b6506c99ddef1b +Reviewed-on: https://go-review.googlesource.com/c/go/+/564196 +LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> +Reviewed-by: Damien Neil <dneil@google.com> +(cherry picked from commit ccbc725f2d678255df1bd326fa511a492aa3a0aa) +Reviewed-on: https://go-review.googlesource.com/c/go/+/567515 +Reviewed-by: Carlos Amedee <carlos@golang.org> + +Upstream-Status: Backport [https://github.com/golang/go/commit/3643147a29352ca2894fd5d0d2069bc4b4335a7e] +CVE: CVE-2024-24785 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + src/html/template/js.go | 22 ++++++++- + src/html/template/js_test.go | 96 ++++++++++++++++++++---------------- + 2 files changed, 74 insertions(+), 44 deletions(-) + +diff --git a/src/html/template/js.go b/src/html/template/js.go +index 35994f0..4d3b25d 100644 +--- a/src/html/template/js.go ++++ b/src/html/template/js.go +@@ -171,13 +171,31 @@ func jsValEscaper(args ...interface{}) string { + // cyclic data. This may be an unacceptable DoS risk. + b, err := json.Marshal(a) + if err != nil { +- // Put a space before comment so that if it is flush against ++ // While the standard JSON marshaller does not include user controlled ++ // information in the error message, if a type has a MarshalJSON method, ++ // the content of the error message is not guaranteed. Since we insert ++ // the error into the template, as part of a comment, we attempt to ++ // prevent the error from either terminating the comment, or the script ++ // block itself. ++ // ++ // In particular we: ++ // * replace "*/" comment end tokens with "* /", which does not ++ // terminate the comment ++ // * replace "</script" with "\x3C/script", and "<!--" with ++ // "\x3C!--", which prevents confusing script block termination ++ // semantics ++ // ++ // We also put a space before the comment so that if it is flush against + // a division operator it is not turned into a line comment: + // x/{{y}} + // turning into + // x//* error marshaling y: + // second line of error message */null +- return fmt.Sprintf(" /* %s */null ", strings.ReplaceAll(err.Error(), "*/", "* /")) ++ errStr := err.Error() ++ errStr = strings.ReplaceAll(errStr, "*/", "* /") ++ errStr = strings.ReplaceAll(errStr, "</script", `\x3C/script`) ++ errStr = strings.ReplaceAll(errStr, "<!--", `\x3C!--`) ++ return fmt.Sprintf(" /* %s */null ", errStr) + } + + // TODO: maybe post-process output to prevent it from containing +diff --git a/src/html/template/js_test.go b/src/html/template/js_test.go +index de9ef28..3fc3baf 100644 +--- a/src/html/template/js_test.go ++++ b/src/html/template/js_test.go +@@ -5,6 +5,7 @@ + package template + + import ( ++ "errors" + "bytes" + "math" + "strings" +@@ -104,61 +105,72 @@ func TestNextJsCtx(t *testing.T) { + } + } + ++type jsonErrType struct{} ++ ++func (e *jsonErrType) MarshalJSON() ([]byte, error) { ++ return nil, errors.New("beep */ boop </script blip <!--") ++} ++ + func TestJSValEscaper(t *testing.T) { + tests := []struct { +- x interface{} +- js string ++ x interface{} ++ js string ++ skipNest bool + }{ +- {int(42), " 42 "}, +- {uint(42), " 42 "}, +- {int16(42), " 42 "}, +- {uint16(42), " 42 "}, +- {int32(-42), " -42 "}, +- {uint32(42), " 42 "}, +- {int16(-42), " -42 "}, +- {uint16(42), " 42 "}, +- {int64(-42), " -42 "}, +- {uint64(42), " 42 "}, +- {uint64(1) << 53, " 9007199254740992 "}, ++ {int(42), " 42 ", false}, ++ {uint(42), " 42 ", false}, ++ {int16(42), " 42 ", false}, ++ {uint16(42), " 42 ", false}, ++ {int32(-42), " -42 ", false}, ++ {uint32(42), " 42 ", false}, ++ {int16(-42), " -42 ", false}, ++ {uint16(42), " 42 ", false}, ++ {int64(-42), " -42 ", false}, ++ {uint64(42), " 42 ", false}, ++ {uint64(1) << 53, " 9007199254740992 ", false}, + // ulp(1 << 53) > 1 so this loses precision in JS + // but it is still a representable integer literal. +- {uint64(1)<<53 + 1, " 9007199254740993 "}, +- {float32(1.0), " 1 "}, +- {float32(-1.0), " -1 "}, +- {float32(0.5), " 0.5 "}, +- {float32(-0.5), " -0.5 "}, +- {float32(1.0) / float32(256), " 0.00390625 "}, +- {float32(0), " 0 "}, +- {math.Copysign(0, -1), " -0 "}, +- {float64(1.0), " 1 "}, +- {float64(-1.0), " -1 "}, +- {float64(0.5), " 0.5 "}, +- {float64(-0.5), " -0.5 "}, +- {float64(0), " 0 "}, +- {math.Copysign(0, -1), " -0 "}, +- {"", `""`}, +- {"foo", `"foo"`}, ++ {uint64(1)<<53 + 1, " 9007199254740993 ", false}, ++ {float32(1.0), " 1 ", false}, ++ {float32(-1.0), " -1 ", false}, ++ {float32(0.5), " 0.5 ", false}, ++ {float32(-0.5), " -0.5 ", false}, ++ {float32(1.0) / float32(256), " 0.00390625 ", false}, ++ {float32(0), " 0 ", false}, ++ {math.Copysign(0, -1), " -0 ", false}, ++ {float64(1.0), " 1 ", false}, ++ {float64(-1.0), " -1 ", false}, ++ {float64(0.5), " 0.5 ", false}, ++ {float64(-0.5), " -0.5 ", false}, ++ {float64(0), " 0 ", false}, ++ {math.Copysign(0, -1), " -0 ", false}, ++ {"", `""`, false}, ++ {"foo", `"foo"`, false}, + // Newlines. +- {"\r\n\u2028\u2029", `"\r\n\u2028\u2029"`}, ++ {"\r\n\u2028\u2029", `"\r\n\u2028\u2029"`, false}, + // "\v" == "v" on IE 6 so use "\u000b" instead. +- {"\t\x0b", `"\t\u000b"`}, +- {struct{ X, Y int }{1, 2}, `{"X":1,"Y":2}`}, +- {[]interface{}{}, "[]"}, +- {[]interface{}{42, "foo", nil}, `[42,"foo",null]`}, +- {[]string{"<!--", "</script>", "-->"}, `["\u003c!--","\u003c/script\u003e","--\u003e"]`}, +- {"<!--", `"\u003c!--"`}, +- {"-->", `"--\u003e"`}, +- {"<![CDATA[", `"\u003c![CDATA["`}, +- {"]]>", `"]]\u003e"`}, +- {"</script", `"\u003c/script"`}, +- {"\U0001D11E", "\"\U0001D11E\""}, // or "\uD834\uDD1E" +- {nil, " null "}, ++ {"\t\x0b", `"\t\u000b"`, false}, ++ {struct{ X, Y int }{1, 2}, `{"X":1,"Y":2}`, false}, ++ {[]interface{}{}, "[]", false}, ++ {[]interface{}{42, "foo", nil}, `[42,"foo",null]`, false}, ++ {[]string{"<!--", "</script>", "-->"}, `["\u003c!--","\u003c/script\u003e","--\u003e"]`, false}, ++ {"<!--", `"\u003c!--"`, false}, ++ {"-->", `"--\u003e"`, false}, ++ {"<![CDATA[", `"\u003c![CDATA["`, false}, ++ {"]]>", `"]]\u003e"`, false}, ++ {"</script", `"\u003c/script"`, false}, ++ {"\U0001D11E", "\"\U0001D11E\"", false}, // or "\uD834\uDD1E" ++ {nil, " null ", false}, ++ {&jsonErrType{}, " /* json: error calling MarshalJSON for type *template.jsonErrType: beep * / boop \\x3C/script blip \\x3C!-- */null ", true}, + } + + for _, test := range tests { + if js := jsValEscaper(test.x); js != test.js { + t.Errorf("%+v: want\n\t%q\ngot\n\t%q", test.x, test.js, js) + } ++ if test.skipNest { ++ continue ++ } + // Make sure that escaping corner cases are not broken + // by nesting. + a := []interface{}{test.x} +-- +2.25.1 + diff --git a/meta/recipes-devtools/go/go-crosssdk.inc b/meta/recipes-devtools/go/go-crosssdk.inc index f0bec79719..36c9b12af8 100644 --- a/meta/recipes-devtools/go/go-crosssdk.inc +++ b/meta/recipes-devtools/go/go-crosssdk.inc @@ -4,6 +4,8 @@ DEPENDS = "go-native virtual/${TARGET_PREFIX}gcc-crosssdk virtual/nativesdk-${TA PN = "go-crosssdk-${SDK_SYS}" PROVIDES = "virtual/${TARGET_PREFIX}go-crosssdk" +export GOCACHE = "${B}/.cache" + do_configure[noexec] = "1" do_compile() { diff --git a/meta/recipes-devtools/go/go-dep_0.5.4.bb b/meta/recipes-devtools/go/go-dep_0.5.4.bb index 0da2c6607c..e29e53433e 100644 --- a/meta/recipes-devtools/go/go-dep_0.5.4.bb +++ b/meta/recipes-devtools/go/go-dep_0.5.4.bb @@ -4,7 +4,7 @@ LICENSE = "BSD-3-Clause" LIC_FILES_CHKSUM = "file://src/${GO_IMPORT}/LICENSE;md5=1bad315647751fab0007812f70d42c0d" GO_IMPORT = "github.com/golang/dep" -SRC_URI = "git://${GO_IMPORT} \ +SRC_URI = "git://${GO_IMPORT};branch=master \ file://0001-Add-support-for-mips-mips64.patch;patchdir=src/github.com/golang/dep \ file://0001-bolt_riscv64-Add-support-for-riscv64.patch;patchdir=src/github.com/golang/dep \ " diff --git a/meta/recipes-devtools/go/go_1.14.bb b/meta/recipes-devtools/go/go_1.14.bb index c17527998b..76ff788238 100644 --- a/meta/recipes-devtools/go/go_1.14.bb +++ b/meta/recipes-devtools/go/go_1.14.bb @@ -7,8 +7,8 @@ export CGO_ENABLED_riscv64 = "" # windows/mips/riscv doesn't support -buildmode=pie, so skip the QA checking # for windows/mips/riscv and their variants. python() { - if 'mips' in d.getVar('TARGET_ARCH',True) or 'riscv' in d.getVar('TARGET_ARCH',True) or 'windows' in d.getVar('TARGET_GOOS', True): - d.appendVar('INSANE_SKIP_%s' % d.getVar('PN',True), " textrel") + if 'mips' in d.getVar('TARGET_ARCH') or 'riscv' in d.getVar('TARGET_ARCH') or 'windows' in d.getVar('TARGET_GOOS'): + d.appendVar('INSANE_SKIP_%s' % d.getVar('PN'), " textrel") else: d.setVar('GOBUILDMODE', 'pie') } diff --git a/meta/recipes-devtools/libcomps/libcomps_0.1.15.bb b/meta/recipes-devtools/libcomps/libcomps_0.1.15.bb index 58d2dee897..d9e712f74a 100644 --- a/meta/recipes-devtools/libcomps/libcomps_0.1.15.bb +++ b/meta/recipes-devtools/libcomps/libcomps_0.1.15.bb @@ -4,7 +4,7 @@ DESCRIPTION = "Libcomps is alternative for yum.comps library. It's written in pu LICENSE = "GPLv2" LIC_FILES_CHKSUM = "file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263" -SRC_URI = "git://github.com/rpm-software-management/libcomps.git \ +SRC_URI = "git://github.com/rpm-software-management/libcomps.git;branch=master;protocol=https \ file://0001-Add-crc32.c-to-sources-list.patch \ file://0002-Do-not-set-PYTHON_INSTALL_DIR-by-running-python.patch \ " diff --git a/meta/recipes-devtools/libdnf/libdnf/0040-Mark-job-goal.upgrade-with-sltr-as-target.patch b/meta/recipes-devtools/libdnf/libdnf/0040-Mark-job-goal.upgrade-with-sltr-as-target.patch new file mode 100644 index 0000000000..61d255581b --- /dev/null +++ b/meta/recipes-devtools/libdnf/libdnf/0040-Mark-job-goal.upgrade-with-sltr-as-target.patch @@ -0,0 +1,58 @@ +From b4c5a3312287f31a2075a235db846ff611586d2c Mon Sep 17 00:00:00 2001 +From: Jaroslav Mracek <jmracek@redhat.com> +Date: Tue, 3 Sep 2019 11:01:23 +0200 +Subject: [PATCH] Mark job goal.upgrade with sltr as targeted + +It allows to keep installed packages in upgrade set. + +It also prevents from reinstalling of modified packages with same NEVRA. + + +Backport commit b4c5a3312287f31a2075a235db846ff611586d2c from +https://github.com/rpm-software-management/libdnf + +This bug is present in oe-core's dnf + +Remove changes to spec file from upstream + +Upstream-Status: Backport +Signed-off-by: Jate Sujjavanich <jatedev@gmail.com> +--- + libdnf.spec | 4 ++-- + libdnf/goal/Goal.cpp | 2 +- + libdnf/goal/Goal.hpp | 6 ++++-- + 3 files changed, 7 insertions(+), 5 deletions(-) + +diff --git a/libdnf/goal/Goal.cpp b/libdnf/goal/Goal.cpp +index b69be19..a38cbb4 100644 +--- a/libdnf/goal/Goal.cpp ++++ b/libdnf/goal/Goal.cpp +@@ -767,7 +767,7 @@ void + Goal::upgrade(HySelector sltr) + { + pImpl->actions = static_cast<DnfGoalActions>(pImpl->actions | DNF_UPGRADE); +- sltrToJob(sltr, &pImpl->staging, SOLVER_UPDATE); ++ sltrToJob(sltr, &pImpl->staging, SOLVER_UPDATE|SOLVER_TARGETED); + } + + void +diff --git a/libdnf/goal/Goal.hpp b/libdnf/goal/Goal.hpp +index f33dfa2..d701317 100644 +--- a/libdnf/goal/Goal.hpp ++++ b/libdnf/goal/Goal.hpp +@@ -86,8 +86,10 @@ public: + /** + * @brief If selector ill formed, it rises std::runtime_error() + * +- * @param sltr p_sltr: It should contain only upgrades with obsoletes otherwise it can try to +- * reinstall installonly packages. ++ * @param sltr p_sltr: It contains upgrade-to packages and obsoletes. The presence of installed ++ * packages prevents reinstalling packages with the same NEVRA but changed contant. To honor repo ++ * priority all relevant packages must be present. To upgrade package foo from priority repo, all ++ * installed and available packages of the foo must be in selector plus obsoletes of foo. + */ + void upgrade(HySelector sltr); + void userInstalled(DnfPackage *pkg); +-- +2.7.4 + diff --git a/meta/recipes-devtools/libdnf/libdnf_0.28.1.bb b/meta/recipes-devtools/libdnf/libdnf_0.28.1.bb index cc7f2be564..39858ad401 100644 --- a/meta/recipes-devtools/libdnf/libdnf_0.28.1.bb +++ b/meta/recipes-devtools/libdnf/libdnf_0.28.1.bb @@ -4,13 +4,14 @@ DESCRIPTION = "This library provides a high level package-manager. It's core lib LICENSE = "LGPLv2.1+" LIC_FILES_CHKSUM = "file://COPYING;md5=4fbd65380cdd255951079008b364516c" -SRC_URI = "git://github.com/rpm-software-management/libdnf \ +SRC_URI = "git://github.com/rpm-software-management/libdnf;branch=master;protocol=https \ file://0001-FindGtkDoc.cmake-drop-the-requirement-for-GTKDOC_SCA.patch \ file://0004-Set-libsolv-variables-with-pkg-config-cmake-s-own-mo.patch \ file://0001-Get-parameters-for-both-libsolv-and-libsolvext-libdn.patch \ file://0001-Add-WITH_TESTS-option.patch \ file://0001-include-stdexcept-for-runtime_error.patch \ file://fix-deprecation-warning.patch \ + file://0040-Mark-job-goal.upgrade-with-sltr-as-target.patch \ " SRCREV = "751f89045b80d58c0d05800f74357cf78cdf7e77" diff --git a/meta/recipes-devtools/librepo/librepo_1.11.2.bb b/meta/recipes-devtools/librepo/librepo_1.11.2.bb index a299514340..73a58f75e3 100644 --- a/meta/recipes-devtools/librepo/librepo_1.11.2.bb +++ b/meta/recipes-devtools/librepo/librepo_1.11.2.bb @@ -5,7 +5,7 @@ DESCRIPTION = "${SUMMARY}" LICENSE = "LGPLv2.1" LIC_FILES_CHKSUM = "file://COPYING;md5=4fbd65380cdd255951079008b364516c" -SRC_URI = "git://github.com/rpm-software-management/librepo.git \ +SRC_URI = "git://github.com/rpm-software-management/librepo.git;branch=master;protocol=https \ file://0002-Do-not-try-to-obtain-PYTHON_INSTALL_DIR-by-running-p.patch \ file://0004-Set-gpgme-variables-with-pkg-config-not-with-cmake-m.patch \ file://CVE-2020-14352.patch \ diff --git a/meta/recipes-devtools/libtool/libtool-2.4.6.inc b/meta/recipes-devtools/libtool/libtool-2.4.6.inc index e9225e140c..c8744e6d5f 100644 --- a/meta/recipes-devtools/libtool/libtool-2.4.6.inc +++ b/meta/recipes-devtools/libtool/libtool-2.4.6.inc @@ -23,6 +23,8 @@ SRC_URI = "${GNU_MIRROR}/libtool/libtool-${PV}.tar.gz \ file://0001-libtool-Check-for-static-libs-for-internal-compiler-.patch \ file://0001-Makefile.am-make-sure-autoheader-run-before-autoconf.patch \ file://0001-Makefile.am-make-sure-autoheader-run-before-automake.patch \ + file://lto-prefix.patch \ + file://debian-no_hostname.patch \ " SRC_URI[md5sum] = "addf44b646ddb4e3919805aa88fa7c5e" diff --git a/meta/recipes-devtools/libtool/libtool/lto-prefix.patch b/meta/recipes-devtools/libtool/libtool/lto-prefix.patch new file mode 100644 index 0000000000..2bd010b8e4 --- /dev/null +++ b/meta/recipes-devtools/libtool/libtool/lto-prefix.patch @@ -0,0 +1,22 @@ +If lto is enabled, we need the prefix-map variables to be passed to the linker. +Add these to the list of options libtool passes through. + +Upstream-Status: Pending +Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org> + +Index: libtool-2.4.6/build-aux/ltmain.in +=================================================================== +--- libtool-2.4.6.orig/build-aux/ltmain.in ++++ libtool-2.4.6/build-aux/ltmain.in +@@ -5424,9 +5424,10 @@ func_mode_link () + # --sysroot=* for sysroot support + # -O*, -g*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization + # -stdlib=* select c++ std lib with clang ++ # -f*-prefix-map* needed for lto linking + -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ + -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ +- -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*) ++ -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*|-f*-prefix-map*) + func_quote_for_eval "$arg" + arg=$func_quote_for_eval_result + func_append compile_command " $arg" diff --git a/meta/recipes-devtools/libtool/libtool_2.4.6.bb b/meta/recipes-devtools/libtool/libtool_2.4.6.bb index a5715faaa9..f5fdd00e5e 100644 --- a/meta/recipes-devtools/libtool/libtool_2.4.6.bb +++ b/meta/recipes-devtools/libtool/libtool_2.4.6.bb @@ -1,6 +1,6 @@ require libtool-${PV}.inc -SRC_URI += "file://multilib.patch file://debian-no_hostname.patch" +SRC_URI += "file://multilib.patch" RDEPENDS_${PN} += "bash" diff --git a/meta/recipes-devtools/llvm/llvm_git.bb b/meta/recipes-devtools/llvm/llvm_git.bb index 534e2c685f..de92cef1a4 100644 --- a/meta/recipes-devtools/llvm/llvm_git.bb +++ b/meta/recipes-devtools/llvm/llvm_git.bb @@ -30,7 +30,7 @@ LLVM_DIR = "llvm${LLVM_RELEASE}" BRANCH = "release/${MAJOR_VERSION}.x" SRCREV = "c1a0a213378a458fbea1a5c77b315c7dce08fd05" -SRC_URI = "git://github.com/llvm/llvm-project.git;branch=${BRANCH} \ +SRC_URI = "git://github.com/llvm/llvm-project.git;branch=${BRANCH};protocol=https \ file://0006-llvm-TargetLibraryInfo-Undefine-libc-functions-if-th.patch;striplevel=2 \ file://0007-llvm-allow-env-override-of-exe-path.patch;striplevel=2 \ file://0001-AsmMatcherEmitter-sort-ClassInfo-lists-by-name-as-we.patch;striplevel=2 \ diff --git a/meta/recipes-devtools/m4/m4-1.4.18.inc b/meta/recipes-devtools/m4/m4-1.4.18.inc index a9b63c1bf6..6475b02f8b 100644 --- a/meta/recipes-devtools/m4/m4-1.4.18.inc +++ b/meta/recipes-devtools/m4/m4-1.4.18.inc @@ -9,6 +9,7 @@ inherit autotools texinfo ptest SRC_URI = "${GNU_MIRROR}/m4/m4-${PV}.tar.gz \ file://ac_config_links.patch \ file://m4-1.4.18-glibc-change-work-around.patch \ + file://0001-c-stack-stop-using-SIGSTKSZ.patch \ " SRC_URI_append_class-target = " file://0001-Unset-need_charset_alias-when-building-for-musl.patch \ file://run-ptest \ diff --git a/meta/recipes-devtools/m4/m4/0001-c-stack-stop-using-SIGSTKSZ.patch b/meta/recipes-devtools/m4/m4/0001-c-stack-stop-using-SIGSTKSZ.patch new file mode 100644 index 0000000000..883b8a2075 --- /dev/null +++ b/meta/recipes-devtools/m4/m4/0001-c-stack-stop-using-SIGSTKSZ.patch @@ -0,0 +1,84 @@ +From 69238f15129f35eb4756ad8e2004e0d7907cb175 Mon Sep 17 00:00:00 2001 +From: Khem Raj <raj.khem@gmail.com> +Date: Fri, 30 Apr 2021 17:40:36 -0700 +Subject: [PATCH] c-stack: stop using SIGSTKSZ + +This patch is required with glibc 2.34+ +based on gnulib [1] + +[1] https://git.savannah.gnu.org/cgit/gnulib.git/commit/?id=f9e2b20a12a230efa30f1d479563ae07d276a94b + +Upstream-Status: Pending +Signed-off-by: Khem Raj <raj.khem@gmail.com> +--- + lib/c-stack.c | 22 +++++++++++++--------- + 1 file changed, 13 insertions(+), 9 deletions(-) + +diff --git a/lib/c-stack.c b/lib/c-stack.c +index 5353c08..863f764 100644 +--- a/lib/c-stack.c ++++ b/lib/c-stack.c +@@ -51,13 +51,14 @@ + typedef struct sigaltstack stack_t; + #endif + #ifndef SIGSTKSZ +-# define SIGSTKSZ 16384 +-#elif HAVE_LIBSIGSEGV && SIGSTKSZ < 16384 ++#define get_sigstksz() (16384) ++#elif HAVE_LIBSIGSEGV + /* libsigsegv 2.6 through 2.8 have a bug where some architectures use + more than the Linux default of an 8k alternate stack when deciding + if a fault was caused by stack overflow. */ +-# undef SIGSTKSZ +-# define SIGSTKSZ 16384 ++#define get_sigstksz() ((SIGSTKSZ) < 16384 ? 16384 : (SIGSTKSZ)) ++#else ++#define get_sigstksz() ((SIGSTKSZ)) + #endif + + #include <stdlib.h> +@@ -131,7 +132,8 @@ die (int signo) + /* Storage for the alternate signal stack. */ + static union + { +- char buffer[SIGSTKSZ]; ++ /* allocate buffer with size from get_sigstksz() */ ++ char *buffer; + + /* These other members are for proper alignment. There's no + standard way to guarantee stack alignment, but this seems enough +@@ -203,10 +205,11 @@ c_stack_action (void (*action) (int)) + program_error_message = _("program error"); + stack_overflow_message = _("stack overflow"); + ++ alternate_signal_stack.buffer = malloc(get_sigstksz()); + /* Always install the overflow handler. */ + if (stackoverflow_install_handler (overflow_handler, + alternate_signal_stack.buffer, +- sizeof alternate_signal_stack.buffer)) ++ get_sigstksz())) + { + errno = ENOTSUP; + return -1; +@@ -279,14 +282,15 @@ c_stack_action (void (*action) (int)) + stack_t st; + struct sigaction act; + st.ss_flags = 0; ++ alternate_signal_stack.buffer = malloc(get_sigstksz()); + # if SIGALTSTACK_SS_REVERSED + /* Irix mistakenly treats ss_sp as the upper bound, rather than + lower bound, of the alternate stack. */ +- st.ss_sp = alternate_signal_stack.buffer + SIGSTKSZ - sizeof (void *); +- st.ss_size = sizeof alternate_signal_stack.buffer - sizeof (void *); ++ st.ss_sp = alternate_signal_stack.buffer + get_sigstksz() - sizeof (void *); ++ st.ss_size = get_sigstksz() - sizeof (void *); + # else + st.ss_sp = alternate_signal_stack.buffer; +- st.ss_size = sizeof alternate_signal_stack.buffer; ++ st.ss_size = get_sigstksz(); + # endif + r = sigaltstack (&st, NULL); + if (r != 0) +-- +2.31.1 + diff --git a/meta/recipes-devtools/mklibs/files/remove-deprecated-exception-specification-cpp17.patch b/meta/recipes-devtools/mklibs/files/remove-deprecated-exception-specification-cpp17.patch new file mode 100644 index 0000000000..f96cc7d302 --- /dev/null +++ b/meta/recipes-devtools/mklibs/files/remove-deprecated-exception-specification-cpp17.patch @@ -0,0 +1,431 @@ +From 597c7a8333df84a87cc48fb8477b603ffbf372a6 Mon Sep 17 00:00:00 2001 +From: Andrej Valek <andrej.valek@siemens.com> +Date: Mon, 23 Aug 2021 12:45:11 +0200 +Subject: [PATCH] feat(cpp17): remove deprecated exception specifications for + C++ 17 + +Upstream-Status: Submitted [https://salsa.debian.org/installer-team/mklibs/-/merge_requests/2] + +based on: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0003r5.html + +Signed-off-by: Andrej Valek <andrej.valek@siemens.com> +--- + src/mklibs-readelf/elf.cpp | 48 ++++++++++++++++++++--------------------- + src/mklibs-readelf/elf.hpp | 18 ++++++++-------- + src/mklibs-readelf/elf_data.hpp | 36 +++++++++++++++---------------- + 3 files changed, 51 insertions(+), 51 deletions(-) + +diff --git a/src/mklibs-readelf/elf.cpp b/src/mklibs-readelf/elf.cpp +index 0e4c0f3..2e6d0f6 100644 +--- a/src/mklibs-readelf/elf.cpp ++++ b/src/mklibs-readelf/elf.cpp +@@ -36,7 +36,7 @@ file::~file () throw () + delete *it; + } + +-file *file::open (const char *filename) throw (std::bad_alloc, std::runtime_error) ++file *file::open (const char *filename) throw () + { + struct stat buf; + int fd; +@@ -72,7 +72,7 @@ file *file::open (const char *filename) throw (std::bad_alloc, std::runtime_erro + } + + template<typename _class> +-file *file::open_class(uint8_t *mem, size_t len) throw (std::bad_alloc, std::runtime_error) ++file *file::open_class(uint8_t *mem, size_t len) throw () + { + switch (mem[EI_DATA]) + { +@@ -86,7 +86,7 @@ file *file::open_class(uint8_t *mem, size_t len) throw (std::bad_alloc, std::run + } + + template <typename _class, typename _data> +-file_data<_class, _data>::file_data(uint8_t *mem, size_t len) throw (std::bad_alloc, std::runtime_error) ++file_data<_class, _data>::file_data(uint8_t *mem, size_t len) throw () + : file(mem, len) + { + if (mem[EI_CLASS] != _class::id) +@@ -190,7 +190,7 @@ section_data<_class, _data>::section_data(Shdr *shdr, uint8_t *mem) throw () + } + + template <typename _class, typename _data> +-void section_data<_class, _data>::update(const file &file) throw (std::bad_alloc) ++void section_data<_class, _data>::update(const file &file) throw () + { + const section_type<section_type_STRTAB> §ion = + dynamic_cast<const section_type<section_type_STRTAB> &>(file.get_section(file.get_shstrndx())); +@@ -204,7 +204,7 @@ section_type<section_type_DYNAMIC>::~section_type() throw () + } + + template <typename _class, typename _data> +-section_real<_class, _data, section_type_DYNAMIC>::section_real(Shdr *header, uint8_t *mem) throw (std::bad_alloc) ++section_real<_class, _data, section_type_DYNAMIC>::section_real(Shdr *header, uint8_t *mem) throw () + : section_data<_class, _data>(header, mem) + { + if (this->type != SHT_DYNAMIC) +@@ -221,7 +221,7 @@ section_real<_class, _data, section_type_DYNAMIC>::section_real(Shdr *header, ui + } + + template <typename _class, typename _data> +-void section_real<_class, _data, section_type_DYNAMIC>::update(const file &file) throw (std::bad_alloc) ++void section_real<_class, _data, section_type_DYNAMIC>::update(const file &file) throw () + { + section_data<_class, _data>::update(file); + +@@ -243,7 +243,7 @@ section_type<section_type_DYNSYM>::~section_type() throw () + } + + template <typename _class, typename _data> +-section_real<_class, _data, section_type_DYNSYM>::section_real(Shdr *header, uint8_t *mem) throw (std::bad_alloc) ++section_real<_class, _data, section_type_DYNSYM>::section_real(Shdr *header, uint8_t *mem) throw () + : section_data<_class, _data>(header, mem) + { + if (this->type != SHT_DYNSYM) +@@ -260,7 +260,7 @@ section_real<_class, _data, section_type_DYNSYM>::section_real(Shdr *header, uin + } + + template <typename _class, typename _data> +-void section_real<_class, _data, section_type_DYNSYM>::update(const file &file) throw (std::bad_alloc) ++void section_real<_class, _data, section_type_DYNSYM>::update(const file &file) throw () + { + section_data<_class, _data>::update (file); + +@@ -285,7 +285,7 @@ const version_definition *section_type<section_type_GNU_VERDEF>::get_version_def + } + + template <typename _class, typename _data> +-section_real<_class, _data, section_type_GNU_VERDEF>::section_real(Shdr *header, uint8_t *mem) throw (std::bad_alloc) ++section_real<_class, _data, section_type_GNU_VERDEF>::section_real(Shdr *header, uint8_t *mem) throw () + : section_data<_class, _data>(header, mem) + { + if (this->type != SHT_GNU_verdef) +@@ -307,7 +307,7 @@ section_real<_class, _data, section_type_GNU_VERDEF>::section_real(Shdr *header, + } + + template <typename _class, typename _data> +-void section_real<_class, _data, section_type_GNU_VERDEF>::update(const file &file) throw (std::bad_alloc) ++void section_real<_class, _data, section_type_GNU_VERDEF>::update(const file &file) throw () + { + section_data<_class, _data>::update(file); + +@@ -333,7 +333,7 @@ const version_requirement_entry *section_type<section_type_GNU_VERNEED>::get_ver + + template <typename _class, typename _data> + section_real<_class, _data, section_type_GNU_VERNEED>:: +-section_real(Shdr *header, uint8_t *mem) throw (std::bad_alloc) ++section_real(Shdr *header, uint8_t *mem) throw () + : section_data<_class, _data> (header, mem) + { + if (this->type != SHT_GNU_verneed) +@@ -355,7 +355,7 @@ section_real(Shdr *header, uint8_t *mem) throw (std::bad_alloc) + } + + template <typename _class, typename _data> +-void section_real<_class, _data, section_type_GNU_VERNEED>::update(const file &file) throw (std::bad_alloc) ++void section_real<_class, _data, section_type_GNU_VERNEED>::update(const file &file) throw () + { + section_data<_class, _data>::update(file); + +@@ -372,7 +372,7 @@ void section_real<_class, _data, section_type_GNU_VERNEED>::update(const file &f + + template <typename _class, typename _data> + section_real<_class, _data, section_type_GNU_VERSYM>:: +-section_real (Shdr *header, uint8_t *mem) throw (std::bad_alloc) ++section_real (Shdr *header, uint8_t *mem) throw () + : section_data<_class, _data> (header, mem) + { + if (this->type != SHT_GNU_versym) +@@ -399,7 +399,7 @@ segment_data<_class, _data>::segment_data (Phdr *phdr, uint8_t *mem) throw () + } + + template <typename _class, typename _data> +-segment_real<_class, _data, segment_type_INTERP>::segment_real (Phdr *header, uint8_t *mem) throw (std::bad_alloc) ++segment_real<_class, _data, segment_type_INTERP>::segment_real (Phdr *header, uint8_t *mem) throw () + : segment_data<_class, _data> (header, mem) + { + if (this->type != PT_INTERP) +@@ -429,13 +429,13 @@ dynamic_data<_class, _data>::dynamic_data (Dyn *dyn) throw () + } + + template <typename _class, typename _data> +-void dynamic_data<_class, _data>::update_string(const section_type<section_type_STRTAB> §ion) throw (std::bad_alloc) ++void dynamic_data<_class, _data>::update_string(const section_type<section_type_STRTAB> §ion) throw () + { + if (is_string) + val_string = section.get_string(val); + } + +-std::string symbol::get_version () const throw (std::bad_alloc) ++std::string symbol::get_version () const throw () + { + if (verneed) + return verneed->get_name(); +@@ -445,7 +445,7 @@ std::string symbol::get_version () const throw (std::bad_alloc) + return "Base"; + } + +-std::string symbol::get_version_file () const throw (std::bad_alloc) ++std::string symbol::get_version_file () const throw () + { + if (verneed) + return verneed->get_file(); +@@ -453,7 +453,7 @@ std::string symbol::get_version_file () const throw (std::bad_alloc) + return "None"; + } + +-std::string symbol::get_name_version () const throw (std::bad_alloc) ++std::string symbol::get_name_version () const throw () + { + std::string ver; + +@@ -478,13 +478,13 @@ symbol_data<_class, _data>::symbol_data (Sym *sym) throw () + } + + template <typename _class, typename _data> +-void symbol_data<_class, _data>::update_string(const section_type<section_type_STRTAB> §ion) throw (std::bad_alloc) ++void symbol_data<_class, _data>::update_string(const section_type<section_type_STRTAB> §ion) throw () + { + name_string = section.get_string(name); + } + + template <typename _class, typename _data> +-void symbol_data<_class, _data>::update_version(const file &file, uint16_t index) throw (std::bad_alloc) ++void symbol_data<_class, _data>::update_version(const file &file, uint16_t index) throw () + { + if (!file.get_section_GNU_VERSYM()) + return; +@@ -531,13 +531,13 @@ version_definition_data<_class, _data>::version_definition_data (Verdef *verdef) + } + + template <typename _class, typename _data> +-void version_definition_data<_class, _data>::update_string(const section_type<section_type_STRTAB> §ion) throw (std::bad_alloc) ++void version_definition_data<_class, _data>::update_string(const section_type<section_type_STRTAB> §ion) throw () + { + for (std::vector<uint32_t>::iterator it = names.begin(); it != names.end(); ++it) + names_string.push_back(section.get_string(*it)); + } + +-version_requirement::version_requirement() throw (std::bad_alloc) ++version_requirement::version_requirement() throw () + : file_string("None") + { } + +@@ -561,7 +561,7 @@ version_requirement_data<_class, _data>::version_requirement_data (Verneed *vern + + template <typename _class, typename _data> + void version_requirement_data<_class, _data>:: +-update_string(const section_type<section_type_STRTAB> §ion) throw (std::bad_alloc) ++update_string(const section_type<section_type_STRTAB> §ion) throw () + { + file_string = section.get_string(file); + +@@ -596,7 +596,7 @@ version_requirement_entry_data(Vernaux *vna, const version_requirement &verneed) + + template <typename _class, typename _data> + void version_requirement_entry_data<_class, _data>:: +-update_string(const section_type<section_type_STRTAB> §ion) throw (std::bad_alloc) ++update_string(const section_type<section_type_STRTAB> §ion) throw () + { + name_string = section.get_string(name); + } +diff --git a/src/mklibs-readelf/elf.hpp b/src/mklibs-readelf/elf.hpp +index 70e61cd..afb0c9e 100644 +--- a/src/mklibs-readelf/elf.hpp ++++ b/src/mklibs-readelf/elf.hpp +@@ -49,7 +49,7 @@ namespace Elf + const uint16_t get_shstrndx() const throw () { return shstrndx; } + + const std::vector<section *> get_sections() const throw () { return sections; }; +- const section &get_section(unsigned int i) const throw (std::out_of_range) { return *sections.at(i); }; ++ const section &get_section(unsigned int i) const throw () { return *sections.at(i); }; + const section_type<section_type_DYNAMIC> *get_section_DYNAMIC() const throw () { return section_DYNAMIC; }; + const section_type<section_type_DYNSYM> *get_section_DYNSYM() const throw () { return section_DYNSYM; }; + const section_type<section_type_GNU_VERDEF> *get_section_GNU_VERDEF() const throw () { return section_GNU_VERDEF; }; +@@ -59,13 +59,13 @@ namespace Elf + const std::vector<segment *> get_segments() const throw () { return segments; }; + const segment_type<segment_type_INTERP> *get_segment_INTERP() const throw () { return segment_INTERP; }; + +- static file *open(const char *filename) throw (std::bad_alloc, std::runtime_error); ++ static file *open(const char *filename) throw (); + + protected: +- file(uint8_t *mem, size_t len) throw (std::bad_alloc) : mem(mem), len(len) { } ++ file(uint8_t *mem, size_t len) throw () : mem(mem), len(len) { } + + template<typename _class> +- static file *open_class(uint8_t *, size_t) throw (std::bad_alloc, std::runtime_error); ++ static file *open_class(uint8_t *, size_t) throw (); + + uint16_t type; + uint16_t machine; +@@ -128,7 +128,7 @@ namespace Elf + class section_type<section_type_STRTAB> : public virtual section + { + public: +- std::string get_string(uint32_t offset) const throw (std::bad_alloc) ++ std::string get_string(uint32_t offset) const throw () + { + return std::string(reinterpret_cast<const char *> (mem + offset)); + } +@@ -263,10 +263,10 @@ namespace Elf + uint8_t get_bind () const throw () { return bind; } + uint8_t get_type () const throw () { return type; } + const std::string &get_name_string() const throw () { return name_string; } +- std::string get_version() const throw (std::bad_alloc); +- std::string get_version_file() const throw (std::bad_alloc); ++ std::string get_version() const throw (); ++ std::string get_version_file() const throw (); + uint16_t get_version_data() const throw () { return versym; } +- std::string get_name_version() const throw (std::bad_alloc); ++ std::string get_name_version() const throw (); + + protected: + uint32_t name; +@@ -305,7 +305,7 @@ namespace Elf + class version_requirement + { + public: +- version_requirement() throw (std::bad_alloc); ++ version_requirement() throw (); + virtual ~version_requirement () throw () { } + + const std::string &get_file() const throw () { return file_string; } +diff --git a/src/mklibs-readelf/elf_data.hpp b/src/mklibs-readelf/elf_data.hpp +index 05effee..3871982 100644 +--- a/src/mklibs-readelf/elf_data.hpp ++++ b/src/mklibs-readelf/elf_data.hpp +@@ -94,7 +94,7 @@ namespace Elf + class file_data : public file + { + public: +- file_data(uint8_t *, size_t len) throw (std::bad_alloc, std::runtime_error); ++ file_data(uint8_t *, size_t len) throw (); + + const uint8_t get_class() const throw () { return _class::id; } + const uint8_t get_data() const throw () { return _data::id; } +@@ -109,7 +109,7 @@ namespace Elf + public: + section_data(Shdr *, uint8_t *) throw (); + +- virtual void update(const file &) throw (std::bad_alloc); ++ virtual void update(const file &) throw (); + }; + + template <typename _class, typename _data, typename _type> +@@ -133,9 +133,9 @@ namespace Elf + typedef typename _elfdef<_class>::Shdr Shdr; + + public: +- section_real(Shdr *, uint8_t *) throw (std::bad_alloc); ++ section_real(Shdr *, uint8_t *) throw (); + +- void update(const file &) throw (std::bad_alloc); ++ void update(const file &) throw (); + }; + + template <typename _class, typename _data> +@@ -147,9 +147,9 @@ namespace Elf + typedef typename _elfdef<_class>::Shdr Shdr; + + public: +- section_real(Shdr *, uint8_t *) throw (std::bad_alloc); ++ section_real(Shdr *, uint8_t *) throw (); + +- void update(const file &) throw (std::bad_alloc); ++ void update(const file &) throw (); + }; + + template <typename _class, typename _data> +@@ -161,9 +161,9 @@ namespace Elf + typedef typename _elfdef<_class>::Shdr Shdr; + + public: +- section_real(Shdr *, uint8_t *) throw (std::bad_alloc); ++ section_real(Shdr *, uint8_t *) throw (); + +- void update(const file &) throw (std::bad_alloc); ++ void update(const file &) throw (); + }; + + template <typename _class, typename _data> +@@ -175,9 +175,9 @@ namespace Elf + typedef typename _elfdef<_class>::Shdr Shdr; + + public: +- section_real(Shdr *, uint8_t *) throw (std::bad_alloc); ++ section_real(Shdr *, uint8_t *) throw (); + +- void update(const file &) throw (std::bad_alloc); ++ void update(const file &) throw (); + }; + + template <typename _class, typename _data> +@@ -189,7 +189,7 @@ namespace Elf + typedef typename _elfdef<_class>::Shdr Shdr; + + public: +- section_real(Shdr *, uint8_t *) throw (std::bad_alloc); ++ section_real(Shdr *, uint8_t *) throw (); + }; + + template <typename _class, typename _data> +@@ -220,7 +220,7 @@ namespace Elf + typedef typename _elfdef<_class>::Phdr Phdr; + + public: +- segment_real (Phdr *, uint8_t *) throw (std::bad_alloc); ++ segment_real (Phdr *, uint8_t *) throw (); + }; + + template <typename _class, typename _data> +@@ -232,7 +232,7 @@ namespace Elf + public: + dynamic_data (Dyn *) throw (); + +- void update_string(const section_type<section_type_STRTAB> &) throw (std::bad_alloc); ++ void update_string(const section_type<section_type_STRTAB> &) throw (); + }; + + template <typename _class, typename _data> +@@ -244,8 +244,8 @@ namespace Elf + public: + symbol_data (Sym *) throw (); + +- void update_string(const section_type<section_type_STRTAB> &) throw (std::bad_alloc); +- virtual void update_version (const file &, uint16_t) throw (std::bad_alloc); ++ void update_string(const section_type<section_type_STRTAB> &) throw (); ++ virtual void update_version (const file &, uint16_t) throw (); + }; + + template <typename _class, typename _data> +@@ -257,7 +257,7 @@ namespace Elf + + version_definition_data (Verdef *) throw (); + +- void update_string(const section_type<section_type_STRTAB> &) throw (std::bad_alloc); ++ void update_string(const section_type<section_type_STRTAB> &) throw (); + }; + + template <typename _class, typename _data> +@@ -269,7 +269,7 @@ namespace Elf + + version_requirement_data (Verneed *) throw (); + +- void update_string(const section_type<section_type_STRTAB> &) throw (std::bad_alloc); ++ void update_string(const section_type<section_type_STRTAB> &) throw (); + }; + + template <typename _class, typename _data> +@@ -280,7 +280,7 @@ namespace Elf + + version_requirement_entry_data (Vernaux *, const version_requirement &) throw (); + +- void update_string(const section_type<section_type_STRTAB> &) throw (std::bad_alloc); ++ void update_string(const section_type<section_type_STRTAB> &) throw (); + }; + } + +-- +2.11.0 + diff --git a/meta/recipes-devtools/mklibs/mklibs-native_0.1.44.bb b/meta/recipes-devtools/mklibs/mklibs-native_0.1.44.bb index 1784af1f4c..07142e57e0 100644 --- a/meta/recipes-devtools/mklibs/mklibs-native_0.1.44.bb +++ b/meta/recipes-devtools/mklibs/mklibs-native_0.1.44.bb @@ -12,6 +12,7 @@ SRC_URI = "http://snapshot.debian.org/archive/debian/20180828T214102Z/pool/main/ file://avoid-failure-on-symbol-provided-by-application.patch \ file://show-GNU-unique-symbols-as-provided-symbols.patch \ file://fix_cross_compile.patch \ + file://remove-deprecated-exception-specification-cpp17.patch \ " SRC_URI[md5sum] = "6b6eeb9b4016c6a7317acc28c89e32cc" diff --git a/meta/recipes-devtools/mtd/mtd-utils/0001-mtd-utils-Fix-return-value-of-ubiformat.patch b/meta/recipes-devtools/mtd/mtd-utils/0001-mtd-utils-Fix-return-value-of-ubiformat.patch deleted file mode 100644 index d43f7e1a7a..0000000000 --- a/meta/recipes-devtools/mtd/mtd-utils/0001-mtd-utils-Fix-return-value-of-ubiformat.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 4d19bffcfd66e25d3ee74536ae2d2da7ad52e8e2 Mon Sep 17 00:00:00 2001 -From: Barry Grussling <barry@grussling.com> -Date: Sun, 12 Jan 2020 12:33:32 -0800 -Subject: [PATCH] mtd-utils: Fix return value of ubiformat -Organization: O.S. Systems Software LTDA. - -This changeset fixes a feature regression in ubiformat. Older versions of -ubiformat, when invoked with a flash-image, would return 0 in the case no error -was encountered. Upon upgrading to latest, it was discovered that ubiformat -returned 255 even without encountering an error condition. - -This changeset corrects the above issue and causes ubiformat, when given an -image file, to return 0 when no errors are detected. - -Tested by running through my loading scripts and verifying ubiformat returned -0. - -Upstream-Status: Backport [2.1.2] - -Signed-off-by: Barry Grussling <barry@grussling.com> -Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at> -Signed-off-by: Otavio Salvador <otavio@ossystems.com.br> ---- - ubi-utils/ubiformat.c | 7 +++++-- - 1 file changed, 5 insertions(+), 2 deletions(-) - -diff --git a/ubi-utils/ubiformat.c b/ubi-utils/ubiformat.c -index a90627c..5377b12 100644 ---- a/ubi-utils/ubiformat.c -+++ b/ubi-utils/ubiformat.c -@@ -550,6 +550,7 @@ static int format(libmtd_t libmtd, const struct mtd_dev_info *mtd, - struct ubi_vtbl_record *vtbl; - int eb1 = -1, eb2 = -1; - long long ec1 = -1, ec2 = -1; -+ int ret = -1; - - write_size = UBI_EC_HDR_SIZE + mtd->subpage_size - 1; - write_size /= mtd->subpage_size; -@@ -643,8 +644,10 @@ static int format(libmtd_t libmtd, const struct mtd_dev_info *mtd, - if (!args.quiet && !args.verbose) - printf("\n"); - -- if (novtbl) -+ if (novtbl) { -+ ret = 0; - goto out_free; -+ } - - if (eb1 == -1 || eb2 == -1) { - errmsg("no eraseblocks for volume table"); -@@ -669,7 +672,7 @@ static int format(libmtd_t libmtd, const struct mtd_dev_info *mtd, - - out_free: - free(hdr); -- return -1; -+ return ret; - } - - int main(int argc, char * const argv[]) --- -2.27.0 - diff --git a/meta/recipes-devtools/mtd/mtd-utils_git.bb b/meta/recipes-devtools/mtd/mtd-utils_git.bb index 9c05dc03dc..fa42770ee4 100644 --- a/meta/recipes-devtools/mtd/mtd-utils_git.bb +++ b/meta/recipes-devtools/mtd/mtd-utils_git.bb @@ -11,18 +11,15 @@ inherit autotools pkgconfig update-alternatives DEPENDS = "zlib e2fsprogs util-linux" RDEPENDS_mtd-utils-tests += "bash" -PV = "2.1.1" +PV = "2.1.3" -SRCREV = "4443221ce9b88440cd9f5bb78e6fe95621d36c8a" -SRC_URI = "git://git.infradead.org/mtd-utils.git \ +SRCREV = "42ea7cd48d2b3c306d59bb6c530d79f8c25bf9f5" +SRC_URI = "git://git.infradead.org/mtd-utils.git;branch=master \ file://add-exclusion-to-mkfs-jffs2-git-2.patch \ - file://0001-mtd-utils-Fix-return-value-of-ubiformat.patch \ -" + " S = "${WORKDIR}/git/" -EXTRA_OECONF += "--enable-install-tests" - # xattr support creates an additional compile-time dependency on acl because # the sys/acl.h header is needed. libacl is not needed and thus enabling xattr # regardless whether acl is enabled or disabled in the distro should be okay. diff --git a/meta/recipes-devtools/nasm/nasm/0002-Add-debug-prefix-map-option.patch b/meta/recipes-devtools/nasm/nasm/0002-Add-debug-prefix-map-option.patch index f788e0fd43..9f4c8dc0bd 100644 --- a/meta/recipes-devtools/nasm/nasm/0002-Add-debug-prefix-map-option.patch +++ b/meta/recipes-devtools/nasm/nasm/0002-Add-debug-prefix-map-option.patch @@ -1,4 +1,4 @@ -From bb4e42ad3a0cdd23a1d1797e6299c76b474867c0 Mon Sep 17 00:00:00 2001 +From 81d6519499dcfebe7d21e65e002a8885a4e8d852 Mon Sep 17 00:00:00 2001 From: Joshua Watt <JPEWhacker@gmail.com> Date: Tue, 19 Nov 2019 13:12:17 -0600 Subject: [PATCH] Add --debug-prefix-map option @@ -11,7 +11,7 @@ Upstream-Status: Submitted [https://bugzilla.nasm.us/show_bug.cgi?id=3392635] Signed-off-by: Joshua Watt <JPEWhacker@gmail.com> --- - asm/nasm.c | 26 +++++++++++++++++++++++++- + asm/nasm.c | 24 ++++++++++++++++++++++++ include/nasmlib.h | 9 +++++++++ nasm.txt | 4 ++++ nasmlib/filename.c | 20 ++++++++++++++++++++ @@ -23,34 +23,32 @@ Signed-off-by: Joshua Watt <JPEWhacker@gmail.com> stdlib/strlcat.c | 2 +- test/elfdebugprefix.asm | 6 ++++++ test/performtest.pl | 12 ++++++++++-- - 12 files changed, 83 insertions(+), 10 deletions(-) + 12 files changed, 82 insertions(+), 9 deletions(-) create mode 100644 test/elfdebugprefix.asm diff --git a/asm/nasm.c b/asm/nasm.c -index a0e1719..fc6c62e 100644 +index e5ae89a..7a7f8b4 100644 --- a/asm/nasm.c +++ b/asm/nasm.c -@@ -938,7 +938,8 @@ enum text_options { - OPT_LIMIT, +@@ -939,6 +939,7 @@ enum text_options { OPT_KEEP_ALL, OPT_NO_LINE, -- OPT_DEBUG -+ OPT_DEBUG, -+ OPT_DEBUG_PREFIX_MAP + OPT_DEBUG, ++ OPT_DEBUG_PREFIX_MAP, + OPT_REPRODUCIBLE }; enum need_arg { - ARG_NO, -@@ -970,6 +971,7 @@ static const struct textargs textopts[] = { +@@ -971,6 +972,7 @@ static const struct textargs textopts[] = { {"keep-all", OPT_KEEP_ALL, ARG_NO, 0}, {"no-line", OPT_NO_LINE, ARG_NO, 0}, {"debug", OPT_DEBUG, ARG_MAYBE, 0}, + {"debug-prefix-map", OPT_DEBUG_PREFIX_MAP, true, 0}, + {"reproducible", OPT_REPRODUCIBLE, ARG_NO, 0}, {NULL, OPT_BOGUS, ARG_NO, 0} }; - -@@ -1332,6 +1334,26 @@ static bool process_arg(char *p, char *q, int pass) - case OPT_DEBUG: - debug_nasm = param ? strtoul(param, NULL, 10) : debug_nasm+1; +@@ -1337,6 +1339,26 @@ static bool process_arg(char *p, char *q, int pass) + case OPT_REPRODUCIBLE: + reproducible = true; break; + case OPT_DEBUG_PREFIX_MAP: { + struct debug_prefix_list *d; @@ -75,7 +73,7 @@ index a0e1719..fc6c62e 100644 case OPT_HELP: help(stdout); exit(0); -@@ -2297,6 +2319,8 @@ static void help(FILE *out) +@@ -2304,6 +2326,8 @@ static void help(FILE *out) " -w-x disable warning x (also -Wno-x)\n" " -w[+-]error promote all warnings to errors (also -Werror)\n" " -w[+-]error=x promote warning x to errors (also -Werror=x)\n" @@ -85,7 +83,7 @@ index a0e1719..fc6c62e 100644 fprintf(out, " %-20s %s\n", diff --git a/include/nasmlib.h b/include/nasmlib.h -index e9bfbcc..98fc653 100644 +index 438178d..4c3e90d 100644 --- a/include/nasmlib.h +++ b/include/nasmlib.h @@ -250,10 +250,19 @@ int64_t readstrnum(char *str, int length, bool *warn); @@ -181,10 +179,10 @@ index 54b22f8..c4a412c 100644 static void as86_cleanup(void) diff --git a/output/outcoff.c b/output/outcoff.c -index bcd9ff3..15bfcf3 100644 +index 58fa024..14baf7b 100644 --- a/output/outcoff.c +++ b/output/outcoff.c -@@ -1095,14 +1095,14 @@ static void coff_symbol(char *name, int32_t strpos, int32_t value, +@@ -1072,14 +1072,14 @@ static void coff_symbol(char *name, int32_t strpos, int32_t value, static void coff_write_symbols(void) { @@ -215,7 +213,7 @@ index 61af020..1292958 100644 nsects = sectlen = 0; syms = saa_init((int32_t)sizeof(struct elf_symbol)); diff --git a/output/outieee.c b/output/outieee.c -index 4cc0f0f..2468724 100644 +index 6d6d4b2..cdb8333 100644 --- a/output/outieee.c +++ b/output/outieee.c @@ -207,7 +207,7 @@ static void ieee_unqualified_name(char *, char *); @@ -228,10 +226,10 @@ index 4cc0f0f..2468724 100644 fpubhead = NULL; fpubtail = &fpubhead; diff --git a/output/outobj.c b/output/outobj.c -index 0d4d311..d8dd6a0 100644 +index 56b43f9..fefea94 100644 --- a/output/outobj.c +++ b/output/outobj.c -@@ -638,7 +638,7 @@ static enum directive_result obj_directive(enum directive, char *); +@@ -644,7 +644,7 @@ static enum directive_result obj_directive(enum directive, char *); static void obj_init(void) { diff --git a/meta/recipes-devtools/nasm/nasm/CVE-2022-44370.patch b/meta/recipes-devtools/nasm/nasm/CVE-2022-44370.patch new file mode 100644 index 0000000000..1bd49c9fd9 --- /dev/null +++ b/meta/recipes-devtools/nasm/nasm/CVE-2022-44370.patch @@ -0,0 +1,104 @@ +From b37677f7e40276bd8f504584bcba2c092f1146a8 Mon Sep 17 00:00:00 2001 +From: "H. Peter Anvin" <hpa@zytor.com> +Date: Mon, 7 Nov 2022 10:26:03 -0800 +Subject: [PATCH] quote_for_pmake: fix counter underrun resulting in segfault + +while (nbs--) { ... } ends with nbs == -1. Rather than a minimal fix, +introduce mempset() to make these kinds of errors less likely in the +future. + +Fixes: https://bugzilla.nasm.us/show_bug.cgi?id=3392815 +Reported-by: <13579and24680@gmail.com> +Signed-off-by: H. Peter Anvin <hpa@zytor.com> + +Upstream-Status: Backport +CVE: CVE-2022-4437 + +Reference to upstream patch: +[https://github.com/netwide-assembler/nasm/commit/2d4e6952417ec6f08b6f135d2b5d0e19b7dae30d] + +Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com> +--- + asm/nasm.c | 12 +++++------- + configure.ac | 1 + + include/compiler.h | 7 +++++++ + 3 files changed, 13 insertions(+), 7 deletions(-) + +diff --git a/asm/nasm.c b/asm/nasm.c +index 7a7f8b4..675cff4 100644 +--- a/asm/nasm.c ++++ b/asm/nasm.c +@@ -1,6 +1,6 @@ + /* ----------------------------------------------------------------------- * + * +- * Copyright 1996-2020 The NASM Authors - All Rights Reserved ++ * Copyright 1996-2022 The NASM Authors - All Rights Reserved + * See the file AUTHORS included with the NASM distribution for + * the specific copyright holders. + * +@@ -814,8 +814,7 @@ static char *quote_for_pmake(const char *str) + } + + /* Convert N backslashes at the end of filename to 2N backslashes */ +- if (nbs) +- n += nbs; ++ n += nbs; + + os = q = nasm_malloc(n); + +@@ -824,10 +823,10 @@ static char *quote_for_pmake(const char *str) + switch (*p) { + case ' ': + case '\t': +- while (nbs--) +- *q++ = '\\'; ++ q = mempset(q, '\\', nbs); + *q++ = '\\'; + *q++ = *p; ++ nbs = 0; + break; + case '$': + *q++ = *p; +@@ -849,9 +848,8 @@ static char *quote_for_pmake(const char *str) + break; + } + } +- while (nbs--) +- *q++ = '\\'; + ++ q = mempset(q, '\\', nbs); + *q = '\0'; + + return os; +diff --git a/configure.ac b/configure.ac +index 39680b1..940ebe2 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -199,6 +199,7 @@ AC_CHECK_FUNCS(strrchrnul) + AC_CHECK_FUNCS(iscntrl) + AC_CHECK_FUNCS(isascii) + AC_CHECK_FUNCS(mempcpy) ++AC_CHECK_FUNCS(mempset) + + AC_CHECK_FUNCS(getuid) + AC_CHECK_FUNCS(getgid) +diff --git a/include/compiler.h b/include/compiler.h +index db3d6d6..b64da6a 100644 +--- a/include/compiler.h ++++ b/include/compiler.h +@@ -256,6 +256,13 @@ static inline void *mempcpy(void *dst, const void *src, size_t n) + } + #endif + ++#ifndef HAVE_MEMPSET ++static inline void *mempset(void *dst, int c, size_t n) ++{ ++ return (char *)memset(dst, c, n) + n; ++} ++#endif ++ + /* + * Hack to support external-linkage inline functions + */ +-- +2.40.0 diff --git a/meta/recipes-devtools/nasm/nasm_2.15.03.bb b/meta/recipes-devtools/nasm/nasm_2.15.05.bb index fc7046244a..c5638debdd 100644 --- a/meta/recipes-devtools/nasm/nasm_2.15.03.bb +++ b/meta/recipes-devtools/nasm/nasm_2.15.05.bb @@ -8,13 +8,14 @@ LIC_FILES_CHKSUM = "file://LICENSE;md5=90904486f8fbf1861cf42752e1a39efe" SRC_URI = "http://www.nasm.us/pub/nasm/releasebuilds/${PV}/nasm-${PV}.tar.bz2 \ file://0001-stdlib-Add-strlcat.patch \ file://0002-Add-debug-prefix-map-option.patch \ + file://CVE-2022-44370.patch \ " -SRC_URI[sha256sum] = "04e7343d9bf112bffa9fda86f6c7c8b120c2ccd700b882e2db9f57484b1bd778" +SRC_URI[sha256sum] = "3c4b8339e5ab54b1bcb2316101f8985a5da50a3f9e504d43fa6f35668bee2fd0" EXTRA_AUTORECONF_append = " -I autoconf/m4" -inherit autotools +inherit autotools-brokensep BBCLASSEXTEND = "native" diff --git a/meta/recipes-devtools/ninja/ninja_1.10.0.bb b/meta/recipes-devtools/ninja/ninja_1.10.0.bb index c02b876c02..755b73a173 100644 --- a/meta/recipes-devtools/ninja/ninja_1.10.0.bb +++ b/meta/recipes-devtools/ninja/ninja_1.10.0.bb @@ -8,7 +8,7 @@ DEPENDS = "re2c-native ninja-native" SRCREV = "ed7f67040b370189d989adbd60ff8ea29957231f" -SRC_URI = "git://github.com/ninja-build/ninja.git;branch=release" +SRC_URI = "git://github.com/ninja-build/ninja.git;branch=release;protocol=https" UPSTREAM_CHECK_GITTAGREGEX = "v(?P<pver>.*)" S = "${WORKDIR}/git" @@ -29,3 +29,6 @@ do_install() { } BBCLASSEXTEND = "native nativesdk" + +# This is a different Ninja +CVE_CHECK_WHITELIST += "CVE-2021-4336" diff --git a/meta/recipes-devtools/opkg/opkg/0001-file_util.c-fix-possible-bad-memory-access-in-file_r.patch b/meta/recipes-devtools/opkg/opkg/0001-file_util.c-fix-possible-bad-memory-access-in-file_r.patch new file mode 100644 index 0000000000..bec21e67f4 --- /dev/null +++ b/meta/recipes-devtools/opkg/opkg/0001-file_util.c-fix-possible-bad-memory-access-in-file_r.patch @@ -0,0 +1,50 @@ +From 8b45a3c4cab95382beea1ecdddeb2e4a9ed14aba Mon Sep 17 00:00:00 2001 +From: Jo-Philipp Wich <jo@mein.io> +Date: Wed, 1 Apr 2020 21:47:40 +0200 +Subject: [PATCH 001/104] file_util.c: fix possible bad memory access in + file_read_line_alloc() + +In the case of a zero length string being returned by fgets(), the condition +checking for a trailing new line would perform a bad memory access outside +of `buf`. This might happen when line with a leading null byte is read. + +Avoid this case by checking that the string has a length of at least one +byte. Also change the unsigned int types to size_t to store length values +while we're at it. + +Upstream-Status: Backport [https://github.com/ndmsystems/opkg/commit/8b45a3c4cab95382beea1ecdddeb2e4a9ed14aba] + +Signed-off-by: Jo-Philipp Wich <jo@mein.io> +Signed-off-by: Alejandro del Castillo <alejandro.delcastillo@ni.com> +Signed-off-by: virendra thakur <virendrak@kpit.com> +--- + libopkg/file_util.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/libopkg/file_util.c b/libopkg/file_util.c +index fbed7b4..ee9f59d 100644 +--- a/libopkg/file_util.c ++++ b/libopkg/file_util.c +@@ -127,17 +127,14 @@ char *file_readlink_alloc(const char *file_name) + */ + char *file_read_line_alloc(FILE * fp) + { ++ size_t buf_len, line_size; + char buf[BUFSIZ]; +- unsigned int buf_len; + char *line = NULL; +- unsigned int line_size = 0; + int got_nl = 0; + +- buf[0] = '\0'; +- + while (fgets(buf, BUFSIZ, fp)) { + buf_len = strlen(buf); +- if (buf[buf_len - 1] == '\n') { ++ if (buf_len > 0 && buf[buf_len - 1] == '\n') { + buf_len--; + buf[buf_len] = '\0'; + got_nl = 1; +-- +2.25.1 + diff --git a/meta/recipes-devtools/opkg/opkg_0.4.2.bb b/meta/recipes-devtools/opkg/opkg_0.4.2.bb index a813f7258b..3ebc27c8ee 100644 --- a/meta/recipes-devtools/opkg/opkg_0.4.2.bb +++ b/meta/recipes-devtools/opkg/opkg_0.4.2.bb @@ -16,6 +16,7 @@ SRC_URI = "http://downloads.yoctoproject.org/releases/${BPN}/${BPN}-${PV}.tar.gz file://opkg.conf \ file://0001-opkg_conf-create-opkg.lock-in-run-instead-of-var-run.patch \ file://sourcedateepoch.patch \ + file://0001-file_util.c-fix-possible-bad-memory-access-in-file_r.patch \ file://run-ptest \ " @@ -50,7 +51,9 @@ EXTRA_OECONF_class-native = "--localstatedir=/${@os.path.relpath('${localstatedi do_install_append () { install -d ${D}${sysconfdir}/opkg install -m 0644 ${WORKDIR}/opkg.conf ${D}${sysconfdir}/opkg/opkg.conf - echo "option lists_dir ${OPKGLIBDIR}/opkg/lists" >>${D}${sysconfdir}/opkg/opkg.conf + echo "option lists_dir ${OPKGLIBDIR}/opkg/lists" >>${D}${sysconfdir}/opkg/opkg.conf + echo "option info_dir ${OPKGLIBDIR}/opkg/info" >>${D}${sysconfdir}/opkg/opkg.conf + echo "option status_file ${OPKGLIBDIR}/opkg/status" >>${D}${sysconfdir}/opkg/opkg.conf # We need to create the lock directory install -d ${D}${OPKGLIBDIR}/opkg diff --git a/meta/recipes-devtools/patchelf/patchelf_0.10.bb b/meta/recipes-devtools/patchelf/patchelf_0.10.bb index b64eaf3c21..2bf3108f88 100644 --- a/meta/recipes-devtools/patchelf/patchelf_0.10.bb +++ b/meta/recipes-devtools/patchelf/patchelf_0.10.bb @@ -4,7 +4,7 @@ HOMEPAGE = "https://github.com/NixOS/patchelf" LICENSE = "GPLv3" -SRC_URI = "git://github.com/NixOS/patchelf;protocol=https \ +SRC_URI = "git://github.com/NixOS/patchelf;protocol=https;branch=master \ file://handle-read-only-files.patch \ file://fix-adjusting-startPage.patch \ file://fix-phdrs.patch \ diff --git a/meta/recipes-devtools/perl/files/CVE-2023-31484.patch b/meta/recipes-devtools/perl/files/CVE-2023-31484.patch new file mode 100644 index 0000000000..0fea7bf8a8 --- /dev/null +++ b/meta/recipes-devtools/perl/files/CVE-2023-31484.patch @@ -0,0 +1,27 @@ +CVE: CVE-2023-31484 +Upstream-Status: Backport [ import from Ubuntu perl_5.30.0-9ubuntu0.5 +upstream https://github.com/andk/cpanpm/commit/9c98370287f4e709924aee7c58ef21c85289a7f0 ] +Signed-off-by: Lee Chee Yang <chee.yang.lee@intel.com> + +From 9c98370287f4e709924aee7c58ef21c85289a7f0 Mon Sep 17 00:00:00 2001 +From: Stig Palmquist <git@stig.io> +Date: Tue, 28 Feb 2023 11:54:06 +0100 +Subject: [PATCH] Add verify_SSL=>1 to HTTP::Tiny to verify https server + identity + +--- + lib/CPAN/HTTP/Client.pm | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/cpan/CPAN/lib/CPAN/HTTP/Client.pm b/cpan/CPAN/lib/CPAN/HTTP/Client.pm +index 4fc792c26..a616fee20 100644 +--- a/cpan/CPAN/lib/CPAN/HTTP/Client.pm ++++ b/cpan/CPAN/lib/CPAN/HTTP/Client.pm +@@ -32,6 +32,7 @@ sub mirror { + + my $want_proxy = $self->_want_proxy($uri); + my $http = HTTP::Tiny->new( ++ verify_SSL => 1, + $want_proxy ? (proxy => $self->{proxy}) : () + ); + diff --git a/meta/recipes-devtools/perl/files/CVE-2023-47038.patch b/meta/recipes-devtools/perl/files/CVE-2023-47038.patch new file mode 100644 index 0000000000..59252c560c --- /dev/null +++ b/meta/recipes-devtools/perl/files/CVE-2023-47038.patch @@ -0,0 +1,121 @@ +as per https://ubuntu.com/security/CVE-2023-47100 , CVE-2023-47100 is duplicate of CVE-2023-47038 +CVE: CVE-2023-47038 CVE-2023-47100 +Upstream-Status: Backport [ import from ubuntu perl_5.30.0-9ubuntu0.5 +upstream https://github.com/Perl/perl5/commit/12c313ce49b36160a7ca2e9b07ad5bd92ee4a010 ] +Signed-off-by: Lee Chee Yang <chee.yang.lee@intel.com> + +Backport of: + +From 12c313ce49b36160a7ca2e9b07ad5bd92ee4a010 Mon Sep 17 00:00:00 2001 +From: Karl Williamson <khw@cpan.org> +Date: Sat, 9 Sep 2023 11:59:09 -0600 +Subject: [PATCH 1/2] Fix read/write past buffer end: perl-security#140 + +A package name may be specified in a \p{...} regular expression +construct. If unspecified, "utf8::" is assumed, which is the package +all official Unicode properties are in. By specifying a different +package, one can create a user-defined property with the same +unqualified name as a Unicode one. Such a property is defined by a sub +whose name begins with "Is" or "In", and if the sub wishes to refer to +an official Unicode property, it must explicitly specify the "utf8::". +S_parse_uniprop_string() is used to parse the interior of both \p{} and +the user-defined sub lines. + +In S_parse_uniprop_string(), it parses the input "name" parameter, +creating a modified copy, "lookup_name", malloc'ed with the same size as +"name". The modifications are essentially to create a canonicalized +version of the input, with such things as extraneous white-space +stripped off. I found it convenient to strip off the package specifier +"utf8::". To to so, the code simply pretends "lookup_name" begins just +after the "utf8::", and adjusts various other values to compensate. +However, it missed the adjustment of one required one. + +This is only a problem when the property name begins with "perl" and +isn't "perlspace" nor "perlword". All such ones are undocumented +internal properties. + +What happens in this case is that the input is reparsed with slightly +different rules in effect as to what is legal versus illegal. The +problem is that "lookup_name" no longer is pointing to its initial +value, but "name" is. Thus the space allocated for filling "lookup_name" +is now shorter than "name", and as this shortened "lookup_name" is +filled by copying suitable portions of "name", the write can be to +unallocated space. + +The solution is to skip the "utf8::" when reparsing "name". Then both +"lookup_name" and "name" are effectively shortened by the same amount, +and there is no going off the end. + +This commit also does white-space adjustment so that things align +vertically for readability. + +This can be easily backported to earlier Perl releases. +--- + regcomp.c | 17 +++++++++++------ + t/re/pat_advanced.t | 8 ++++++++ + 2 files changed, 19 insertions(+), 6 deletions(-) + +--- a/regcomp.c ++++ b/regcomp.c +@@ -22606,7 +22606,7 @@ Perl_parse_uniprop_string(pTHX_ + * compile perl to know about them) */ + bool is_nv_type = FALSE; + +- unsigned int i, j = 0; ++ unsigned int i = 0, i_zero = 0, j = 0; + int equals_pos = -1; /* Where the '=' is found, or negative if none */ + int slash_pos = -1; /* Where the '/' is found, or negative if none */ + int table_index = 0; /* The entry number for this property in the table +@@ -22717,9 +22717,13 @@ Perl_parse_uniprop_string(pTHX_ + * all of them are considered to be for that package. For the purposes of + * parsing the rest of the property, strip it off */ + if (non_pkg_begin == STRLENs("utf8::") && memBEGINPs(name, name_len, "utf8::")) { +- lookup_name += STRLENs("utf8::"); +- j -= STRLENs("utf8::"); +- equals_pos -= STRLENs("utf8::"); ++ lookup_name += STRLENs("utf8::"); ++ j -= STRLENs("utf8::"); ++ equals_pos -= STRLENs("utf8::"); ++ i_zero = STRLENs("utf8::"); /* When resetting 'i' to reparse ++ from the beginning, it has to be ++ set past what we're stripping ++ off */ + } + + /* Here, we are either done with the whole property name, if it was simple; +@@ -22997,7 +23001,8 @@ Perl_parse_uniprop_string(pTHX_ + + /* We set the inputs back to 0 and the code below will reparse, + * using strict */ +- i = j = 0; ++ i = i_zero; ++ j = 0; + } + } + +@@ -23018,7 +23023,7 @@ Perl_parse_uniprop_string(pTHX_ + * separates two digits */ + if (cur == '_') { + if ( stricter +- && ( i == 0 || (int) i == equals_pos || i == name_len- 1 ++ && ( i == i_zero || (int) i == equals_pos || i == name_len- 1 + || ! isDIGIT_A(name[i-1]) || ! isDIGIT_A(name[i+1]))) + { + lookup_name[j++] = '_'; +--- a/t/re/pat_advanced.t ++++ b/t/re/pat_advanced.t +@@ -2524,6 +2524,14 @@ EOF + "", {}, "*COMMIT caused positioning beyond EOS"); + } + ++ { # perl-security#140, read/write past buffer end ++ fresh_perl_like('qr/\p{utf8::perl x}/', ++ qr/Illegal user-defined property name "utf8::perl x" in regex/, ++ {}, "perl-security#140"); ++ fresh_perl_is('qr/\p{utf8::_perl_surrogate}/', "", ++ {}, "perl-security#140"); ++ } ++ + + # !!! NOTE that tests that aren't at all likely to crash perl should go + # a ways above, above these last ones. There's a comment there that, like diff --git a/meta/recipes-devtools/perl/libmodule-build-perl_0.4231.bb b/meta/recipes-devtools/perl/libmodule-build-perl_0.4231.bb index a6fd7b1c07..c91b44cd6e 100644 --- a/meta/recipes-devtools/perl/libmodule-build-perl_0.4231.bb +++ b/meta/recipes-devtools/perl/libmodule-build-perl_0.4231.bb @@ -37,6 +37,7 @@ EXTRA_CPAN_BUILD_FLAGS = "--create_packlist=0" do_install_append () { rm -rf ${D}${docdir}/perl/html + sed -i "s:^#!.*:#!/usr/bin/env perl:" ${D}${bindir}/config_data } do_install_ptest() { diff --git a/meta/recipes-devtools/perl/libxml-parser-perl_2.46.bb b/meta/recipes-devtools/perl/libxml-parser-perl_2.46.bb index bc154bbdc5..ef2b292352 100644 --- a/meta/recipes-devtools/perl/libxml-parser-perl_2.46.bb +++ b/meta/recipes-devtools/perl/libxml-parser-perl_2.46.bb @@ -53,6 +53,7 @@ do_install_ptest() { chown -R root:root ${D}${PTEST_PATH}/samples } +RDEPENDS_${PN} += "perl-module-carp perl-module-file-spec" RDEPENDS_${PN}-ptest += "perl-module-filehandle perl-module-if perl-module-test perl-module-test-more" BBCLASSEXTEND="native nativesdk" diff --git a/meta/recipes-devtools/perl/perl_5.30.1.bb b/meta/recipes-devtools/perl/perl_5.30.1.bb index 9bb94e7caa..bf81a023b8 100644 --- a/meta/recipes-devtools/perl/perl_5.30.1.bb +++ b/meta/recipes-devtools/perl/perl_5.30.1.bb @@ -29,6 +29,8 @@ SRC_URI = "https://www.cpan.org/src/5.0/perl-${PV}.tar.gz;name=perl \ file://CVE-2020-10878_1.patch \ file://CVE-2020-10878_2.patch \ file://CVE-2020-12723.patch \ + file://CVE-2023-31484.patch \ + file://CVE-2023-47038.patch \ " SRC_URI_append_class-native = " \ file://perl-configpm-switch.patch \ @@ -44,6 +46,10 @@ SRC_URI[perl-cross.sha256sum] = "edce0b0c2f725e2db3f203d6d8e9f3f7161256f5d159055 S = "${WORKDIR}/perl-${PV}" +# This is windows only issue. +# https://ubuntu.com/security/CVE-2023-47039 +CVE_CHECK_WHITELIST += "CVE-2023-47039" + inherit upstream-version-is-even update-alternatives DEPENDS += "zlib virtual/crypt" diff --git a/meta/recipes-devtools/pseudo/files/build-oldlibc b/meta/recipes-devtools/pseudo/files/build-oldlibc new file mode 100755 index 0000000000..85c438de4e --- /dev/null +++ b/meta/recipes-devtools/pseudo/files/build-oldlibc @@ -0,0 +1,20 @@ +#!/bin/sh +# +# Script to re-generate pseudo-prebuilt-2.33.tar.xz +# +# Copyright (C) 2021 Richard Purdie +# +# SPDX-License-Identifier: GPL-2.0-only +# + +for i in x86_64 aarch64 i686; do + if [ ! -e $i-nativesdk-libc.tar.xz ]; then + wget http://downloads.yoctoproject.org/releases/uninative/3.2/$i-nativesdk-libc.tar.xz + fi + tar -xf $i-nativesdk-libc.tar.xz --wildcards \*/lib/libpthread\* \*/lib/libdl\* + cd $i-linux/lib + ln -s libdl.so.2 libdl.so + ln -s libpthread.so.0 libpthread.so + cd ../.. +done +tar -cJf pseudo-prebuilt-2.33.tar.xz *-linux
\ No newline at end of file diff --git a/meta/recipes-devtools/pseudo/files/older-glibc-symbols.patch b/meta/recipes-devtools/pseudo/files/older-glibc-symbols.patch new file mode 100644 index 0000000000..c453b5f735 --- /dev/null +++ b/meta/recipes-devtools/pseudo/files/older-glibc-symbols.patch @@ -0,0 +1,57 @@ +If we link against a newer glibc 2.34 and then try and our LD_PRELOAD is run against a +binary on a host with an older libc, we see symbol errors since in glibc 2.34, pthread +and dl are merged into libc itself. + +We need to use the older form of linking so use glibc binaries from an older release +to force this. We only use minimal symbols from these anyway. + +pthread_atfork is problematic, particularly on arm so use the internal glibc routine +it maps too. This was always present in the main libc from 2.3.2 onwards. + +Yes this is horrible. Better solutions welcome. + +There is more info in the bug: [YOCTO #14521] + +Upstream-Status: Inappropriate [this patch is native and nativesdk] +Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org> + +Tweak library search order, make prebuilt lib ahead of recipe lib +Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com> +--- + Makefile.in | 2 +- + pseudo_wrappers.c | 5 ++++- + 2 files changed, 5 insertions(+), 2 deletions(-) + +diff --git a/Makefile.in b/Makefile.in +--- a/Makefile.in ++++ b/Makefile.in +@@ -120,7 +120,7 @@ $(PSEUDODB): pseudodb.o $(SHOBJS) $(DBOBJS) pseudo_ipc.o | $(BIN) + libpseudo: $(LIBPSEUDO) + + $(LIBPSEUDO): $(WRAPOBJS) pseudo_client.o pseudo_ipc.o $(SHOBJS) | $(LIB) +- $(CC) $(CFLAGS) $(CFLAGS_PSEUDO) -shared -o $(LIBPSEUDO) \ ++ $(CC) $(CFLAGS) -Lprebuilt/$(shell uname -m)-linux/lib/ $(CFLAGS_PSEUDO) -shared -o $(LIBPSEUDO) \ + pseudo_client.o pseudo_ipc.o \ + $(WRAPOBJS) $(SHOBJS) $(LDFLAGS) $(CLIENT_LDFLAGS) + +diff --git a/pseudo_wrappers.c b/pseudo_wrappers.c +--- a/pseudo_wrappers.c ++++ b/pseudo_wrappers.c +@@ -100,10 +100,13 @@ static void libpseudo_atfork_child(void) + pseudo_mutex_holder = 0; + } + ++extern void *__dso_handle; ++extern int __register_atfork (void (*) (void), void (*) (void), void (*) (void), void *); ++ + static void + _libpseudo_init(void) { + if (!_libpseudo_initted) +- pthread_atfork(NULL, NULL, libpseudo_atfork_child); ++ __register_atfork (NULL, NULL, libpseudo_atfork_child, &__dso_handle == NULL ? NULL : __dso_handle); + + pseudo_getlock(); + pseudo_antimagic(); +-- +2.27.0 + diff --git a/meta/recipes-devtools/pseudo/pseudo_git.bb b/meta/recipes-devtools/pseudo/pseudo_git.bb index 0ba460f3e6..b5da3f0e29 100644 --- a/meta/recipes-devtools/pseudo/pseudo_git.bb +++ b/meta/recipes-devtools/pseudo/pseudo_git.bb @@ -5,8 +5,15 @@ SRC_URI = "git://git.yoctoproject.org/pseudo;branch=oe-core \ file://fallback-passwd \ file://fallback-group \ " +SRC_URI:append:class-native = " \ + http://downloads.yoctoproject.org/mirror/sources/pseudo-prebuilt-2.33.tar.xz;subdir=git/prebuilt;name=prebuilt \ + file://older-glibc-symbols.patch" +SRC_URI:append:class-nativesdk = " \ + http://downloads.yoctoproject.org/mirror/sources/pseudo-prebuilt-2.33.tar.xz;subdir=git/prebuilt;name=prebuilt \ + file://older-glibc-symbols.patch" +SRC_URI[prebuilt.sha256sum] = "ed9f456856e9d86359f169f46a70ad7be4190d6040282b84c8d97b99072485aa" -SRCREV = "b988b0a6b8afd8d459bc9a2528e834f63a3d59b2" +SRCREV = "2b4b88eb513335b0ece55fe51854693d9b20de35" S = "${WORKDIR}/git" PV = "1.9.0+git${SRCPV}" diff --git a/meta/recipes-devtools/python/python-setuptools.inc b/meta/recipes-devtools/python/python-setuptools.inc index 29be852f66..5faf62bc3a 100644 --- a/meta/recipes-devtools/python/python-setuptools.inc +++ b/meta/recipes-devtools/python/python-setuptools.inc @@ -8,6 +8,8 @@ PYPI_PACKAGE_EXT = "zip" inherit pypi +SRC_URI += " file://CVE-2022-40897.patch " + SRC_URI_append_class-native = " file://0001-conditionally-do-not-fetch-code-by-easy_install.patch" SRC_URI[md5sum] = "0c956eea142af9c2b02d72e3c042af30" diff --git a/meta/recipes-devtools/python/python3-jinja2_2.11.3.bb b/meta/recipes-devtools/python/python3-jinja2_2.11.3.bb index dbdf563f87..9f054c6024 100644 --- a/meta/recipes-devtools/python/python3-jinja2_2.11.3.bb +++ b/meta/recipes-devtools/python/python3-jinja2_2.11.3.bb @@ -1,5 +1,5 @@ DESCRIPTION = "Python Jinja2: A small but fast and easy to use stand-alone template engine written in pure python." -HOMEPAGE = "https://pypi.org/project/Jinja/" +HOMEPAGE = "https://pypi.org/project/Jinja2/" LICENSE = "BSD-3-Clause" LIC_FILES_CHKSUM = "file://LICENSE.rst;md5=5dc88300786f1c214c1e9827a5229462" diff --git a/meta/recipes-devtools/python/python3-magic_0.4.15.bb b/meta/recipes-devtools/python/python3-magic_0.4.15.bb index 698016ba4c..b73310c808 100644 --- a/meta/recipes-devtools/python/python3-magic_0.4.15.bb +++ b/meta/recipes-devtools/python/python3-magic_0.4.15.bb @@ -14,6 +14,11 @@ inherit pypi setuptools3 SRC_URI[md5sum] = "e384c95a47218f66c6501cd6dd45ff59" SRC_URI[sha256sum] = "f3765c0f582d2dfc72c15f3b5a82aecfae9498bd29ca840d72f37d7bd38bfcd5" -RDEPENDS_${PN} += "file" +DEPENDS_append_class-native = " file-replacement-native" + +RDEPENDS_${PN} += "file \ + ${PYTHON_PN}-ctypes \ + ${PYTHON_PN}-io \ + ${PYTHON_PN}-shell" BBCLASSEXTEND = "native" diff --git a/meta/recipes-devtools/python/python3-pip/CVE-2021-3572.patch b/meta/recipes-devtools/python/python3-pip/CVE-2021-3572.patch new file mode 100644 index 0000000000..a38ab57bc6 --- /dev/null +++ b/meta/recipes-devtools/python/python3-pip/CVE-2021-3572.patch @@ -0,0 +1,48 @@ +From c4fd13410b9a219f77fc30775d4a0ac9f69725bd Mon Sep 17 00:00:00 2001 +From: Hitendra Prajapati <hprajapati@mvista.com> +Date: Thu, 16 Jun 2022 09:52:43 +0530 +Subject: [PATCH] CVE-2021-3572 + +Upstream-Status: Backport [https://github.com/pypa/pip/commit/e46bdda9711392fec0c45c1175bae6db847cb30b] +CVE: CVE-2021-3572 +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> +--- + news/9827.bugfix.rst | 3 +++ + src/pip/_internal/vcs/git.py | 10 ++++++++-- + 2 files changed, 11 insertions(+), 2 deletions(-) + create mode 100644 news/9827.bugfix.rst + +diff --git a/news/9827.bugfix.rst b/news/9827.bugfix.rst +new file mode 100644 +index 0000000..e0d27c3 +--- /dev/null ++++ b/news/9827.bugfix.rst +@@ -0,0 +1,3 @@ ++**SECURITY**: Stop splitting on unicode separators in git references, ++which could be maliciously used to install a different revision on the ++repository. +diff --git a/src/pip/_internal/vcs/git.py b/src/pip/_internal/vcs/git.py +index 7483303..1b895f6 100644 +--- a/src/pip/_internal/vcs/git.py ++++ b/src/pip/_internal/vcs/git.py +@@ -137,9 +137,15 @@ class Git(VersionControl): + output = cls.run_command(['show-ref', rev], cwd=dest, + show_stdout=False, on_returncode='ignore') + refs = {} +- for line in output.strip().splitlines(): ++ # NOTE: We do not use splitlines here since that would split on other ++ # unicode separators, which can be maliciously used to install a ++ # different revision. ++ for line in output.strip().split("\n"): ++ line = line.rstrip("\r") ++ if not line: ++ continue + try: +- sha, ref = line.split() ++ ref_sha, ref_name = line.split(" ", maxsplit=2) + except ValueError: + # Include the offending line to simplify troubleshooting if + # this error ever occurs. +-- +2.25.1 + diff --git a/meta/recipes-devtools/python/python3-pip_20.0.2.bb b/meta/recipes-devtools/python/python3-pip_20.0.2.bb index 08738fb2f9..e24c6f4477 100644 --- a/meta/recipes-devtools/python/python3-pip_20.0.2.bb +++ b/meta/recipes-devtools/python/python3-pip_20.0.2.bb @@ -6,6 +6,7 @@ LIC_FILES_CHKSUM = "file://LICENSE.txt;md5=8ba06d529c955048e5ddd7c45459eb2e" DEPENDS += "python3 python3-setuptools-native" +SRC_URI = "file://CVE-2021-3572.patch " SRC_URI[md5sum] = "7d42ba49b809604f0df3d55df1c3fd86" SRC_URI[sha256sum] = "7db0c8ea4c7ea51c8049640e8e6e7fde949de672bfa4949920675563a5a6967f" diff --git a/meta/recipes-devtools/python/python3-setuptools/CVE-2022-40897.patch b/meta/recipes-devtools/python/python3-setuptools/CVE-2022-40897.patch new file mode 100644 index 0000000000..9150cea07e --- /dev/null +++ b/meta/recipes-devtools/python/python3-setuptools/CVE-2022-40897.patch @@ -0,0 +1,29 @@ +From 43a9c9bfa6aa626ec2a22540bea28d2ca77964be Mon Sep 17 00:00:00 2001 +From: "Jason R. Coombs" <jaraco@jaraco.com> +Date: Fri, 4 Nov 2022 13:47:53 -0400 +Subject: [PATCH] Limit the amount of whitespace to search/backtrack. Fixes + #3659. + +CVE: CVE-2022-40897 +Upstream-Status: Backport [ +Upstream : https://github.com/pypa/setuptools/commit/43a9c9bfa6aa626ec2a22540bea28d2ca77964be +Import from Ubuntu: http://archive.ubuntu.com/ubuntu/pool/main/s/setuptools/setuptools_45.2.0-1ubuntu0.1.debian.tar.xz +] +Signed-off-by: Lee Chee Yang <chee.yang.lee@intel.com> + +--- + setuptools/package_index.py | 2 +- + setuptools/tests/test_packageindex.py | 1 - + 2 files changed, 1 insertion(+), 2 deletions(-) + +--- setuptools-45.2.0.orig/setuptools/package_index.py ++++ setuptools-45.2.0/setuptools/package_index.py +@@ -215,7 +215,7 @@ def unique_values(func): + return wrapper + + +-REL = re.compile(r"""<([^>]*\srel\s*=\s*['"]?([^'">]+)[^>]*)>""", re.I) ++REL = re.compile(r"""<([^>]*\srel\s{0,10}=\s{0,10}['"]?([^'" >]+)[^>]*)>""", re.I) + # this line is here to fix emacs' cruddy broken syntax highlighting + + diff --git a/meta/recipes-devtools/python/python3/0001-bpo-36852-proper-detection-of-mips-architecture-for-.patch b/meta/recipes-devtools/python/python3/0001-bpo-36852-proper-detection-of-mips-architecture-for-.patch index c4fae09a5b..4ac0e140cc 100644 --- a/meta/recipes-devtools/python/python3/0001-bpo-36852-proper-detection-of-mips-architecture-for-.patch +++ b/meta/recipes-devtools/python/python3/0001-bpo-36852-proper-detection-of-mips-architecture-for-.patch @@ -14,17 +14,21 @@ Upstream-Status: Submitted [https://github.com/python/cpython/pull/13196] Signed-off-by: Matthias Schoepfer <matthias.schoepfer@ithinx.io> %% original patch: 0001-bpo-36852-proper-detection-of-mips-architecture-for-.patch + +Updated to apply after dea270a2a80214de22afadaaca2043d0d782eb7d + +Signed-off-by: Tim Orling <tim.orling@konsulko.com> --- configure.ac | 175 +++++++-------------------------------------------- 1 file changed, 21 insertions(+), 154 deletions(-) diff --git a/configure.ac b/configure.ac -index ede710e..bc81b0b 100644 +index de83332dd3..16b02d0798 100644 --- a/configure.ac +++ b/configure.ac -@@ -710,160 +710,27 @@ fi - MULTIARCH=$($CC --print-multiarch 2>/dev/null) - AC_SUBST(MULTIARCH) +@@ -719,160 +719,27 @@ then + fi + -AC_MSG_CHECKING([for the platform triplet based on compiler characteristics]) -cat >> conftest.c <<EOF @@ -185,25 +189,25 @@ index ede710e..bc81b0b 100644 +## Need to handle macos, vxworks and hurd special (?) :-/ +case ${target_os} in + darwin*) -+ PLATFORM_TRIPLET=darwin -+ ;; ++ PLATFORM_TRIPLET=darwin ++ ;; + hurd*) -+ PLATFORM_TRIPLET=i386-gnu -+ ;; ++ PLATFORM_TRIPLET=i386-gnu ++ ;; + vxworks*) -+ PLATFORM_TRIPLET=vxworks -+ ;; ++ PLATFORM_TRIPLET=vxworks ++ ;; + *) + if test "${target_cpu}" != "i686"; then -+ PLATFORM_TRIPLET=${target_cpu}-${target_os} -+ else -+ PLATFORM_TRIPLET=i386-${target_os} -+ fi -+ ;; -+esac ++ PLATFORM_TRIPLET=${target_cpu}-${target_os} ++ else ++ PLATFORM_TRIPLET=i386-${target_os} ++ fi ++ ;; ++esac - if test x$PLATFORM_TRIPLET != x && test x$MULTIARCH != x; then - if test x$PLATFORM_TRIPLET != x$MULTIARCH; then + if test x$PLATFORM_TRIPLET != xdarwin; then + MULTIARCH=$($CC --print-multiarch 2>/dev/null) -- -2.24.1 +2.32.0 diff --git a/meta/recipes-devtools/python/python3/CVE-2023-24329.patch b/meta/recipes-devtools/python/python3/CVE-2023-24329.patch new file mode 100644 index 0000000000..23dec65602 --- /dev/null +++ b/meta/recipes-devtools/python/python3/CVE-2023-24329.patch @@ -0,0 +1,80 @@ +From 72d356e3584ebfb8e813a8e9f2cd3dccf233c0d9 Mon Sep 17 00:00:00 2001 +From: "Miss Islington (bot)" + <31488909+miss-islington@users.noreply.github.com> +Date: Sun, 13 Nov 2022 11:00:25 -0800 +Subject: [PATCH] gh-99418: Make urllib.parse.urlparse enforce that a scheme + must begin with an alphabetical ASCII character. (GH-99421) + +Prevent urllib.parse.urlparse from accepting schemes that don't begin with an alphabetical ASCII character. + +RFC 3986 defines a scheme like this: `scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )` +RFC 2234 defines an ALPHA like this: `ALPHA = %x41-5A / %x61-7A` + +The WHATWG URL spec defines a scheme like this: +`"A URL-scheme string must be one ASCII alpha, followed by zero or more of ASCII alphanumeric, U+002B (+), U+002D (-), and U+002E (.)."` +(cherry picked from commit 439b9cfaf43080e91c4ad69f312f21fa098befc7) + +Co-authored-by: Ben Kallus <49924171+kenballus@users.noreply.github.com> + +Upstream-Status: Backport [https://github.com/python/cpython/commit/72d356e3584ebfb8e813a8e9f2cd3dccf233c0d9] +CVE: CVE-2023-24329 +Signed-off-by: Vivek Kumbhar <vkumbhar@mvista.com> +--- + Lib/test/test_urlparse.py | 18 ++++++++++++++++++ + Lib/urllib/parse.py | 2 +- + ...22-11-12-15-45-51.gh-issue-99418.FxfAXS.rst | 2 ++ + 3 files changed, 21 insertions(+), 1 deletion(-) + create mode 100644 Misc/NEWS.d/next/Library/2022-11-12-15-45-51.gh-issue-99418.FxfAXS.rst + +diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py +index 0ad3bf1..e1aa913 100644 +--- a/Lib/test/test_urlparse.py ++++ b/Lib/test/test_urlparse.py +@@ -735,6 +735,24 @@ class UrlParseTestCase(unittest.TestCase): + with self.assertRaises(ValueError): + p.port + ++ def test_attributes_bad_scheme(self): ++ """Check handling of invalid schemes.""" ++ for bytes in (False, True): ++ for parse in (urllib.parse.urlsplit, urllib.parse.urlparse): ++ for scheme in (".", "+", "-", "0", "http&", "६http"): ++ with self.subTest(bytes=bytes, parse=parse, scheme=scheme): ++ url = scheme + "://www.example.net" ++ if bytes: ++ if url.isascii(): ++ url = url.encode("ascii") ++ else: ++ continue ++ p = parse(url) ++ if bytes: ++ self.assertEqual(p.scheme, b"") ++ else: ++ self.assertEqual(p.scheme, "") ++ + def test_attributes_without_netloc(self): + # This example is straight from RFC 3261. It looks like it + # should allow the username, hostname, and port to be filled +diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py +index 979e6d2..2e7a3e2 100644 +--- a/Lib/urllib/parse.py ++++ b/Lib/urllib/parse.py +@@ -452,7 +452,7 @@ def urlsplit(url, scheme='', allow_fragments=True): + clear_cache() + netloc = query = fragment = '' + i = url.find(':') +- if i > 0: ++ if i > 0 and url[0].isascii() and url[0].isalpha(): + if url[:i] == 'http': # optimize the common case + url = url[i+1:] + if url[:2] == '//': +diff --git a/Misc/NEWS.d/next/Library/2022-11-12-15-45-51.gh-issue-99418.FxfAXS.rst b/Misc/NEWS.d/next/Library/2022-11-12-15-45-51.gh-issue-99418.FxfAXS.rst +new file mode 100644 +index 0000000..0a06e7c +--- /dev/null ++++ b/Misc/NEWS.d/next/Library/2022-11-12-15-45-51.gh-issue-99418.FxfAXS.rst +@@ -0,0 +1,2 @@ ++Fix bug in :func:`urllib.parse.urlparse` that causes URL schemes that begin ++with a digit, a plus sign, or a minus sign to be parsed incorrectly. +-- +2.25.1 diff --git a/meta/recipes-devtools/python/python3/makerace.patch b/meta/recipes-devtools/python/python3/makerace.patch new file mode 100644 index 0000000000..8971f28b8e --- /dev/null +++ b/meta/recipes-devtools/python/python3/makerace.patch @@ -0,0 +1,23 @@ +libainstall installs python-config.py but the .pyc cache files are generated +by the libinstall target. This means some builds may not generate the pyc files +for python-config.py depending on the order things happen in. This means builds +are not always reproducible. + +Add a dependency to avoid the race. + +Upstream-Status: Pending +Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org> + +Index: Python-3.8.11/Makefile.pre.in +=================================================================== +--- Python-3.8.11.orig/Makefile.pre.in ++++ Python-3.8.11/Makefile.pre.in +@@ -1415,7 +1415,7 @@ LIBSUBDIRS= tkinter tkinter/test tkinter + unittest unittest/test unittest/test/testmock \ + venv venv/scripts venv/scripts/common venv/scripts/posix \ + curses pydoc_data +-libinstall: build_all $(srcdir)/Modules/xxmodule.c ++libinstall: build_all $(srcdir)/Modules/xxmodule.c libainstall + @for i in $(SCRIPTDIR) $(LIBDEST); \ + do \ + if test ! -d $(DESTDIR)$$i; then \ diff --git a/meta/recipes-devtools/python/python3/python3-manifest.json b/meta/recipes-devtools/python/python3/python3-manifest.json index 3bcc9b8662..0e87f91dd8 100644 --- a/meta/recipes-devtools/python/python3/python3-manifest.json +++ b/meta/recipes-devtools/python/python3/python3-manifest.json @@ -531,7 +531,9 @@ "rdepends": [ "core" ], - "files": [], + "files": [ + "${libdir}/python${PYTHON_MAJMIN}/distutils/command/wininst-*.exe" + ], "cached": [] }, "distutils": { diff --git a/meta/recipes-devtools/python/python3_3.8.10.bb b/meta/recipes-devtools/python/python3_3.8.10.bb deleted file mode 100644 index 7295c6320e..0000000000 --- a/meta/recipes-devtools/python/python3_3.8.10.bb +++ /dev/null @@ -1,363 +0,0 @@ -SUMMARY = "The Python Programming Language" -HOMEPAGE = "http://www.python.org" -DESCRIPTION = "Python is a programming language that lets you work more quickly and integrate your systems more effectively." -LICENSE = "PSF-2.0 & BSD-0-Clause" -SECTION = "devel/python" - -LIC_FILES_CHKSUM = "file://LICENSE;md5=c22d2438294c784731bf9dd224a467b7" - -SRC_URI = "http://www.python.org/ftp/python/${PV}/Python-${PV}.tar.xz \ - file://run-ptest \ - file://create_manifest3.py \ - file://get_module_deps3.py \ - file://python3-manifest.json \ - file://check_build_completeness.py \ - file://cgi_py.patch \ - file://0001-Do-not-add-usr-lib-termcap-to-linker-flags-to-avoid-.patch \ - ${@bb.utils.contains('PACKAGECONFIG', 'tk', '', 'file://avoid_warning_about_tkinter.patch', d)} \ - file://0001-Do-not-use-the-shell-version-of-python-config-that-w.patch \ - file://python-config.patch \ - file://0001-Makefile.pre-use-qemu-wrapper-when-gathering-profile.patch \ - file://0001-Do-not-hardcode-lib-as-location-for-site-packages-an.patch \ - file://0001-python3-use-cc_basename-to-replace-CC-for-checking-c.patch \ - file://0001-Lib-sysconfig.py-fix-another-place-where-lib-is-hard.patch \ - file://0001-Makefile-fix-Issue36464-parallel-build-race-problem.patch \ - file://0001-bpo-36852-proper-detection-of-mips-architecture-for-.patch \ - file://crosspythonpath.patch \ - file://reformat_sysconfig.py \ - file://0001-Use-FLAG_REF-always-for-interned-strings.patch \ - file://0001-test_locale.py-correct-the-test-output-format.patch \ - file://0017-setup.py-do-not-report-missing-dependencies-for-disa.patch \ - file://0001-setup.py-pass-missing-libraries-to-Extension-for-mul.patch \ - file://0001-Makefile-do-not-compile-.pyc-in-parallel.patch \ - file://0001-configure.ac-fix-LIBPL.patch \ - file://0001-python3-Do-not-hardcode-lib-for-distutils.patch \ - file://0020-configure.ac-setup.py-do-not-add-a-curses-include-pa.patch \ - file://0001-test_ctypes.test_find-skip-without-tools-sdk.patch \ - " - -SRC_URI_append_class-native = " \ - file://0001-distutils-sysconfig-append-STAGING_LIBDIR-python-sys.patch \ - file://12-distutils-prefix-is-inside-staging-area.patch \ - file://0001-Don-t-search-system-for-headers-libraries.patch \ - " - -SRC_URI[md5sum] = "d9eee4b20155553830a2025e4dcaa7b3" -SRC_URI[sha256sum] = "6af24a66093dd840bcccf371d4044a3027e655cf24591ce26e48022bc79219d9" - -# exclude pre-releases for both python 2.x and 3.x -UPSTREAM_CHECK_REGEX = "[Pp]ython-(?P<pver>\d+(\.\d+)+).tar" - -CVE_PRODUCT = "python" - -# Upstream consider this expected behaviour -CVE_CHECK_WHITELIST += "CVE-2007-4559" -# This is not exploitable when glibc has CVE-2016-10739 fixed. -CVE_CHECK_WHITELIST += "CVE-2019-18348" - -# This is windows only issue. -CVE_CHECK_WHITELIST += "CVE-2020-15523" - -PYTHON_MAJMIN = "3.8" - -S = "${WORKDIR}/Python-${PV}" - -BBCLASSEXTEND = "native nativesdk" - -inherit autotools pkgconfig qemu ptest multilib_header update-alternatives - -MULTILIB_SUFFIX = "${@d.getVar('base_libdir',1).split('/')[-1]}" - -ALTERNATIVE_${PN}-dev = "python3-config" -ALTERNATIVE_LINK_NAME[python3-config] = "${bindir}/python${PYTHON_MAJMIN}-config" -ALTERNATIVE_TARGET[python3-config] = "${bindir}/python${PYTHON_MAJMIN}-config-${MULTILIB_SUFFIX}" - - -DEPENDS = "bzip2-replacement-native libffi bzip2 openssl sqlite3 zlib virtual/libintl xz virtual/crypt util-linux libtirpc libnsl2 autoconf-archive" -DEPENDS_append_class-target = " python3-native" -DEPENDS_append_class-nativesdk = " python3-native" - -EXTRA_OECONF = " --without-ensurepip --enable-shared" -EXTRA_OECONF_append_class-native = " --bindir=${bindir}/${PN}" - -export CROSSPYTHONPATH="${STAGING_LIBDIR_NATIVE}/python${PYTHON_MAJMIN}/lib-dynload/" - -EXTRANATIVEPATH += "python3-native" - -CACHED_CONFIGUREVARS = " \ - ac_cv_file__dev_ptmx=yes \ - ac_cv_file__dev_ptc=no \ - ac_cv_working_tzset=yes \ -" -python() { - # PGO currently causes builds to not be reproducible, so disable it for - # now. See YOCTO #13407 - if bb.utils.contains('MACHINE_FEATURES', 'qemu-usermode', True, False, d) and d.getVar('BUILD_REPRODUCIBLE_BINARIES') != '1': - d.setVar('PACKAGECONFIG_PGO', 'pgo') - else: - d.setVar('PACKAGECONFIG_PGO', '') -} - -PACKAGECONFIG_class-target ??= "readline ${PACKAGECONFIG_PGO} gdbm" -PACKAGECONFIG_class-native ??= "readline gdbm" -PACKAGECONFIG_class-nativesdk ??= "readline gdbm" -PACKAGECONFIG[readline] = ",,readline" -# Use profile guided optimisation by running PyBench inside qemu-user -PACKAGECONFIG[pgo] = "--enable-optimizations,,qemu-native" -PACKAGECONFIG[tk] = ",,tk" -PACKAGECONFIG[gdbm] = ",,gdbm" - -do_configure_prepend () { - mkdir -p ${B}/Modules - cat > ${B}/Modules/Setup.local << EOF -*disabled* -${@bb.utils.contains('PACKAGECONFIG', 'gdbm', '', '_gdbm _dbm', d)} -${@bb.utils.contains('PACKAGECONFIG', 'readline', '', 'readline', d)} -EOF -} - -CPPFLAGS_append = " -I${STAGING_INCDIR}/ncursesw -I${STAGING_INCDIR}/uuid" - -EXTRA_OEMAKE = '\ - STAGING_LIBDIR=${STAGING_LIBDIR} \ - STAGING_INCDIR=${STAGING_INCDIR} \ - LIB=${baselib} \ -' - -do_compile_prepend_class-target() { - if ${@bb.utils.contains('PACKAGECONFIG', 'pgo', 'true', 'false', d)}; then - qemu_binary="${@qemu_wrapper_cmdline(d, '${STAGING_DIR_TARGET}', ['${B}', '${STAGING_DIR_TARGET}/${base_libdir}'])}" - cat >pgo-wrapper <<EOF -#!/bin/sh -cd ${B} -$qemu_binary "\$@" -EOF - chmod +x pgo-wrapper - fi -} - -do_install_prepend() { - ${WORKDIR}/check_build_completeness.py ${T}/log.do_compile -} - -do_install_append_class-target() { - oe_multilib_header python${PYTHON_MAJMIN}/pyconfig.h -} - -do_install_append_class-native() { - # Make sure we use /usr/bin/env python - for PYTHSCRIPT in `grep -rIl ${bindir}/${PN}/python ${D}${bindir}/${PN}`; do - sed -i -e '1s|^#!.*|#!/usr/bin/env python3|' $PYTHSCRIPT - done - # Add a symlink to the native Python so that scripts can just invoke - # "nativepython" and get the right one without needing absolute paths - # (these often end up too long for the #! parser in the kernel as the - # buffer is 128 bytes long). - ln -s python3-native/python3 ${D}${bindir}/nativepython3 -} - -do_install_append() { - mkdir -p ${D}${libdir}/python-sysconfigdata - sysconfigfile=`find ${D} -name _sysconfig*.py` - cp $sysconfigfile ${D}${libdir}/python-sysconfigdata/_sysconfigdata.py - - sed -i \ - -e "s,^ 'LIBDIR'.*, 'LIBDIR': '${STAGING_LIBDIR}'\,,g" \ - -e "s,^ 'INCLUDEDIR'.*, 'INCLUDEDIR': '${STAGING_INCDIR}'\,,g" \ - -e "s,^ 'CONFINCLUDEDIR'.*, 'CONFINCLUDEDIR': '${STAGING_INCDIR}'\,,g" \ - -e "/^ 'INCLDIRSTOMAKE'/{N; s,/usr/include,${STAGING_INCDIR},g}" \ - -e "/^ 'INCLUDEPY'/s,/usr/include,${STAGING_INCDIR},g" \ - ${D}${libdir}/python-sysconfigdata/_sysconfigdata.py -} - -do_install_append_class-nativesdk () { - create_wrapper ${D}${bindir}/python${PYTHON_MAJMIN} TERMINFO_DIRS='${sysconfdir}/terminfo:/etc/terminfo:/usr/share/terminfo:/usr/share/misc/terminfo:/lib/terminfo' PYTHONNOUSERSITE='1' -} - -SSTATE_SCAN_FILES += "Makefile _sysconfigdata.py" -PACKAGE_PREPROCESS_FUNCS += "py_package_preprocess" - -py_package_preprocess () { - # Remove references to buildmachine paths in target Makefile and _sysconfigdata - sed -i -e 's:--sysroot=${STAGING_DIR_TARGET}::g' -e s:'--with-libtool-sysroot=${STAGING_DIR_TARGET}'::g \ - -e 's|${DEBUG_PREFIX_MAP}||g' \ - -e 's:${HOSTTOOLS_DIR}/::g' \ - -e 's:${RECIPE_SYSROOT_NATIVE}::g' \ - -e 's:${RECIPE_SYSROOT}::g' \ - -e 's:${BASE_WORKDIR}/${MULTIMACH_TARGET_SYS}::g' \ - ${PKGD}/${libdir}/python${PYTHON_MAJMIN}/config-${PYTHON_MAJMIN}${PYTHON_ABI}*/Makefile \ - ${PKGD}/${libdir}/python${PYTHON_MAJMIN}/_sysconfigdata*.py \ - ${PKGD}/${bindir}/python${PYTHON_MAJMIN}-config - - # Reformat _sysconfigdata after modifying it so that it remains - # reproducible - for c in ${PKGD}/${libdir}/python${PYTHON_MAJMIN}/_sysconfigdata*.py; do - python3 ${WORKDIR}/reformat_sysconfig.py $c - done - - # Recompile _sysconfigdata after modifying it - cd ${PKGD} - sysconfigfile=`find . -name _sysconfigdata_*.py` - ${STAGING_BINDIR_NATIVE}/python3-native/python3 \ - -c "from py_compile import compile; compile('$sysconfigfile')" - ${STAGING_BINDIR_NATIVE}/python3-native/python3 \ - -c "from py_compile import compile; compile('$sysconfigfile', optimize=1)" - ${STAGING_BINDIR_NATIVE}/python3-native/python3 \ - -c "from py_compile import compile; compile('$sysconfigfile', optimize=2)" - cd - - - mv ${PKGD}/${bindir}/python${PYTHON_MAJMIN}-config ${PKGD}/${bindir}/python${PYTHON_MAJMIN}-config-${MULTILIB_SUFFIX} - - #Remove the unneeded copy of target sysconfig data - rm -rf ${PKGD}/${libdir}/python-sysconfigdata -} - -# We want bytecode precompiled .py files (.pyc's) by default -# but the user may set it on their own conf -INCLUDE_PYCS ?= "1" - -python(){ - import collections, json - - filename = os.path.join(d.getVar('THISDIR'), 'python3', 'python3-manifest.json') - # This python changes the datastore based on the contents of a file, so mark - # that dependency. - bb.parse.mark_dependency(d, filename) - - with open(filename) as manifest_file: - manifest_str = manifest_file.read() - json_start = manifest_str.find('# EOC') + 6 - manifest_file.seek(json_start) - manifest_str = manifest_file.read() - python_manifest = json.loads(manifest_str, object_pairs_hook=collections.OrderedDict) - - # First set RPROVIDES for -native case - # Hardcoded since it cant be python3-native-foo, should be python3-foo-native - pn = 'python3' - rprovides = d.getVar('RPROVIDES').split() - - # ${PN}-misc-native is not in the manifest - rprovides.append(pn + '-misc-native') - - for key in python_manifest: - pypackage = pn + '-' + key + '-native' - if pypackage not in rprovides: - rprovides.append(pypackage) - - d.setVar('RPROVIDES_class-native', ' '.join(rprovides)) - - # Then work on the target - include_pycs = d.getVar('INCLUDE_PYCS') - - packages = d.getVar('PACKAGES').split() - pn = d.getVar('PN') - - newpackages=[] - for key in python_manifest: - pypackage = pn + '-' + key - - if pypackage not in packages: - # We need to prepend, otherwise python-misc gets everything - # so we use a new variable - newpackages.append(pypackage) - - # "Build" python's manifest FILES, RDEPENDS and SUMMARY - d.setVar('FILES_' + pypackage, '') - for value in python_manifest[key]['files']: - d.appendVar('FILES_' + pypackage, ' ' + value) - - # Add cached files - if include_pycs == '1': - for value in python_manifest[key]['cached']: - d.appendVar('FILES_' + pypackage, ' ' + value) - - for value in python_manifest[key]['rdepends']: - # Make it work with or without $PN - if '${PN}' in value: - value=value.split('-', 1)[1] - d.appendVar('RDEPENDS_' + pypackage, ' ' + pn + '-' + value) - - for value in python_manifest[key].get('rrecommends', ()): - if '${PN}' in value: - value=value.split('-', 1)[1] - d.appendVar('RRECOMMENDS_' + pypackage, ' ' + pn + '-' + value) - - d.setVar('SUMMARY_' + pypackage, python_manifest[key]['summary']) - - # Prepending so to avoid python-misc getting everything - packages = newpackages + packages - d.setVar('PACKAGES', ' '.join(packages)) - d.setVar('ALLOW_EMPTY_${PN}-modules', '1') - d.setVar('ALLOW_EMPTY_${PN}-pkgutil', '1') -} - -# Files needed to create a new manifest - -do_create_manifest() { - # This task should be run with every new release of Python. - # We must ensure that PACKAGECONFIG enables everything when creating - # a new manifest, this is to base our new manifest on a complete - # native python build, containing all dependencies, otherwise the task - # wont be able to find the required files. - # e.g. BerkeleyDB is an optional build dependency so it may or may not - # be present, we must ensure it is. - - cd ${WORKDIR} - # This needs to be executed by python-native and NOT by HOST's python - nativepython3 create_manifest3.py ${PYTHON_MAJMIN} - cp python3-manifest.json.new ${THISDIR}/python3/python3-manifest.json -} - -# bitbake python -c create_manifest -# Make sure we have native python ready when we create a new manifest -addtask do_create_manifest after do_patch do_prepare_recipe_sysroot - -# manual dependency additions -RRECOMMENDS_${PN}-core_append_class-nativesdk = " nativesdk-python3-modules" -RRECOMMENDS_${PN}-crypt_append_class-target = " openssl ca-certificates" -RRECOMMENDS_${PN}-crypt_append_class-nativesdk = " openssl ca-certificates" - -# For historical reasons PN is empty and provided by python3-modules -FILES_${PN} = "" -RPROVIDES_${PN}-modules = "${PN}" - -FILES_${PN}-pydoc += "${bindir}/pydoc${PYTHON_MAJMIN} ${bindir}/pydoc3" -FILES_${PN}-idle += "${bindir}/idle3 ${bindir}/idle${PYTHON_MAJMIN}" - -# provide python-pyvenv from python3-venv -RPROVIDES_${PN}-venv += "python3-pyvenv" - -# package libpython3 -PACKAGES =+ "libpython3 libpython3-staticdev" -FILES_libpython3 = "${libdir}/libpython*.so.*" -FILES_libpython3-staticdev += "${libdir}/python${PYTHON_MAJMIN}/config-${PYTHON_MAJMIN}-*/libpython${PYTHON_MAJMIN}.a" -INSANE_SKIP_${PN}-dev += "dev-elf" -INSANE_SKIP_${PN}-ptest += "dev-deps" - -# catch all the rest (unsorted) -PACKAGES += "${PN}-misc" -RDEPENDS_${PN}-misc += "python3-core python3-email python3-codecs python3-pydoc python3-pickle python3-audio" -RDEPENDS_${PN}-modules_append_class-target = " python3-misc" -RDEPENDS_${PN}-modules_append_class-nativesdk = " python3-misc" -FILES_${PN}-misc = "${libdir}/python${PYTHON_MAJMIN} ${libdir}/python${PYTHON_MAJMIN}/lib-dynload" - -# catch manpage -PACKAGES += "${PN}-man" -FILES_${PN}-man = "${datadir}/man" - -# See https://bugs.python.org/issue18748 and https://bugs.python.org/issue37395 -RDEPENDS_libpython3_append_libc-glibc = " libgcc" -RDEPENDS_${PN}-ctypes_append_libc-glibc = " ${MLPREFIX}ldconfig" -RDEPENDS_${PN}-ptest = "${PN}-modules ${PN}-tests ${PN}-dev unzip bzip2 libgcc tzdata-europe coreutils sed" -RDEPENDS_${PN}-ptest_append_libc-glibc = " locale-base-tr-tr.iso-8859-9" -RDEPENDS_${PN}-tkinter += "${@bb.utils.contains('PACKAGECONFIG', 'tk', 'tk tk-lib', '', d)}" -RDEPENDS_${PN}-dev = "" - -RDEPENDS_${PN}-tests_append_class-target = " bash" -RDEPENDS_${PN}-tests_append_class-nativesdk = " bash" - -# Python's tests contain large numbers of files we don't need in the recipe sysroots -SYSROOT_PREPROCESS_FUNCS += " py3_sysroot_cleanup" -py3_sysroot_cleanup () { - rm -rf ${SYSROOT_DESTDIR}${libdir}/python${PYTHON_MAJMIN}/test -} diff --git a/meta/recipes-devtools/python/python3_3.8.11.bb b/meta/recipes-devtools/python/python3_3.8.18.bb index f549bb2205..9d0f72ecf9 100644 --- a/meta/recipes-devtools/python/python3_3.8.11.bb +++ b/meta/recipes-devtools/python/python3_3.8.18.bb @@ -4,7 +4,7 @@ DESCRIPTION = "Python is a programming language that lets you work more quickly LICENSE = "PSF-2.0 & BSD-0-Clause" SECTION = "devel/python" -LIC_FILES_CHKSUM = "file://LICENSE;md5=c22d2438294c784731bf9dd224a467b7" +LIC_FILES_CHKSUM = "file://LICENSE;md5=07fc4b9a9c0c0e48050ed38a5e72552b" SRC_URI = "http://www.python.org/ftp/python/${PV}/Python-${PV}.tar.xz \ file://run-ptest \ @@ -33,6 +33,8 @@ SRC_URI = "http://www.python.org/ftp/python/${PV}/Python-${PV}.tar.xz \ file://0001-configure.ac-fix-LIBPL.patch \ file://0001-python3-Do-not-hardcode-lib-for-distutils.patch \ file://0020-configure.ac-setup.py-do-not-add-a-curses-include-pa.patch \ + file://makerace.patch \ + file://CVE-2023-24329.patch \ " SRC_URI_append_class-native = " \ @@ -41,8 +43,8 @@ SRC_URI_append_class-native = " \ file://0001-Don-t-search-system-for-headers-libraries.patch \ " -SRC_URI[md5sum] = "5840ba601128f48fee4e7c98fbdac65d" -SRC_URI[sha256sum] = "fb1a1114ebfe9e97199603c6083e20b236a0e007a2c51f29283ffb50c1420fb2" +SRC_URI[md5sum] = "5ea6267ea00513fc31d3746feb35842d" +SRC_URI[sha256sum] = "3ffb71cd349a326ba7b2fadc7e7df86ba577dd9c4917e52a8401adbda7405e3f" # exclude pre-releases for both python 2.x and 3.x UPSTREAM_CHECK_REGEX = "[Pp]ython-(?P<pver>\d+(\.\d+)+).tar" @@ -55,7 +57,12 @@ CVE_CHECK_WHITELIST += "CVE-2007-4559" CVE_CHECK_WHITELIST += "CVE-2019-18348" # This is windows only issue. -CVE_CHECK_WHITELIST += "CVE-2020-15523" +CVE_CHECK_WHITELIST += "CVE-2020-15523 CVE-2022-26488" +# The mailcap module is insecure by design, so this can't be fixed in a meaningful way. +# The module will be removed in the future and flaws documented. +CVE_CHECK_WHITELIST += "CVE-2015-20107" +# Not an issue, in fact expected behaviour +CVE_CHECK_WHITELIST += "CVE-2023-36632" PYTHON_MAJMIN = "3.8" diff --git a/meta/recipes-devtools/qemu/qemu-system-native_4.2.0.bb b/meta/recipes-devtools/qemu/qemu-system-native_4.2.0.bb index d83ee59375..5ae6a37f26 100644 --- a/meta/recipes-devtools/qemu/qemu-system-native_4.2.0.bb +++ b/meta/recipes-devtools/qemu/qemu-system-native_4.2.0.bb @@ -9,7 +9,7 @@ DEPENDS = "glib-2.0-native zlib-native pixman-native qemu-native bison-native" EXTRA_OECONF_append = " --target-list=${@get_qemu_system_target_list(d)}" -PACKAGECONFIG ??= "fdt alsa kvm" +PACKAGECONFIG ??= "fdt alsa kvm slirp" # Handle distros such as CentOS 5 32-bit that do not have kvm support PACKAGECONFIG_remove = "${@'kvm' if not os.path.exists('/usr/include/linux/kvm.h') else ''}" diff --git a/meta/recipes-devtools/qemu/qemu.inc b/meta/recipes-devtools/qemu/qemu.inc index 8f927bdf54..59ff69d51d 100644 --- a/meta/recipes-devtools/qemu/qemu.inc +++ b/meta/recipes-devtools/qemu/qemu.inc @@ -35,27 +35,116 @@ SRC_URI = "https://download.qemu.org/${BPN}-${PV}.tar.xz \ file://CVE-2020-7039-2.patch \ file://CVE-2020-7039-3.patch \ file://0001-Add-enable-disable-udev.patch \ - file://CVE-2020-7211.patch \ - file://0001-qemu-Do-not-include-file-if-not-exists.patch \ + file://CVE-2020-7211.patch \ + file://0001-qemu-Do-not-include-file-if-not-exists.patch \ file://CVE-2020-11102.patch \ - file://CVE-2020-11869.patch \ - file://CVE-2020-13361.patch \ - file://CVE-2020-10761.patch \ - file://CVE-2020-10702.patch \ - file://CVE-2020-13659.patch \ - file://CVE-2020-13800.patch \ - file://CVE-2020-13362.patch \ - file://CVE-2020-15863.patch \ - file://CVE-2020-14364.patch \ - file://CVE-2020-14415.patch \ - file://CVE-2020-16092.patch \ - file://0001-target-mips-Increase-number-of-TLB-entries-on-the-34.patch \ - file://CVE-2019-20175.patch \ - file://CVE-2020-24352.patch \ - file://CVE-2020-25723.patch \ - file://CVE-2021-20203.patch \ - file://CVE-2021-3392.patch \ - " + file://CVE-2020-11869.patch \ + file://CVE-2020-13361.patch \ + file://CVE-2020-10761.patch \ + file://CVE-2020-10702.patch \ + file://CVE-2020-13659.patch \ + file://CVE-2020-13800.patch \ + file://CVE-2020-13362.patch \ + file://CVE-2020-15863.patch \ + file://CVE-2020-14364.patch \ + file://CVE-2020-14415.patch \ + file://CVE-2020-16092.patch \ + file://0001-target-mips-Increase-number-of-TLB-entries-on-the-34.patch \ + file://CVE-2019-20175.patch \ + file://CVE-2020-24352.patch \ + file://CVE-2020-25723.patch \ + file://CVE-2021-20203.patch \ + file://CVE-2021-3392.patch \ + file://CVE-2020-25085.patch \ + file://CVE-2020-25624_1.patch \ + file://CVE-2020-25624_2.patch \ + file://CVE-2020-25625.patch \ + file://CVE-2020-29443.patch \ + file://CVE-2021-20221.patch \ + file://CVE-2021-20181.patch \ + file://CVE-2021-3416_1.patch \ + file://CVE-2021-3416_2.patch \ + file://CVE-2021-3416_3.patch \ + file://CVE-2021-3416_5.patch \ + file://CVE-2021-3416_6.patch \ + file://CVE-2021-3416_7.patch \ + file://CVE-2021-3416_8.patch \ + file://CVE-2021-3416_9.patch \ + file://CVE-2021-3416_10.patch \ + file://CVE-2021-20257.patch \ + file://CVE-2021-3544.patch \ + file://CVE-2021-3544_2.patch \ + file://CVE-2021-3544_3.patch \ + file://CVE-2021-3544_4.patch \ + file://CVE-2021-3544_5.patch \ + file://CVE-2021-3545.patch \ + file://CVE-2021-3546.patch \ + file://CVE-2021-3527-1.patch \ + file://CVE-2021-3527-2.patch \ + file://CVE-2021-3582.patch \ + file://CVE-2021-3607.patch \ + file://CVE-2021-3608.patch \ + file://CVE-2020-12829_1.patch \ + file://CVE-2020-12829_2.patch \ + file://CVE-2020-12829_3.patch \ + file://CVE-2020-12829_4.patch \ + file://CVE-2020-12829_5.patch \ + file://CVE-2020-27617.patch \ + file://CVE-2020-28916.patch \ + file://CVE-2021-3682.patch \ + file://CVE-2020-13253_1.patch \ + file://CVE-2020-13253_2.patch \ + file://CVE-2020-13253_3.patch \ + file://CVE-2020-13253_4.patch \ + file://CVE-2020-13253_5.patch \ + file://CVE-2020-13791.patch \ + file://CVE-2022-35414.patch \ + file://CVE-2020-27821.patch \ + file://CVE-2020-13754-1.patch \ + file://CVE-2020-13754-2.patch \ + file://CVE-2020-13754-3.patch \ + file://CVE-2020-13754-4.patch \ + file://CVE-2021-3713.patch \ + file://CVE-2021-3748.patch \ + file://CVE-2021-3930.patch \ + file://CVE-2021-4206.patch \ + file://CVE-2021-4207.patch \ + file://CVE-2022-0216-1.patch \ + file://CVE-2022-0216-2.patch \ + file://CVE-2021-3750.patch \ + file://CVE-2021-3638.patch \ + file://CVE-2021-20196.patch \ + file://CVE-2021-3507.patch \ + file://hw-block-nvme-refactor-nvme_addr_read.patch \ + file://hw-block-nvme-handle-dma-errors.patch \ + file://CVE-2021-3929.patch \ + file://CVE-2022-4144.patch \ + file://CVE-2020-15859.patch \ + file://CVE-2020-15469-1.patch \ + file://CVE-2020-15469-2.patch \ + file://CVE-2020-15469-3.patch \ + file://CVE-2020-15469-4.patch \ + file://CVE-2020-15469-5.patch \ + file://CVE-2020-15469-6.patch \ + file://CVE-2020-15469-7.patch \ + file://CVE-2020-15469-8.patch \ + file://CVE-2020-35504.patch \ + file://CVE-2020-35505.patch \ + file://CVE-2022-26354.patch \ + file://CVE-2021-3409-1.patch \ + file://CVE-2021-3409-2.patch \ + file://CVE-2021-3409-3.patch \ + file://CVE-2021-3409-4.patch \ + file://CVE-2021-3409-5.patch \ + file://hw-display-qxl-Pass-requested-buffer-size-to-qxl_phy.patch \ + file://CVE-2023-0330.patch \ + file://CVE-2023-3354.patch \ + file://CVE-2023-3180.patch \ + file://CVE-2020-24165.patch \ + file://CVE-2023-5088.patch \ + file://9pfs-local-ignore-O_NOATIME-if-we-don-t-have-permiss.patch \ + file://CVE-2023-2861.patch \ + " UPSTREAM_CHECK_REGEX = "qemu-(?P<pver>\d+(\.\d+)+)\.tar" SRC_URI[md5sum] = "278eeb294e4b497e79af7a57e660cb9a" @@ -72,6 +161,21 @@ CVE_CHECK_WHITELIST += "CVE-2007-0998" # https://bugzilla.redhat.com/show_bug.cgi?id=1609015#c11 CVE_CHECK_WHITELIST += "CVE-2018-18438" +# the issue introduced in v5.1.0-rc0 +CVE_CHECK_WHITELIST += "CVE-2020-27661" + +# As per https://nvd.nist.gov/vuln/detail/CVE-2023-0664 +# https://bugzilla.redhat.com/show_bug.cgi?id=2167423 +# this bug related to windows specific. +CVE_CHECK_WHITELIST += "CVE-2023-0664" + +# As per https://bugzilla.redhat.com/show_bug.cgi?id=2203387 +# RHEL specific issue +CVE_CHECK_WHITELIST += "CVE-2023-2680" + +# Affected only `qemu-kvm` shipped with Red Hat Enterprise Linux 8.3 release. +CVE_CHECK_WHITELIST += "CVE-2021-20295" + COMPATIBLE_HOST_mipsarchn32 = "null" COMPATIBLE_HOST_mipsarchn64 = "null" @@ -210,6 +314,16 @@ PACKAGECONFIG[glusterfs] = "--enable-glusterfs,--disable-glusterfs" PACKAGECONFIG[xkbcommon] = "--enable-xkbcommon,--disable-xkbcommon,libxkbcommon" PACKAGECONFIG[libudev] = "--enable-libudev,--disable-libudev,eudev" PACKAGECONFIG[libxml2] = "--enable-libxml2,--disable-libxml2,libxml2" +PACKAGECONFIG[seccomp] = "--enable-seccomp,--disable-seccomp,libseccomp" +PACKAGECONFIG[capstone] = "--enable-capstone,--disable-capstone" +# libnfs is currently provided by meta-kodi +PACKAGECONFIG[libnfs] = "--enable-libnfs,--disable-libnfs,libnfs" +PACKAGECONFIG[brlapi] = "--enable-brlapi,--disable-brlapi" +PACKAGECONFIG[vde] = "--enable-vde,--disable-vde" +# version 4.2.0 doesn't have an "internal" option for enable-slirp, so use "git" which uses the same configure code path +PACKAGECONFIG[slirp] = "--enable-slirp=git,--disable-slirp" +PACKAGECONFIG[rbd] = "--enable-rbd,--disable-rbd" +PACKAGECONFIG[rdma] = "--enable-rdma,--disable-rdma" INSANE_SKIP_${PN} = "arch" diff --git a/meta/recipes-devtools/qemu/qemu/0012-fix-libcap-header-issue-on-some-distro.patch b/meta/recipes-devtools/qemu/qemu/0012-fix-libcap-header-issue-on-some-distro.patch index 3a7d7bbd33..3789f1edea 100644 --- a/meta/recipes-devtools/qemu/qemu/0012-fix-libcap-header-issue-on-some-distro.patch +++ b/meta/recipes-devtools/qemu/qemu/0012-fix-libcap-header-issue-on-some-distro.patch @@ -60,7 +60,7 @@ Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com> 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c -index 6f132c5f..8329950c 100644 +index 300c9765..2823db7d 100644 --- a/fsdev/virtfs-proxy-helper.c +++ b/fsdev/virtfs-proxy-helper.c @@ -13,7 +13,6 @@ @@ -71,9 +71,9 @@ index 6f132c5f..8329950c 100644 #include <sys/fsuid.h> #include <sys/vfs.h> #include <sys/ioctl.h> -@@ -27,7 +26,11 @@ - #include "9p-iov-marshal.h" +@@ -28,7 +27,11 @@ #include "hw/9pfs/9p-proxy.h" + #include "hw/9pfs/9p-util.h" #include "fsdev/9p-iov-marshal.h" - +/* @@ -84,3 +84,6 @@ index 6f132c5f..8329950c 100644 #define PROGNAME "virtfs-proxy-helper" #ifndef XFS_SUPER_MAGIC +-- +2.25.1 + diff --git a/meta/recipes-devtools/qemu/qemu/9pfs-local-ignore-O_NOATIME-if-we-don-t-have-permiss.patch b/meta/recipes-devtools/qemu/qemu/9pfs-local-ignore-O_NOATIME-if-we-don-t-have-permiss.patch new file mode 100644 index 0000000000..72d9c47bde --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/9pfs-local-ignore-O_NOATIME-if-we-don-t-have-permiss.patch @@ -0,0 +1,63 @@ +From a5804fcf7b22fc7d1f9ec794dd284c7d504bd16b Mon Sep 17 00:00:00 2001 +From: Omar Sandoval <osandov@fb.com> +Date: Thu, 14 May 2020 08:06:43 +0200 +Subject: [PATCH] 9pfs: local: ignore O_NOATIME if we don't have permissions + +QEMU's local 9pfs server passes through O_NOATIME from the client. If +the QEMU process doesn't have permissions to use O_NOATIME (namely, it +does not own the file nor have the CAP_FOWNER capability), the open will +fail. This causes issues when from the client's point of view, it +believes it has permissions to use O_NOATIME (e.g., a process running as +root in the virtual machine). Additionally, overlayfs on Linux opens +files on the lower layer using O_NOATIME, so in this case a 9pfs mount +can't be used as a lower layer for overlayfs (cf. +https://github.com/osandov/drgn/blob/dabfe1971951701da13863dbe6d8a1d172ad9650/vmtest/onoatimehack.c +and https://github.com/NixOS/nixpkgs/issues/54509). + +Luckily, O_NOATIME is effectively a hint, and is often ignored by, e.g., +network filesystems. open(2) notes that O_NOATIME "may not be effective +on all filesystems. One example is NFS, where the server maintains the +access time." This means that we can honor it when possible but fall +back to ignoring it. + +Acked-by: Christian Schoenebeck <qemu_oss@crudebyte.com> +Signed-off-by: Omar Sandoval <osandov@fb.com> +Message-Id: <e9bee604e8df528584693a4ec474ded6295ce8ad.1587149256.git.osandov@fb.com> +Signed-off-by: Greg Kurz <groug@kaod.org> + +Upstream-Status: Backport [https://gitlab.com/qemu-project/qemu/-/commit/a5804fcf7b22fc7d1f9ec794dd284c7d504bd16b] +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + hw/9pfs/9p-util.h | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h +index 79ed6b233e5..546f46dc7dc 100644 +--- a/hw/9pfs/9p-util.h ++++ b/hw/9pfs/9p-util.h +@@ -37,9 +37,22 @@ static inline int openat_file(int dirfd, const char *name, int flags, + { + int fd, serrno, ret; + ++again: + fd = openat(dirfd, name, flags | O_NOFOLLOW | O_NOCTTY | O_NONBLOCK, + mode); + if (fd == -1) { ++ if (errno == EPERM && (flags & O_NOATIME)) { ++ /* ++ * The client passed O_NOATIME but we lack permissions to honor it. ++ * Rather than failing the open, fall back without O_NOATIME. This ++ * doesn't break the semantics on the client side, as the Linux ++ * open(2) man page notes that O_NOATIME "may not be effective on ++ * all filesystems". In particular, NFS and other network ++ * filesystems ignore it entirely. ++ */ ++ flags &= ~O_NOATIME; ++ goto again; ++ } + return -1; + } + +-- +GitLab + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-12829_1.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-12829_1.patch new file mode 100644 index 0000000000..6fee4f640d --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-12829_1.patch @@ -0,0 +1,164 @@ +From e29da77e5fddf6480e3a0e80b63d703edaec751b Mon Sep 17 00:00:00 2001 +From: BALATON Zoltan <balaton@eik.bme.hu> +Date: Thu, 21 May 2020 21:39:44 +0200 +Subject: [PATCH] sm501: Convert printf + abort to qemu_log_mask +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Some places already use qemu_log_mask() to log unimplemented features +or errors but some others have printf() then abort(). Convert these to +qemu_log_mask() and avoid aborting to prevent guests to easily cause +denial of service. + +Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu> +Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> +Message-id: 305af87f59d81e92f2aaff09eb8a3603b8baa322.1590089984.git.balaton@eik.bme.hu +Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> + +Upstream-Status: Backport +CVE: CVE-2020-12829 dep#1 +Signed-off-by: Armin Kuster <akuster@mvista.com> + +--- + hw/display/sm501.c | 57 ++++++++++++++++++++++------------------------ + 1 file changed, 27 insertions(+), 30 deletions(-) + +diff --git a/hw/display/sm501.c b/hw/display/sm501.c +index acc692531a..bd3ccfe311 100644 +--- a/hw/display/sm501.c ++++ b/hw/display/sm501.c +@@ -727,8 +727,8 @@ static void sm501_2d_operation(SM501State *s) + int fb_len = get_width(s, crt) * get_height(s, crt) * get_bpp(s, crt); + + if (addressing != 0x0) { +- printf("%s: only XY addressing is supported.\n", __func__); +- abort(); ++ qemu_log_mask(LOG_UNIMP, "sm501: only XY addressing is supported.\n"); ++ return; + } + + if (rop_mode == 0) { +@@ -754,8 +754,8 @@ static void sm501_2d_operation(SM501State *s) + + if ((s->twoD_source_base & 0x08000000) || + (s->twoD_destination_base & 0x08000000)) { +- printf("%s: only local memory is supported.\n", __func__); +- abort(); ++ qemu_log_mask(LOG_UNIMP, "sm501: only local memory is supported.\n"); ++ return; + } + + switch (operation) { +@@ -823,9 +823,9 @@ static void sm501_2d_operation(SM501State *s) + break; + + default: +- printf("non-implemented SM501 2D operation. %d\n", operation); +- abort(); +- break; ++ qemu_log_mask(LOG_UNIMP, "sm501: not implemented 2D operation: %d\n", ++ operation); ++ return; + } + + if (dst_base >= get_fb_addr(s, crt) && +@@ -892,9 +892,8 @@ static uint64_t sm501_system_config_read(void *opaque, hwaddr addr, + break; + + default: +- printf("sm501 system config : not implemented register read." +- " addr=%x\n", (int)addr); +- abort(); ++ qemu_log_mask(LOG_UNIMP, "sm501: not implemented system config" ++ "register read. addr=%" HWADDR_PRIx "\n", addr); + } + + return ret; +@@ -948,15 +947,15 @@ static void sm501_system_config_write(void *opaque, hwaddr addr, + break; + case SM501_ENDIAN_CONTROL: + if (value & 0x00000001) { +- printf("sm501 system config : big endian mode not implemented.\n"); +- abort(); ++ qemu_log_mask(LOG_UNIMP, "sm501: system config big endian mode not" ++ " implemented.\n"); + } + break; + + default: +- printf("sm501 system config : not implemented register write." +- " addr=%x, val=%x\n", (int)addr, (uint32_t)value); +- abort(); ++ qemu_log_mask(LOG_UNIMP, "sm501: not implemented system config" ++ "register write. addr=%" HWADDR_PRIx ++ ", val=%" PRIx64 "\n", addr, value); + } + } + +@@ -1207,9 +1206,8 @@ static uint64_t sm501_disp_ctrl_read(void *opaque, hwaddr addr, + break; + + default: +- printf("sm501 disp ctrl : not implemented register read." +- " addr=%x\n", (int)addr); +- abort(); ++ qemu_log_mask(LOG_UNIMP, "sm501: not implemented disp ctrl register " ++ "read. addr=%" HWADDR_PRIx "\n", addr); + } + + return ret; +@@ -1345,9 +1343,9 @@ static void sm501_disp_ctrl_write(void *opaque, hwaddr addr, + break; + + default: +- printf("sm501 disp ctrl : not implemented register write." +- " addr=%x, val=%x\n", (int)addr, (unsigned)value); +- abort(); ++ qemu_log_mask(LOG_UNIMP, "sm501: not implemented disp ctrl register " ++ "write. addr=%" HWADDR_PRIx ++ ", val=%" PRIx64 "\n", addr, value); + } + } + +@@ -1433,9 +1431,8 @@ static uint64_t sm501_2d_engine_read(void *opaque, hwaddr addr, + ret = 0; /* Should return interrupt status */ + break; + default: +- printf("sm501 disp ctrl : not implemented register read." +- " addr=%x\n", (int)addr); +- abort(); ++ qemu_log_mask(LOG_UNIMP, "sm501: not implemented disp ctrl register " ++ "read. addr=%" HWADDR_PRIx "\n", addr); + } + + return ret; +@@ -1520,9 +1517,9 @@ static void sm501_2d_engine_write(void *opaque, hwaddr addr, + /* ignored, writing 0 should clear interrupt status */ + break; + default: +- printf("sm501 2d engine : not implemented register write." +- " addr=%x, val=%x\n", (int)addr, (unsigned)value); +- abort(); ++ qemu_log_mask(LOG_UNIMP, "sm501: not implemented 2d engine register " ++ "write. addr=%" HWADDR_PRIx ++ ", val=%" PRIx64 "\n", addr, value); + } + } + +@@ -1670,9 +1667,9 @@ static void sm501_update_display(void *opaque) + draw_line = draw_line32_funcs[dst_depth_index]; + break; + default: +- printf("sm501 update display : invalid control register value.\n"); +- abort(); +- break; ++ qemu_log_mask(LOG_GUEST_ERROR, "sm501: update display" ++ "invalid control register value.\n"); ++ return; + } + + /* set up to draw hardware cursor */ +-- +2.25.1 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-12829_2.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-12829_2.patch new file mode 100644 index 0000000000..e7258a43d3 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-12829_2.patch @@ -0,0 +1,139 @@ +From 6f8183b5dc5b309378687830a25e85ea8fb860ea Mon Sep 17 00:00:00 2001 +From: BALATON Zoltan <balaton@eik.bme.hu> +Date: Thu, 21 May 2020 21:39:44 +0200 +Subject: [PATCH 2/5] sm501: Shorten long variable names in sm501_2d_operation + +This increases readability and cleans up some confusing naming. + +Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu> +Message-id: b9b67b94c46e945252a73c77dfd117132c63c4fb.1590089984.git.balaton@eik.bme.hu +Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> + +Upstream-Status: Backport +CVE: CVE-2020-12829 dep#2 +Signed-off-by: Armin Kuster <akuster@mvista.com> + +--- + hw/display/sm501.c | 45 ++++++++++++++++++++++----------------------- + 1 file changed, 22 insertions(+), 23 deletions(-) + +diff --git a/hw/display/sm501.c b/hw/display/sm501.c +index bd3ccfe311..f42d05e1e4 100644 +--- a/hw/display/sm501.c ++++ b/hw/display/sm501.c +@@ -700,17 +700,16 @@ static inline void hwc_invalidate(SM501State *s, int crt) + static void sm501_2d_operation(SM501State *s) + { + /* obtain operation parameters */ +- int operation = (s->twoD_control >> 16) & 0x1f; ++ int cmd = (s->twoD_control >> 16) & 0x1F; + int rtl = s->twoD_control & 0x8000000; + int src_x = (s->twoD_source >> 16) & 0x01FFF; + int src_y = s->twoD_source & 0xFFFF; + int dst_x = (s->twoD_destination >> 16) & 0x01FFF; + int dst_y = s->twoD_destination & 0xFFFF; +- int operation_width = (s->twoD_dimension >> 16) & 0x1FFF; +- int operation_height = s->twoD_dimension & 0xFFFF; ++ int width = (s->twoD_dimension >> 16) & 0x1FFF; ++ int height = s->twoD_dimension & 0xFFFF; + uint32_t color = s->twoD_foreground; +- int format_flags = (s->twoD_stretch >> 20) & 0x3; +- int addressing = (s->twoD_stretch >> 16) & 0xF; ++ int format = (s->twoD_stretch >> 20) & 0x3; + int rop_mode = (s->twoD_control >> 15) & 0x1; /* 1 for rop2, else rop3 */ + /* 1 if rop2 source is the pattern, otherwise the source is the bitmap */ + int rop2_source_is_pattern = (s->twoD_control >> 14) & 0x1; +@@ -721,12 +720,12 @@ static void sm501_2d_operation(SM501State *s) + /* get frame buffer info */ + uint8_t *src = s->local_mem + src_base; + uint8_t *dst = s->local_mem + dst_base; +- int src_width = s->twoD_pitch & 0x1FFF; +- int dst_width = (s->twoD_pitch >> 16) & 0x1FFF; ++ int src_pitch = s->twoD_pitch & 0x1FFF; ++ int dst_pitch = (s->twoD_pitch >> 16) & 0x1FFF; + int crt = (s->dc_crt_control & SM501_DC_CRT_CONTROL_SEL) ? 1 : 0; + int fb_len = get_width(s, crt) * get_height(s, crt) * get_bpp(s, crt); + +- if (addressing != 0x0) { ++ if ((s->twoD_stretch >> 16) & 0xF) { + qemu_log_mask(LOG_UNIMP, "sm501: only XY addressing is supported.\n"); + return; + } +@@ -758,20 +757,20 @@ static void sm501_2d_operation(SM501State *s) + return; + } + +- switch (operation) { ++ switch (cmd) { + case 0x00: /* copy area */ + #define COPY_AREA(_bpp, _pixel_type, rtl) { \ + int y, x, index_d, index_s; \ +- for (y = 0; y < operation_height; y++) { \ +- for (x = 0; x < operation_width; x++) { \ ++ for (y = 0; y < height; y++) { \ ++ for (x = 0; x < width; x++) { \ + _pixel_type val; \ + \ + if (rtl) { \ +- index_s = ((src_y - y) * src_width + src_x - x) * _bpp; \ +- index_d = ((dst_y - y) * dst_width + dst_x - x) * _bpp; \ ++ index_s = ((src_y - y) * src_pitch + src_x - x) * _bpp; \ ++ index_d = ((dst_y - y) * dst_pitch + dst_x - x) * _bpp; \ + } else { \ +- index_s = ((src_y + y) * src_width + src_x + x) * _bpp; \ +- index_d = ((dst_y + y) * dst_width + dst_x + x) * _bpp; \ ++ index_s = ((src_y + y) * src_pitch + src_x + x) * _bpp; \ ++ index_d = ((dst_y + y) * dst_pitch + dst_x + x) * _bpp; \ + } \ + if (rop_mode == 1 && rop == 5) { \ + /* Invert dest */ \ +@@ -783,7 +782,7 @@ static void sm501_2d_operation(SM501State *s) + } \ + } \ + } +- switch (format_flags) { ++ switch (format) { + case 0: + COPY_AREA(1, uint8_t, rtl); + break; +@@ -799,15 +798,15 @@ static void sm501_2d_operation(SM501State *s) + case 0x01: /* fill rectangle */ + #define FILL_RECT(_bpp, _pixel_type) { \ + int y, x; \ +- for (y = 0; y < operation_height; y++) { \ +- for (x = 0; x < operation_width; x++) { \ +- int index = ((dst_y + y) * dst_width + dst_x + x) * _bpp; \ ++ for (y = 0; y < height; y++) { \ ++ for (x = 0; x < width; x++) { \ ++ int index = ((dst_y + y) * dst_pitch + dst_x + x) * _bpp; \ + *(_pixel_type *)&dst[index] = (_pixel_type)color; \ + } \ + } \ + } + +- switch (format_flags) { ++ switch (format) { + case 0: + FILL_RECT(1, uint8_t); + break; +@@ -824,14 +823,14 @@ static void sm501_2d_operation(SM501State *s) + + default: + qemu_log_mask(LOG_UNIMP, "sm501: not implemented 2D operation: %d\n", +- operation); ++ cmd); + return; + } + + if (dst_base >= get_fb_addr(s, crt) && + dst_base <= get_fb_addr(s, crt) + fb_len) { +- int dst_len = MIN(fb_len, ((dst_y + operation_height - 1) * dst_width + +- dst_x + operation_width) * (1 << format_flags)); ++ int dst_len = MIN(fb_len, ((dst_y + height - 1) * dst_pitch + ++ dst_x + width) * (1 << format)); + if (dst_len) { + memory_region_set_dirty(&s->local_mem_region, dst_base, dst_len); + } +-- +2.25.1 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-12829_3.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-12829_3.patch new file mode 100644 index 0000000000..c647028cfe --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-12829_3.patch @@ -0,0 +1,47 @@ +From 2824809b7f8f03ddc6e2b7e33e78c06022424298 Mon Sep 17 00:00:00 2001 +From: BALATON Zoltan <balaton@eik.bme.hu> +Date: Thu, 21 May 2020 21:39:44 +0200 +Subject: [PATCH 3/5] sm501: Use BIT(x) macro to shorten constant +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu> +Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> +Message-id: 124bf5de8d7cf503b32b377d0445029a76bfbd49.1590089984.git.balaton@eik.bme.hu +Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> + +Upstream-Status: Backport +CVE: CVE-2020-12829 dep#3 +Signed-off-by: Armin Kuster <akuster@mvista.com> + +--- + hw/display/sm501.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/hw/display/sm501.c b/hw/display/sm501.c +index f42d05e1e4..97660090bb 100644 +--- a/hw/display/sm501.c ++++ b/hw/display/sm501.c +@@ -701,7 +701,7 @@ static void sm501_2d_operation(SM501State *s) + { + /* obtain operation parameters */ + int cmd = (s->twoD_control >> 16) & 0x1F; +- int rtl = s->twoD_control & 0x8000000; ++ int rtl = s->twoD_control & BIT(27); + int src_x = (s->twoD_source >> 16) & 0x01FFF; + int src_y = s->twoD_source & 0xFFFF; + int dst_x = (s->twoD_destination >> 16) & 0x01FFF; +@@ -751,8 +751,7 @@ static void sm501_2d_operation(SM501State *s) + } + } + +- if ((s->twoD_source_base & 0x08000000) || +- (s->twoD_destination_base & 0x08000000)) { ++ if (s->twoD_source_base & BIT(27) || s->twoD_destination_base & BIT(27)) { + qemu_log_mask(LOG_UNIMP, "sm501: only local memory is supported.\n"); + return; + } +-- +2.25.1 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-12829_4.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-12829_4.patch new file mode 100644 index 0000000000..485af05e1e --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-12829_4.patch @@ -0,0 +1,100 @@ +From 3d0b096298b5579a7fa0753ad90968b27bc65372 Mon Sep 17 00:00:00 2001 +From: BALATON Zoltan <balaton@eik.bme.hu> +Date: Thu, 21 May 2020 21:39:44 +0200 +Subject: [PATCH 4/5] sm501: Clean up local variables in sm501_2d_operation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Make variables local to the block they are used in to make it clearer +which operation they are needed for. + +Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu> +Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> +Message-id: ae59f8138afe7f6a5a4a82539d0f61496a906b06.1590089984.git.balaton@eik.bme.hu +Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> + +Upstream-Status: Backport +CVE: CVE-2020-12829 dep#4 +Signed-off-by: Armin Kuster <akuster@mvista.com> + +--- + hw/display/sm501.c | 31 ++++++++++++++++--------------- + 1 file changed, 16 insertions(+), 15 deletions(-) + +diff --git a/hw/display/sm501.c b/hw/display/sm501.c +index 97660090bb..5ed57703d8 100644 +--- a/hw/display/sm501.c ++++ b/hw/display/sm501.c +@@ -699,28 +699,19 @@ static inline void hwc_invalidate(SM501State *s, int crt) + + static void sm501_2d_operation(SM501State *s) + { +- /* obtain operation parameters */ + int cmd = (s->twoD_control >> 16) & 0x1F; + int rtl = s->twoD_control & BIT(27); +- int src_x = (s->twoD_source >> 16) & 0x01FFF; +- int src_y = s->twoD_source & 0xFFFF; +- int dst_x = (s->twoD_destination >> 16) & 0x01FFF; +- int dst_y = s->twoD_destination & 0xFFFF; +- int width = (s->twoD_dimension >> 16) & 0x1FFF; +- int height = s->twoD_dimension & 0xFFFF; +- uint32_t color = s->twoD_foreground; + int format = (s->twoD_stretch >> 20) & 0x3; + int rop_mode = (s->twoD_control >> 15) & 0x1; /* 1 for rop2, else rop3 */ + /* 1 if rop2 source is the pattern, otherwise the source is the bitmap */ + int rop2_source_is_pattern = (s->twoD_control >> 14) & 0x1; + int rop = s->twoD_control & 0xFF; +- uint32_t src_base = s->twoD_source_base & 0x03FFFFFF; ++ int dst_x = (s->twoD_destination >> 16) & 0x01FFF; ++ int dst_y = s->twoD_destination & 0xFFFF; ++ int width = (s->twoD_dimension >> 16) & 0x1FFF; ++ int height = s->twoD_dimension & 0xFFFF; + uint32_t dst_base = s->twoD_destination_base & 0x03FFFFFF; +- +- /* get frame buffer info */ +- uint8_t *src = s->local_mem + src_base; + uint8_t *dst = s->local_mem + dst_base; +- int src_pitch = s->twoD_pitch & 0x1FFF; + int dst_pitch = (s->twoD_pitch >> 16) & 0x1FFF; + int crt = (s->dc_crt_control & SM501_DC_CRT_CONTROL_SEL) ? 1 : 0; + int fb_len = get_width(s, crt) * get_height(s, crt) * get_bpp(s, crt); +@@ -758,6 +749,13 @@ static void sm501_2d_operation(SM501State *s) + + switch (cmd) { + case 0x00: /* copy area */ ++ { ++ int src_x = (s->twoD_source >> 16) & 0x01FFF; ++ int src_y = s->twoD_source & 0xFFFF; ++ uint32_t src_base = s->twoD_source_base & 0x03FFFFFF; ++ uint8_t *src = s->local_mem + src_base; ++ int src_pitch = s->twoD_pitch & 0x1FFF; ++ + #define COPY_AREA(_bpp, _pixel_type, rtl) { \ + int y, x, index_d, index_s; \ + for (y = 0; y < height; y++) { \ +@@ -793,8 +791,11 @@ static void sm501_2d_operation(SM501State *s) + break; + } + break; +- ++ } + case 0x01: /* fill rectangle */ ++ { ++ uint32_t color = s->twoD_foreground; ++ + #define FILL_RECT(_bpp, _pixel_type) { \ + int y, x; \ + for (y = 0; y < height; y++) { \ +@@ -819,7 +820,7 @@ static void sm501_2d_operation(SM501State *s) + break; + } + break; +- ++ } + default: + qemu_log_mask(LOG_UNIMP, "sm501: not implemented 2D operation: %d\n", + cmd); +-- +2.25.1 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-12829_5.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-12829_5.patch new file mode 100644 index 0000000000..ab09e8b039 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-12829_5.patch @@ -0,0 +1,266 @@ +From b15a22bbcbe6a78dc3d88fe3134985e4cdd87de4 Mon Sep 17 00:00:00 2001 +From: BALATON Zoltan <balaton@eik.bme.hu> +Date: Thu, 21 May 2020 21:39:44 +0200 +Subject: [PATCH 5/5] sm501: Replace hand written implementation with pixman + where possible + +Besides being faster this should also prevent malicious guests to +abuse 2D engine to overwrite data or cause a crash. + +Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu> +Message-id: 58666389b6cae256e4e972a32c05cf8aa51bffc0.1590089984.git.balaton@eik.bme.hu +Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> + +Upstream-Status: Backport +CVE: CVE-2020-12829 +Signed-off-by: Armin Kuster <akuster@mvista.com> + +--- + hw/display/sm501.c | 207 ++++++++++++++++++++++++++------------------- + 1 file changed, 119 insertions(+), 88 deletions(-) + +diff --git a/hw/display/sm501.c b/hw/display/sm501.c +index 5ed57703d8..8bf4d111f4 100644 +--- a/hw/display/sm501.c ++++ b/hw/display/sm501.c +@@ -706,13 +706,12 @@ static void sm501_2d_operation(SM501State *s) + /* 1 if rop2 source is the pattern, otherwise the source is the bitmap */ + int rop2_source_is_pattern = (s->twoD_control >> 14) & 0x1; + int rop = s->twoD_control & 0xFF; +- int dst_x = (s->twoD_destination >> 16) & 0x01FFF; +- int dst_y = s->twoD_destination & 0xFFFF; +- int width = (s->twoD_dimension >> 16) & 0x1FFF; +- int height = s->twoD_dimension & 0xFFFF; ++ unsigned int dst_x = (s->twoD_destination >> 16) & 0x01FFF; ++ unsigned int dst_y = s->twoD_destination & 0xFFFF; ++ unsigned int width = (s->twoD_dimension >> 16) & 0x1FFF; ++ unsigned int height = s->twoD_dimension & 0xFFFF; + uint32_t dst_base = s->twoD_destination_base & 0x03FFFFFF; +- uint8_t *dst = s->local_mem + dst_base; +- int dst_pitch = (s->twoD_pitch >> 16) & 0x1FFF; ++ unsigned int dst_pitch = (s->twoD_pitch >> 16) & 0x1FFF; + int crt = (s->dc_crt_control & SM501_DC_CRT_CONTROL_SEL) ? 1 : 0; + int fb_len = get_width(s, crt) * get_height(s, crt) * get_bpp(s, crt); + +@@ -721,104 +720,136 @@ static void sm501_2d_operation(SM501State *s) + return; + } + +- if (rop_mode == 0) { +- if (rop != 0xcc) { +- /* Anything other than plain copies are not supported */ +- qemu_log_mask(LOG_UNIMP, "sm501: rop3 mode with rop %x is not " +- "supported.\n", rop); +- } +- } else { +- if (rop2_source_is_pattern && rop != 0x5) { +- /* For pattern source, we support only inverse dest */ +- qemu_log_mask(LOG_UNIMP, "sm501: rop2 source being the pattern and " +- "rop %x is not supported.\n", rop); +- } else { +- if (rop != 0x5 && rop != 0xc) { +- /* Anything other than plain copies or inverse dest is not +- * supported */ +- qemu_log_mask(LOG_UNIMP, "sm501: rop mode %x is not " +- "supported.\n", rop); +- } +- } +- } +- + if (s->twoD_source_base & BIT(27) || s->twoD_destination_base & BIT(27)) { + qemu_log_mask(LOG_UNIMP, "sm501: only local memory is supported.\n"); + return; + } + ++ if (!dst_pitch) { ++ qemu_log_mask(LOG_GUEST_ERROR, "sm501: Zero dest pitch.\n"); ++ return; ++ } ++ ++ if (!width || !height) { ++ qemu_log_mask(LOG_GUEST_ERROR, "sm501: Zero size 2D op.\n"); ++ return; ++ } ++ ++ if (rtl) { ++ dst_x -= width - 1; ++ dst_y -= height - 1; ++ } ++ ++ if (dst_base >= get_local_mem_size(s) || dst_base + ++ (dst_x + width + (dst_y + height) * (dst_pitch + width)) * ++ (1 << format) >= get_local_mem_size(s)) { ++ qemu_log_mask(LOG_GUEST_ERROR, "sm501: 2D op dest is outside vram.\n"); ++ return; ++ } ++ + switch (cmd) { +- case 0x00: /* copy area */ ++ case 0: /* BitBlt */ + { +- int src_x = (s->twoD_source >> 16) & 0x01FFF; +- int src_y = s->twoD_source & 0xFFFF; ++ unsigned int src_x = (s->twoD_source >> 16) & 0x01FFF; ++ unsigned int src_y = s->twoD_source & 0xFFFF; + uint32_t src_base = s->twoD_source_base & 0x03FFFFFF; +- uint8_t *src = s->local_mem + src_base; +- int src_pitch = s->twoD_pitch & 0x1FFF; +- +-#define COPY_AREA(_bpp, _pixel_type, rtl) { \ +- int y, x, index_d, index_s; \ +- for (y = 0; y < height; y++) { \ +- for (x = 0; x < width; x++) { \ +- _pixel_type val; \ +- \ +- if (rtl) { \ +- index_s = ((src_y - y) * src_pitch + src_x - x) * _bpp; \ +- index_d = ((dst_y - y) * dst_pitch + dst_x - x) * _bpp; \ +- } else { \ +- index_s = ((src_y + y) * src_pitch + src_x + x) * _bpp; \ +- index_d = ((dst_y + y) * dst_pitch + dst_x + x) * _bpp; \ +- } \ +- if (rop_mode == 1 && rop == 5) { \ +- /* Invert dest */ \ +- val = ~*(_pixel_type *)&dst[index_d]; \ +- } else { \ +- val = *(_pixel_type *)&src[index_s]; \ +- } \ +- *(_pixel_type *)&dst[index_d] = val; \ +- } \ +- } \ +- } +- switch (format) { +- case 0: +- COPY_AREA(1, uint8_t, rtl); +- break; +- case 1: +- COPY_AREA(2, uint16_t, rtl); +- break; +- case 2: +- COPY_AREA(4, uint32_t, rtl); +- break; ++ unsigned int src_pitch = s->twoD_pitch & 0x1FFF; ++ ++ if (!src_pitch) { ++ qemu_log_mask(LOG_GUEST_ERROR, "sm501: Zero src pitch.\n"); ++ return; ++ } ++ ++ if (rtl) { ++ src_x -= width - 1; ++ src_y -= height - 1; ++ } ++ ++ if (src_base >= get_local_mem_size(s) || src_base + ++ (src_x + width + (src_y + height) * (src_pitch + width)) * ++ (1 << format) >= get_local_mem_size(s)) { ++ qemu_log_mask(LOG_GUEST_ERROR, ++ "sm501: 2D op src is outside vram.\n"); ++ return; ++ } ++ ++ if ((rop_mode && rop == 0x5) || (!rop_mode && rop == 0x55)) { ++ /* Invert dest, is there a way to do this with pixman? */ ++ unsigned int x, y, i; ++ uint8_t *d = s->local_mem + dst_base; ++ ++ for (y = 0; y < height; y++) { ++ i = (dst_x + (dst_y + y) * dst_pitch) * (1 << format); ++ for (x = 0; x < width; x++, i += (1 << format)) { ++ switch (format) { ++ case 0: ++ d[i] = ~d[i]; ++ break; ++ case 1: ++ *(uint16_t *)&d[i] = ~*(uint16_t *)&d[i]; ++ break; ++ case 2: ++ *(uint32_t *)&d[i] = ~*(uint32_t *)&d[i]; ++ break; ++ } ++ } ++ } ++ } else { ++ /* Do copy src for unimplemented ops, better than unpainted area */ ++ if ((rop_mode && (rop != 0xc || rop2_source_is_pattern)) || ++ (!rop_mode && rop != 0xcc)) { ++ qemu_log_mask(LOG_UNIMP, ++ "sm501: rop%d op %x%s not implemented\n", ++ (rop_mode ? 2 : 3), rop, ++ (rop2_source_is_pattern ? ++ " with pattern source" : "")); ++ } ++ /* Check for overlaps, this could be made more exact */ ++ uint32_t sb, se, db, de; ++ sb = src_base + src_x + src_y * (width + src_pitch); ++ se = sb + width + height * (width + src_pitch); ++ db = dst_base + dst_x + dst_y * (width + dst_pitch); ++ de = db + width + height * (width + dst_pitch); ++ if (rtl && ((db >= sb && db <= se) || (de >= sb && de <= se))) { ++ /* regions may overlap: copy via temporary */ ++ int llb = width * (1 << format); ++ int tmp_stride = DIV_ROUND_UP(llb, sizeof(uint32_t)); ++ uint32_t *tmp = g_malloc(tmp_stride * sizeof(uint32_t) * ++ height); ++ pixman_blt((uint32_t *)&s->local_mem[src_base], tmp, ++ src_pitch * (1 << format) / sizeof(uint32_t), ++ tmp_stride, 8 * (1 << format), 8 * (1 << format), ++ src_x, src_y, 0, 0, width, height); ++ pixman_blt(tmp, (uint32_t *)&s->local_mem[dst_base], ++ tmp_stride, ++ dst_pitch * (1 << format) / sizeof(uint32_t), ++ 8 * (1 << format), 8 * (1 << format), ++ 0, 0, dst_x, dst_y, width, height); ++ g_free(tmp); ++ } else { ++ pixman_blt((uint32_t *)&s->local_mem[src_base], ++ (uint32_t *)&s->local_mem[dst_base], ++ src_pitch * (1 << format) / sizeof(uint32_t), ++ dst_pitch * (1 << format) / sizeof(uint32_t), ++ 8 * (1 << format), 8 * (1 << format), ++ src_x, src_y, dst_x, dst_y, width, height); ++ } + } + break; + } +- case 0x01: /* fill rectangle */ ++ case 1: /* Rectangle Fill */ + { + uint32_t color = s->twoD_foreground; + +-#define FILL_RECT(_bpp, _pixel_type) { \ +- int y, x; \ +- for (y = 0; y < height; y++) { \ +- for (x = 0; x < width; x++) { \ +- int index = ((dst_y + y) * dst_pitch + dst_x + x) * _bpp; \ +- *(_pixel_type *)&dst[index] = (_pixel_type)color; \ +- } \ +- } \ +- } +- +- switch (format) { +- case 0: +- FILL_RECT(1, uint8_t); +- break; +- case 1: +- color = cpu_to_le16(color); +- FILL_RECT(2, uint16_t); +- break; +- case 2: ++ if (format == 2) { + color = cpu_to_le32(color); +- FILL_RECT(4, uint32_t); +- break; ++ } else if (format == 1) { ++ color = cpu_to_le16(color); + } ++ ++ pixman_fill((uint32_t *)&s->local_mem[dst_base], ++ dst_pitch * (1 << format) / sizeof(uint32_t), ++ 8 * (1 << format), dst_x, dst_y, width, height, color); + break; + } + default: +-- +2.25.1 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-13253_1.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-13253_1.patch new file mode 100644 index 0000000000..7f8383987c --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-13253_1.patch @@ -0,0 +1,50 @@ +From 6dd3a164f5b31c703c7d8372841ad3bd6a57de6d Mon Sep 17 00:00:00 2001 +From: =?utf8?q?Philippe=20Mathieu-Daud=C3=A9?= <f4bug@amsat.org> +Date: Tue, 5 Jun 2018 22:28:51 -0300 +Subject: [PATCH 1/1] hw/sd/sdcard: Simplify realize() a bit +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf8 +Content-Transfer-Encoding: 8bit + +We don't need to check if sd->blk is set twice. + +Reviewed-by: Peter Maydell <peter.maydell@linaro.org> +Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org> +Reviewed-by: Alistair Francis <alistair.francis@wdc.com> +Message-Id: <20200630133912.9428-18-f4bug@amsat.org> + +Upstram-Status: Backport: +https://git.qemu.org/?p=qemu.git;a=commit;f=hw/sd/sd.c;h=6dd3a164f5b31c703c7d8372841ad3bd6a57de6d + +CVE: CVE-2020-13253 + +Signed-off-by: Davide Gardenal <davide.gardenal@huawei.com> +--- + hw/sd/sd.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/hw/sd/sd.c b/hw/sd/sd.c +index 1cc16bf..edd60a0 100644 +--- a/hw/sd/sd.c ++++ b/hw/sd/sd.c +@@ -2105,12 +2105,12 @@ static void sd_realize(DeviceState *dev, Error **errp) + return; + } + +- if (sd->blk && blk_is_read_only(sd->blk)) { +- error_setg(errp, "Cannot use read-only drive as SD card"); +- return; +- } +- + if (sd->blk) { ++ if (blk_is_read_only(sd->blk)) { ++ error_setg(errp, "Cannot use read-only drive as SD card"); ++ return; ++ } ++ + ret = blk_set_perm(sd->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE, + BLK_PERM_ALL, errp); + if (ret < 0) { +-- +1.8.3.1 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-13253_2.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-13253_2.patch new file mode 100644 index 0000000000..53145d059f --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-13253_2.patch @@ -0,0 +1,112 @@ +From a9bcedd15a5834ca9ae6c3a97933e85ac7edbd36 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= <f4bug@amsat.org> +Date: Tue, 7 Jul 2020 13:02:34 +0200 +Subject: [PATCH] hw/sd/sdcard: Do not allow invalid SD card sizes +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +QEMU allows to create SD card with unrealistic sizes. This could +work, but some guests (at least Linux) consider sizes that are not +a power of 2 as a firmware bug and fix the card size to the next +power of 2. + +While the possibility to use small SD card images has been seen as +a feature, it became a bug with CVE-2020-13253, where the guest is +able to do OOB read/write accesses past the image size end. + +In a pair of commits we will fix CVE-2020-13253 as: + + Read command is rejected if BLOCK_LEN_ERROR or ADDRESS_ERROR + occurred and no data transfer is performed. + + Write command is rejected if BLOCK_LEN_ERROR or ADDRESS_ERROR + occurred and no data transfer is performed. + + WP_VIOLATION errors are not modified: the error bit is set, we + stay in receive-data state, wait for a stop command. All further + data transfer is ignored. See the check on sd->card_status at the + beginning of sd_read_data() and sd_write_data(). + +While this is the correct behavior, in case QEMU create smaller SD +cards, guests still try to access past the image size end, and QEMU +considers this is an invalid address, thus "all further data transfer +is ignored". This is wrong and make the guest looping until +eventually timeouts. + +Fix by not allowing invalid SD card sizes (suggesting the expected +size as a hint): + + $ qemu-system-arm -M orangepi-pc -drive file=rootfs.ext2,if=sd,format=raw + qemu-system-arm: Invalid SD card size: 60 MiB + SD card size has to be a power of 2, e.g. 64 MiB. + You can resize disk images with 'qemu-img resize <imagefile> <new-size>' + (note that this will lose data if you make the image smaller than it currently is). + +Cc: qemu-stable@nongnu.org +Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org> +Reviewed-by: Alistair Francis <alistair.francis@wdc.com> +Reviewed-by: Peter Maydell <peter.maydell@linaro.org> +Message-Id: <20200713183209.26308-8-f4bug@amsat.org> + +Upstram-Status: Backport: +https://git.qemu.org/?p=qemu.git;a=commit;h=a9bcedd15a5834ca9ae6c3a97933e85ac7edbd36 + +CVE: CVE-2020-13253 + +Signed-off-by: Davide Gardenal <davide.gardenal@huawei.com> +--- + hw/sd/sd.c | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/hw/sd/sd.c b/hw/sd/sd.c +index edd60a09c0..76d68359a4 100644 +--- a/hw/sd/sd.c ++++ b/hw/sd/sd.c +@@ -32,6 +32,7 @@ + + #include "qemu/osdep.h" + #include "qemu/units.h" ++#include "qemu/cutils.h" + #include "hw/irq.h" + #include "hw/registerfields.h" + #include "sysemu/block-backend.h" +@@ -2106,11 +2107,35 @@ static void sd_realize(DeviceState *dev, Error **errp) + } + + if (sd->blk) { ++ int64_t blk_size; ++ + if (blk_is_read_only(sd->blk)) { + error_setg(errp, "Cannot use read-only drive as SD card"); + return; + } + ++ blk_size = blk_getlength(sd->blk); ++ if (blk_size > 0 && !is_power_of_2(blk_size)) { ++ int64_t blk_size_aligned = pow2ceil(blk_size); ++ char *blk_size_str; ++ ++ blk_size_str = size_to_str(blk_size); ++ error_setg(errp, "Invalid SD card size: %s", blk_size_str); ++ g_free(blk_size_str); ++ ++ blk_size_str = size_to_str(blk_size_aligned); ++ error_append_hint(errp, ++ "SD card size has to be a power of 2, e.g. %s.\n" ++ "You can resize disk images with" ++ " 'qemu-img resize <imagefile> <new-size>'\n" ++ "(note that this will lose data if you make the" ++ " image smaller than it currently is).\n", ++ blk_size_str); ++ g_free(blk_size_str); ++ ++ return; ++ } ++ + ret = blk_set_perm(sd->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE, + BLK_PERM_ALL, errp); + if (ret < 0) { +-- +2.32.0 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-13253_3.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-13253_3.patch new file mode 100644 index 0000000000..b512b2bd7f --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-13253_3.patch @@ -0,0 +1,86 @@ +From 794d68de2f021a6d3874df41d6bbe8590ec05207 Mon Sep 17 00:00:00 2001 +From: =?utf8?q?Philippe=20Mathieu-Daud=C3=A9?= <f4bug@amsat.org> +Date: Mon, 13 Jul 2020 09:27:35 +0200 +Subject: [PATCH] hw/sd/sdcard: Update coding style to make checkpatch.pl happy +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf8 +Content-Transfer-Encoding: 8bit + +To make the next commit easier to review, clean this code first. + +Reviewed-by: Peter Maydell <peter.maydell@linaro.org> +Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org> +Reviewed-by: Alistair Francis <alistair.francis@wdc.com> +Reviewed-by: Alexander Bulekov <alxndr@bu.edu> +Message-Id: <20200630133912.9428-3-f4bug@amsat.org> + +Upstram-Status: Backport: +https://git.qemu.org/?p=qemu.git;a=commit;f=hw/sd/sd.c;h=794d68de2f021a6d3874df41d6bbe8590ec05207 + +CVE: CVE-2020-13253 + +Signed-off-by: Davide Gardenal <davide.gardenal@huawei.com> +--- +diff --git a/hw/sd/sd.c b/hw/sd/sd.c +--- a/hw/sd/sd.c (revision b0ca999a43a22b38158a222233d3f5881648bb4f) ++++ b/hw/sd/sd.c (date 1647514442924) +@@ -1154,8 +1154,9 @@ + sd->data_start = addr; + sd->data_offset = 0; + +- if (sd->data_start + sd->blk_len > sd->size) ++ if (sd->data_start + sd->blk_len > sd->size) { + sd->card_status |= ADDRESS_ERROR; ++ } + return sd_r1; + + default: +@@ -1170,8 +1171,9 @@ + sd->data_start = addr; + sd->data_offset = 0; + +- if (sd->data_start + sd->blk_len > sd->size) ++ if (sd->data_start + sd->blk_len > sd->size) { + sd->card_status |= ADDRESS_ERROR; ++ } + return sd_r1; + + default: +@@ -1216,12 +1218,15 @@ + sd->data_offset = 0; + sd->blk_written = 0; + +- if (sd->data_start + sd->blk_len > sd->size) ++ if (sd->data_start + sd->blk_len > sd->size) { + sd->card_status |= ADDRESS_ERROR; +- if (sd_wp_addr(sd, sd->data_start)) ++ } ++ if (sd_wp_addr(sd, sd->data_start)) { + sd->card_status |= WP_VIOLATION; +- if (sd->csd[14] & 0x30) ++ } ++ if (sd->csd[14] & 0x30) { + sd->card_status |= WP_VIOLATION; ++ } + return sd_r1; + + default: +@@ -1240,12 +1245,15 @@ + sd->data_offset = 0; + sd->blk_written = 0; + +- if (sd->data_start + sd->blk_len > sd->size) ++ if (sd->data_start + sd->blk_len > sd->size) { + sd->card_status |= ADDRESS_ERROR; +- if (sd_wp_addr(sd, sd->data_start)) ++ } ++ if (sd_wp_addr(sd, sd->data_start)) { + sd->card_status |= WP_VIOLATION; +- if (sd->csd[14] & 0x30) ++ } ++ if (sd->csd[14] & 0x30) { + sd->card_status |= WP_VIOLATION; ++ } + return sd_r1; + + default: diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-13253_4.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-13253_4.patch new file mode 100644 index 0000000000..6b4c1ec050 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-13253_4.patch @@ -0,0 +1,139 @@ +From 790762e5487114341cccc5bffcec4cb3c022c3cd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= <f4bug@amsat.org> +Date: Thu, 4 Jun 2020 19:22:29 +0200 +Subject: [PATCH] hw/sd/sdcard: Do not switch to ReceivingData if address is + invalid +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Only move the state machine to ReceivingData if there is no +pending error. This avoids later OOB access while processing +commands queued. + + "SD Specifications Part 1 Physical Layer Simplified Spec. v3.01" + + 4.3.3 Data Read + + Read command is rejected if BLOCK_LEN_ERROR or ADDRESS_ERROR + occurred and no data transfer is performed. + + 4.3.4 Data Write + + Write command is rejected if BLOCK_LEN_ERROR or ADDRESS_ERROR + occurred and no data transfer is performed. + +WP_VIOLATION errors are not modified: the error bit is set, we +stay in receive-data state, wait for a stop command. All further +data transfer is ignored. See the check on sd->card_status at the +beginning of sd_read_data() and sd_write_data(). + +Fixes: CVE-2020-13253 + +Cc: qemu-stable@nongnu.org +Reported-by: Alexander Bulekov <alxndr@bu.edu> +Buglink: https://bugs.launchpad.net/qemu/+bug/1880822 +Reviewed-by: Peter Maydell <peter.maydell@linaro.org> +Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org> +Reviewed-by: Alistair Francis <alistair.francis@wdc.com> +Message-Id: <20200630133912.9428-6-f4bug@amsat.org> + +Upstram-Status: Backport: +https://git.qemu.org/?p=qemu.git;a=commit;h=790762e5487114341cccc5bffcec4cb3c022c3cd + +CVE: CVE-2020-13253 + +Signed-off-by: Davide Gardenal <davide.gardenal@huawei.com> +--- + hw/sd/sd.c | 38 ++++++++++++++++++++++++-------------- + 1 file changed, 24 insertions(+), 14 deletions(-) + +diff --git a/hw/sd/sd.c b/hw/sd/sd.c +index f4f76f8fd2..fad9cf1ee7 100644 +--- a/hw/sd/sd.c ++++ b/hw/sd/sd.c +@@ -1171,13 +1171,15 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) + case 17: /* CMD17: READ_SINGLE_BLOCK */ + switch (sd->state) { + case sd_transfer_state: +- sd->state = sd_sendingdata_state; +- sd->data_start = addr; +- sd->data_offset = 0; + +- if (sd->data_start + sd->blk_len > sd->size) { ++ if (addr + sd->blk_len > sd->size) { + sd->card_status |= ADDRESS_ERROR; ++ return sd_r1; + } ++ ++ sd->state = sd_sendingdata_state; ++ sd->data_start = addr; ++ sd->data_offset = 0; + return sd_r1; + + default: +@@ -1188,13 +1190,15 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) + case 18: /* CMD18: READ_MULTIPLE_BLOCK */ + switch (sd->state) { + case sd_transfer_state: +- sd->state = sd_sendingdata_state; +- sd->data_start = addr; +- sd->data_offset = 0; + +- if (sd->data_start + sd->blk_len > sd->size) { ++ if (addr + sd->blk_len > sd->size) { + sd->card_status |= ADDRESS_ERROR; ++ return sd_r1; + } ++ ++ sd->state = sd_sendingdata_state; ++ sd->data_start = addr; ++ sd->data_offset = 0; + return sd_r1; + + default: +@@ -1234,14 +1238,17 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) + /* Writing in SPI mode not implemented. */ + if (sd->spi) + break; ++ ++ if (addr + sd->blk_len > sd->size) { ++ sd->card_status |= ADDRESS_ERROR; ++ return sd_r1; ++ } ++ + sd->state = sd_receivingdata_state; + sd->data_start = addr; + sd->data_offset = 0; + sd->blk_written = 0; + +- if (sd->data_start + sd->blk_len > sd->size) { +- sd->card_status |= ADDRESS_ERROR; +- } + if (sd_wp_addr(sd, sd->data_start)) { + sd->card_status |= WP_VIOLATION; + } +@@ -1261,14 +1268,17 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) + /* Writing in SPI mode not implemented. */ + if (sd->spi) + break; ++ ++ if (addr + sd->blk_len > sd->size) { ++ sd->card_status |= ADDRESS_ERROR; ++ return sd_r1; ++ } ++ + sd->state = sd_receivingdata_state; + sd->data_start = addr; + sd->data_offset = 0; + sd->blk_written = 0; + +- if (sd->data_start + sd->blk_len > sd->size) { +- sd->card_status |= ADDRESS_ERROR; +- } + if (sd_wp_addr(sd, sd->data_start)) { + sd->card_status |= WP_VIOLATION; + } +-- +2.32.0 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-13253_5.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-13253_5.patch new file mode 100644 index 0000000000..ffce610f79 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-13253_5.patch @@ -0,0 +1,54 @@ +From 9157dd597d293ab7f599f4d96c3fe8a6e07c633d Mon Sep 17 00:00:00 2001 +From: =?utf8?q?Philippe=20Mathieu-Daud=C3=A9?= <f4bug@amsat.org> +Date: Wed, 3 Jun 2020 19:59:16 +0200 +Subject: [PATCH] hw/sd/sdcard: Restrict Class 6 commands to SCSD cards +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf8 +Content-Transfer-Encoding: 8bit + +Only SCSD cards support Class 6 (Block Oriented Write Protection) +commands. + + "SD Specifications Part 1 Physical Layer Simplified Spec. v3.01" + + 4.3.14 Command Functional Difference in Card Capacity Types + + * Write Protected Group + + SDHC and SDXC do not support write-protected groups. Issuing + CMD28, CMD29 and CMD30 generates the ILLEGAL_COMMAND error. + +Cc: qemu-stable@nongnu.org +Reviewed-by: Peter Maydell <peter.maydell@linaro.org> +Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org> +Reviewed-by: Alistair Francis <alistair.francis@wdc.com> +Message-Id: <20200630133912.9428-7-f4bug@amsat.org> + +Upstram-Status: Backport: +https://git.qemu.org/?p=qemu.git;a=commit;h=9157dd597d293ab7f599f4d96c3fe8a6e07c633d + +CVE: CVE-2020-13253 + +Signed-off-by: Davide Gardenal <davide.gardenal@huawei.com> +--- + hw/sd/sd.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/hw/sd/sd.c b/hw/sd/sd.c +index 5137168..1cc16bf 100644 +--- a/hw/sd/sd.c ++++ b/hw/sd/sd.c +@@ -920,6 +920,11 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) + sd->multi_blk_cnt = 0; + } + ++ if (sd_cmd_class[req.cmd] == 6 && FIELD_EX32(sd->ocr, OCR, CARD_CAPACITY)) { ++ /* Only Standard Capacity cards support class 6 commands */ ++ return sd_illegal; ++ } ++ + switch (req.cmd) { + /* Basic commands (Class 0 and Class 1) */ + case 0: /* CMD0: GO_IDLE_STATE */ +-- +1.8.3.1 diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-13754-1.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-13754-1.patch new file mode 100644 index 0000000000..fdfff9d81d --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-13754-1.patch @@ -0,0 +1,91 @@ +From 5d971f9e672507210e77d020d89e0e89165c8fc9 Mon Sep 17 00:00:00 2001 +From: "Michael S. Tsirkin" <mst@redhat.com> +Date: Wed, 10 Jun 2020 09:47:49 -0400 +Subject: [PATCH] memory: Revert "memory: accept mismatching sizes in + memory_region_access_valid" + +Memory API documentation documents valid .min_access_size and .max_access_size +fields and explains that any access outside these boundaries is blocked. + +This is what devices seem to assume. + +However this is not what the implementation does: it simply +ignores the boundaries unless there's an "accepts" callback. + +Naturally, this breaks a bunch of devices. + +Revert to the documented behaviour. + +Devices that want to allow any access can just drop the valid field, +or add the impl field to have accesses converted to appropriate +length. + +Cc: qemu-stable@nongnu.org +Reviewed-by: Richard Henderson <rth@twiddle.net> +Fixes: CVE-2020-13754 +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1842363 +Fixes: a014ed07bd5a ("memory: accept mismatching sizes in memory_region_access_valid") +Signed-off-by: Michael S. Tsirkin <mst@redhat.com> +Message-Id: <20200610134731.1514409-1-mst@redhat.com> +Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> + +https://git.qemu.org/?p=qemu.git;a=patch;h=5d971f9e672507210e77d020d89e0e89165c8fc9 +CVE: CVE-2020-13754 +Upstream-Status: Backport +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> +--- + memory.c | 29 +++++++++-------------------- + 1 file changed, 9 insertions(+), 20 deletions(-) + +diff --git a/memory.c b/memory.c +index 2f15a4b..9200b20 100644 +--- a/memory.c ++++ b/memory.c +@@ -1352,35 +1352,24 @@ bool memory_region_access_valid(MemoryRegion *mr, + bool is_write, + MemTxAttrs attrs) + { +- int access_size_min, access_size_max; +- int access_size, i; +- +- if (!mr->ops->valid.unaligned && (addr & (size - 1))) { ++ if (mr->ops->valid.accepts ++ && !mr->ops->valid.accepts(mr->opaque, addr, size, is_write, attrs)) { + return false; + } + +- if (!mr->ops->valid.accepts) { +- return true; +- } +- +- access_size_min = mr->ops->valid.min_access_size; +- if (!mr->ops->valid.min_access_size) { +- access_size_min = 1; ++ if (!mr->ops->valid.unaligned && (addr & (size - 1))) { ++ return false; + } + +- access_size_max = mr->ops->valid.max_access_size; ++ /* Treat zero as compatibility all valid */ + if (!mr->ops->valid.max_access_size) { +- access_size_max = 4; ++ return true; + } + +- access_size = MAX(MIN(size, access_size_max), access_size_min); +- for (i = 0; i < size; i += access_size) { +- if (!mr->ops->valid.accepts(mr->opaque, addr + i, access_size, +- is_write, attrs)) { +- return false; +- } ++ if (size > mr->ops->valid.max_access_size ++ || size < mr->ops->valid.min_access_size) { ++ return false; + } +- + return true; + } + +-- +1.8.3.1 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-13754-2.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-13754-2.patch new file mode 100644 index 0000000000..7354edc54d --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-13754-2.patch @@ -0,0 +1,69 @@ +From dba04c3488c4699f5afe96f66e448b1d447cf3fb Mon Sep 17 00:00:00 2001 +From: Michael Tokarev <mjt@tls.msk.ru> +Date: Mon, 20 Jul 2020 19:06:27 +0300 +Subject: [PATCH] acpi: accept byte and word access to core ACPI registers + +All ISA registers should be accessible as bytes, words or dwords +(if wide enough). Fix the access constraints for acpi-pm-evt, +acpi-pm-tmr & acpi-cnt registers. + +Fixes: 5d971f9e67 (memory: Revert "memory: accept mismatching sizes in memory_region_access_valid") +Fixes: afafe4bbe0 (apci: switch cnt to memory api) +Fixes: 77d58b1e47 (apci: switch timer to memory api) +Fixes: b5a7c024d2 (apci: switch evt to memory api) +Buglink: https://lore.kernel.org/xen-devel/20200630170913.123646-1-anthony.perard@citrix.com/T/ +Buglink: https://bugs.debian.org/964793 +BugLink: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=964247 +BugLink: https://bugs.launchpad.net/bugs/1886318 +Reported-By: Simon John <git@the-jedi.co.uk> +Signed-off-by: Michael Tokarev <mjt@tls.msk.ru> +Message-Id: <20200720160627.15491-1-mjt@msgid.tls.msk.ru> +Cc: qemu-stable@nongnu.org +Reviewed-by: Michael S. Tsirkin <mst@redhat.com> +Signed-off-by: Michael S. Tsirkin <mst@redhat.com> + +https://git.qemu.org/?p=qemu.git;a=patch;h=dba04c3488c4699f5afe96f66e448b1d447cf3fb +CVE: CVE-2020-13754 +Upstream-Status: Backport +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> +--- + hw/acpi/core.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/hw/acpi/core.c b/hw/acpi/core.c +index f6d9ec4..ac06db3 100644 +--- a/hw/acpi/core.c ++++ b/hw/acpi/core.c +@@ -458,7 +458,8 @@ static void acpi_pm_evt_write(void *opaque, hwaddr addr, uint64_t val, + static const MemoryRegionOps acpi_pm_evt_ops = { + .read = acpi_pm_evt_read, + .write = acpi_pm_evt_write, +- .valid.min_access_size = 2, ++ .impl.min_access_size = 2, ++ .valid.min_access_size = 1, + .valid.max_access_size = 2, + .endianness = DEVICE_LITTLE_ENDIAN, + }; +@@ -527,7 +528,8 @@ static void acpi_pm_tmr_write(void *opaque, hwaddr addr, uint64_t val, + static const MemoryRegionOps acpi_pm_tmr_ops = { + .read = acpi_pm_tmr_read, + .write = acpi_pm_tmr_write, +- .valid.min_access_size = 4, ++ .impl.min_access_size = 4, ++ .valid.min_access_size = 1, + .valid.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, + }; +@@ -599,7 +601,8 @@ static void acpi_pm_cnt_write(void *opaque, hwaddr addr, uint64_t val, + static const MemoryRegionOps acpi_pm_cnt_ops = { + .read = acpi_pm_cnt_read, + .write = acpi_pm_cnt_write, +- .valid.min_access_size = 2, ++ .impl.min_access_size = 2, ++ .valid.min_access_size = 1, + .valid.max_access_size = 2, + .endianness = DEVICE_LITTLE_ENDIAN, + }; +-- +1.8.3.1 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-13754-3.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-13754-3.patch new file mode 100644 index 0000000000..2a8781050f --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-13754-3.patch @@ -0,0 +1,65 @@ +From 8e67fda2dd6202ccec093fda561107ba14830a17 Mon Sep 17 00:00:00 2001 +From: Laurent Vivier <lvivier@redhat.com> +Date: Tue, 21 Jul 2020 10:33:22 +0200 +Subject: [PATCH] xhci: fix valid.max_access_size to access address registers +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf8 +Content-Transfer-Encoding: 8bit + +QEMU XHCI advertises AC64 (64-bit addressing) but doesn't allow +64-bit mode access in "runtime" and "operational" MemoryRegionOps. + +Set the max_access_size based on sizeof(dma_addr_t) as AC64 is set. + +XHCI specs: +"If the xHC supports 64-bit addressing (AC64 = â1â), then software +should write 64-bit registers using only Qword accesses. If a +system is incapable of issuing Qword accesses, then writes to the +64-bit address fields shall be performed using 2 Dword accesses; +low Dword-first, high-Dword second. If the xHC supports 32-bit +addressing (AC64 = â0â), then the high Dword of registers containing +64-bit address fields are unused and software should write addresses +using only Dword accesses" + +The problem has been detected with SLOF, as linux kernel always accesses +registers using 32-bit access even if AC64 is set and revealed by +5d971f9e6725 ("memory: Revert "memory: accept mismatching sizes in memory_region_access_valid"") + +Suggested-by: Alexey Kardashevskiy <aik@au1.ibm.com> +Signed-off-by: Laurent Vivier <lvivier@redhat.com> +Message-id: 20200721083322.90651-1-lvivier@redhat.com +Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> + +https://git.qemu.org/?p=qemu.git;a=patch;h=8e67fda2dd6202ccec093fda561107ba14830a17 +CVE: CVE-2020-13754 +Upstream-Status: Backport +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> +--- + hw/usb/hcd-xhci.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index b330e36..67a18fe 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -3184,7 +3184,7 @@ static const MemoryRegionOps xhci_oper_ops = { + .read = xhci_oper_read, + .write = xhci_oper_write, + .valid.min_access_size = 4, +- .valid.max_access_size = 4, ++ .valid.max_access_size = sizeof(dma_addr_t), + .endianness = DEVICE_LITTLE_ENDIAN, + }; + +@@ -3200,7 +3200,7 @@ static const MemoryRegionOps xhci_runtime_ops = { + .read = xhci_runtime_read, + .write = xhci_runtime_write, + .valid.min_access_size = 4, +- .valid.max_access_size = 4, ++ .valid.max_access_size = sizeof(dma_addr_t), + .endianness = DEVICE_LITTLE_ENDIAN, + }; + +-- +1.8.3.1 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-13754-4.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-13754-4.patch new file mode 100644 index 0000000000..6bad07d03f --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-13754-4.patch @@ -0,0 +1,39 @@ +From 70b78d4e71494c90d2ccb40381336bc9b9a22f79 Mon Sep 17 00:00:00 2001 +From: Alistair Francis <alistair.francis@wdc.com> +Date: Tue, 30 Jun 2020 13:12:11 -0700 +Subject: [PATCH] hw/riscv: Allow 64 bit access to SiFive CLINT + +Commit 5d971f9e672507210e77d020d89e0e89165c8fc9 +"memory: Revert "memory: accept mismatching sizes in +memory_region_access_valid"" broke most RISC-V boards as they do 64 bit +accesses to the CLINT and QEMU would trigger a fault. Fix this failure +by allowing 8 byte accesses. + +Signed-off-by: Alistair Francis <alistair.francis@wdc.com> +Reviewed-by: LIU Zhiwei<zhiwei_liu@c-sky.com> +Message-Id: <122b78825b077e4dfd39b444d3a46fe894a7804c.1593547870.git.alistair.francis@wdc.com> + +https://git.qemu.org/?p=qemu.git;a=patch;h=70b78d4e71494c90d2ccb40381336bc9b9a22f79 +CVE: CVE-2020-13754 +Upstream-Status: Backport +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> +--- + hw/riscv/sifive_clint.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/riscv/sifive_clint.c b/hw/riscv/sifive_clint.c +index b11ffa0..669c21a 100644 +--- a/hw/riscv/sifive_clint.c ++++ b/hw/riscv/sifive_clint.c +@@ -181,7 +181,7 @@ static const MemoryRegionOps sifive_clint_ops = { + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, +- .max_access_size = 4 ++ .max_access_size = 8 + } + }; + +-- +1.8.3.1 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-13791.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-13791.patch new file mode 100644 index 0000000000..1e8278f7b7 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-13791.patch @@ -0,0 +1,44 @@ +Date: Thu, 4 Jun 2020 16:25:24 +0530 +From: Prasad J Pandit <pjp@fedoraproject.org> +Subject: [PATCH v3] ati-vga: check address before reading configuration bytes (CVE-2020-13791) + +While reading PCI configuration bytes, a guest may send an +address towards the end of the configuration space. It may lead +to an OOB access issue. Add check to ensure 'address + size' is +within PCI configuration space. + +CVE: CVE-2020-13791 + +Upstream-Status: Submitted +https://lists.gnu.org/archive/html/qemu-devel/2020-06/msg00979.html + +Reported-by: Ren Ding <rding@gatech.edu> +Reported-by: Hanqing Zhao <hanqing@gatech.edu> +Reported-by: Yi Ren <c4tren@gmail.com> +Suggested-by: BALATON Zoltan <balaton@eik.bme.hu> +Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org> +Signed-off-by: Davide Gardenal <davide.gardenal@huawei.com> +--- + hw/display/ati.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +Update v3: avoid modifying 'addr' variable + -> https://lists.gnu.org/archive/html/qemu-devel/2020-06/msg00834.html + +diff --git a/hw/display/ati.c b/hw/display/ati.c +index 67604e68de..b4d0fd88b7 100644 +--- a/hw/display/ati.c ++++ b/hw/display/ati.c +@@ -387,7 +387,9 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size) + val = s->regs.crtc_pitch; + break; + case 0xf00 ... 0xfff: +- val = pci_default_read_config(&s->dev, addr - 0xf00, size); ++ if ((addr - 0xf00) + size <= pci_config_size(&s->dev)) { ++ val = pci_default_read_config(&s->dev, addr - 0xf00, size); ++ } + break; + case CUR_OFFSET: + val = s->regs.cur_offset; +-- +2.26.2 diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-15469-1.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-15469-1.patch new file mode 100644 index 0000000000..20f39f0a26 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-15469-1.patch @@ -0,0 +1,50 @@ +From 520f26fc6d17b71a43eaf620e834b3bdf316f3d3 Mon Sep 17 00:00:00 2001 +From: Prasad J Pandit <pjp@fedoraproject.org> +Date: Tue, 11 Aug 2020 17:11:25 +0530 +Subject: [PATCH] hw/pci-host: add pci-intack write method + +Add pci-intack mmio write method to avoid NULL pointer dereference +issue. + +Reported-by: Lei Sun <slei.casper@gmail.com> +Reviewed-by: Li Qiang <liq3ea@gmail.com> +Reviewed-by: Peter Maydell <peter.maydell@linaro.org> +Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org> +Message-Id: <20200811114133.672647-2-ppandit@redhat.com> +Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> + +CVE: CVE-2020-15469 +Upstream-Status: Backport [import from ubuntu +https://git.launchpad.net/ubuntu/+source/qemu/tree/debian/patches/CVE-2020-15469-1.patch?h=ubuntu/focal-security +Upstream commit https://github.com/qemu/qemu/commit/520f26fc6d17b71a43eaf620e834b3bdf316f3d3 ] +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> +--- + hw/pci-host/prep.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/hw/pci-host/prep.c ++++ b/hw/pci-host/prep.c +@@ -26,6 +26,7 @@ + #include "qemu/osdep.h" + #include "qemu-common.h" + #include "qemu/units.h" ++#include "qemu/log.h" + #include "qapi/error.h" + #include "hw/pci/pci.h" + #include "hw/pci/pci_bus.h" +@@ -119,8 +120,15 @@ static uint64_t raven_intack_read(void * + return pic_read_irq(isa_pic); + } + ++static void raven_intack_write(void *opaque, hwaddr addr, ++ uint64_t data, unsigned size) ++{ ++ qemu_log_mask(LOG_UNIMP, "%s not implemented\n", __func__); ++} ++ + static const MemoryRegionOps raven_intack_ops = { + .read = raven_intack_read, ++ .write = raven_intack_write, + .valid = { + .max_access_size = 1, + }, diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-15469-2.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-15469-2.patch new file mode 100644 index 0000000000..d6715d337c --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-15469-2.patch @@ -0,0 +1,69 @@ +From 4f2a5202a05fc1612954804a2482f07bff105ea2 Mon Sep 17 00:00:00 2001 +From: Prasad J Pandit <pjp@fedoraproject.org> +Date: Tue, 11 Aug 2020 17:11:26 +0530 +Subject: [PATCH] pci-host: designware: add pcie-msi read method + +Add pcie-msi mmio read method to avoid NULL pointer dereference +issue. + +Reported-by: Lei Sun <slei.casper@gmail.com> +Reviewed-by: Li Qiang <liq3ea@gmail.com> +Reviewed-by: Peter Maydell <peter.maydell@linaro.org> +Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org> +Message-Id: <20200811114133.672647-3-ppandit@redhat.com> +Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> + +CVE: CVE-2020-15469 +Upstream-Status: Backport [import from ubuntu https://git.launchpad.net/ubuntu/+source/qemu/tree/debian/patches/CVE-2020-15469-2.patch?h=ubuntu/focal-security Upstream Commit https://github.com/qemu/qemu/commit/4f2a5202a05fc1612954804a2482f07bff105ea2] +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> +--- + hw/pci-host/designware.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/hw/pci-host/designware.c b/hw/pci-host/designware.c +index f9fb97a..bde3a34 100644 +--- a/hw/pci-host/designware.c ++++ b/hw/pci-host/designware.c +@@ -21,6 +21,7 @@ + #include "qemu/osdep.h" + #include "qapi/error.h" + #include "qemu/module.h" ++#include "qemu/log.h" + #include "hw/pci/msi.h" + #include "hw/pci/pci_bridge.h" + #include "hw/pci/pci_host.h" +@@ -63,6 +64,23 @@ designware_pcie_root_to_host(DesignwarePCIERoot *root) + return DESIGNWARE_PCIE_HOST(bus->parent); + } + ++static uint64_t designware_pcie_root_msi_read(void *opaque, hwaddr addr, ++ unsigned size) ++{ ++ /* ++ * Attempts to read from the MSI address are undefined in ++ * the PCI specifications. For this hardware, the datasheet ++ * specifies that a read from the magic address is simply not ++ * intercepted by the MSI controller, and will go out to the ++ * AHB/AXI bus like any other PCI-device-initiated DMA read. ++ * This is not trivial to implement in QEMU, so since ++ * well-behaved guests won't ever ask a PCI device to DMA from ++ * this address we just log the missing functionality. ++ */ ++ qemu_log_mask(LOG_UNIMP, "%s not implemented\n", __func__); ++ return 0; ++} ++ + static void designware_pcie_root_msi_write(void *opaque, hwaddr addr, + uint64_t val, unsigned len) + { +@@ -77,6 +95,7 @@ static void designware_pcie_root_msi_write(void *opaque, hwaddr addr, + } + + static const MemoryRegionOps designware_pci_host_msi_ops = { ++ .read = designware_pcie_root_msi_read, + .write = designware_pcie_root_msi_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { +-- +1.8.3.1 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-15469-3.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-15469-3.patch new file mode 100644 index 0000000000..85abe8ff32 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-15469-3.patch @@ -0,0 +1,49 @@ +From 24202d2b561c3b4c48bd28383c8c34b4ac66c2bf Mon Sep 17 00:00:00 2001 +From: Prasad J Pandit <pjp@fedoraproject.org> +Date: Tue, 11 Aug 2020 17:11:27 +0530 +Subject: [PATCH] vfio: add quirk device write method + +Add vfio quirk device mmio write method to avoid NULL pointer +dereference issue. + +Reported-by: Lei Sun <slei.casper@gmail.com> +Reviewed-by: Li Qiang <liq3ea@gmail.com> +Reviewed-by: Peter Maydell <peter.maydell@linaro.org> +Acked-by: Alex Williamson <alex.williamson@redhat.com> +Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org> +Message-Id: <20200811114133.672647-4-ppandit@redhat.com> +Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> + +CVE: CVE-2020-15469 +Upstream-Status: Backport [import from ubuntu https://git.launchpad.net/ubuntu/+source/qemu/tree/debian/patches/CVE-2020-15469-3.patch?h=ubuntu/focal-security Upstream commit https://github.com/qemu/qemu/commit/24202d2b561c3b4c48bd28383c8c34b4ac66c2bf] +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> +--- + hw/vfio/pci-quirks.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/hw/vfio/pci-quirks.c ++++ b/hw/vfio/pci-quirks.c +@@ -13,6 +13,7 @@ + #include "qemu/osdep.h" + #include "exec/memop.h" + #include "qemu/units.h" ++#include "qemu/log.h" + #include "qemu/error-report.h" + #include "qemu/main-loop.h" + #include "qemu/module.h" +@@ -278,8 +279,15 @@ static uint64_t vfio_ati_3c3_quirk_read( + return data; + } + ++static void vfio_ati_3c3_quirk_write(void *opaque, hwaddr addr, ++ uint64_t data, unsigned size) ++{ ++ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid access\n", __func__); ++} ++ + static const MemoryRegionOps vfio_ati_3c3_quirk = { + .read = vfio_ati_3c3_quirk_read, ++ .write = vfio_ati_3c3_quirk_write, + .endianness = DEVICE_LITTLE_ENDIAN, + }; + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-15469-4.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-15469-4.patch new file mode 100644 index 0000000000..52fac8a051 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-15469-4.patch @@ -0,0 +1,53 @@ +From f867cebaedbc9c43189f102e4cdfdff05e88df7f Mon Sep 17 00:00:00 2001 +From: Prasad J Pandit <pjp@fedoraproject.org> +Date: Tue, 11 Aug 2020 17:11:28 +0530 +Subject: [PATCH] prep: add ppc-parity write method + +Add ppc-parity mmio write method to avoid NULL pointer dereference +issue. + +Reported-by: Lei Sun <slei.casper@gmail.com> +Acked-by: David Gibson <david@gibson.dropbear.id.au> +Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org> +Reviewed-by: Li Qiang <liq3ea@gmail.com> +Message-Id: <20200811114133.672647-5-ppandit@redhat.com> +Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> + +CVE: CVE-2020-15469 +Upstream-Status: Backport [import from ubuntu https://git.launchpad.net/ubuntu/+source/qemu/tree/debian/patches/CVE-2020-15469-4.patch?h=ubuntu/focal-security Upstream commit https://github.com/qemu/qemu/commit/f867cebaedbc9c43189f102e4cdfdff05e88df7f] +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> +--- + hw/ppc/prep_systemio.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/hw/ppc/prep_systemio.c b/hw/ppc/prep_systemio.c +index 4e48ef2..b2bd783 100644 +--- a/hw/ppc/prep_systemio.c ++++ b/hw/ppc/prep_systemio.c +@@ -23,6 +23,7 @@ + */ + + #include "qemu/osdep.h" ++#include "qemu/log.h" + #include "hw/irq.h" + #include "hw/isa/isa.h" + #include "hw/qdev-properties.h" +@@ -235,8 +236,15 @@ static uint64_t ppc_parity_error_readl(void *opaque, hwaddr addr, + return val; + } + ++static void ppc_parity_error_writel(void *opaque, hwaddr addr, ++ uint64_t data, unsigned size) ++{ ++ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid access\n", __func__); ++} ++ + static const MemoryRegionOps ppc_parity_error_ops = { + .read = ppc_parity_error_readl, ++ .write = ppc_parity_error_writel, + .valid = { + .min_access_size = 4, + .max_access_size = 4, +-- +1.8.3.1 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-15469-5.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-15469-5.patch new file mode 100644 index 0000000000..49c6c5e3e2 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-15469-5.patch @@ -0,0 +1,53 @@ +From b5bf601f364e1a14ca4c3276f88dfec024acf613 Mon Sep 17 00:00:00 2001 +From: Prasad J Pandit <pjp@fedoraproject.org> +Date: Tue, 11 Aug 2020 17:11:29 +0530 +Subject: [PATCH] nvram: add nrf51_soc flash read method + +Add nrf51_soc mmio read method to avoid NULL pointer dereference +issue. + +Reported-by: Lei Sun <slei.casper@gmail.com> +Reviewed-by: Peter Maydell <peter.maydell@linaro.org> +Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org> +Reviewed-by: Li Qiang <liq3ea@gmail.com> +Message-Id: <20200811114133.672647-6-ppandit@redhat.com> +Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> + +CVE: CVE-2020-15469 +Upstream-Status: Backport [import from ubuntu https://git.launchpad.net/ubuntu/+source/qemu/tree/debian/patches/CVE-2020-15469-5.patch?h=ubuntu/focal-security Upstream commit https://github.com/qemu/qemu/commit/b5bf601f364e1a14ca4c3276f88dfec024acf613 ] +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> +--- + hw/nvram/nrf51_nvm.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/hw/nvram/nrf51_nvm.c b/hw/nvram/nrf51_nvm.c +index f2283c1..7b3460d 100644 +--- a/hw/nvram/nrf51_nvm.c ++++ b/hw/nvram/nrf51_nvm.c +@@ -273,6 +273,15 @@ static const MemoryRegionOps io_ops = { + .endianness = DEVICE_LITTLE_ENDIAN, + }; + ++static uint64_t flash_read(void *opaque, hwaddr offset, unsigned size) ++{ ++ /* ++ * This is a rom_device MemoryRegion which is always in ++ * romd_mode (we never put it in MMIO mode), so reads always ++ * go directly to RAM and never come here. ++ */ ++ g_assert_not_reached(); ++} + + static void flash_write(void *opaque, hwaddr offset, uint64_t value, + unsigned int size) +@@ -300,6 +309,7 @@ static void flash_write(void *opaque, hwaddr offset, uint64_t value, + + + static const MemoryRegionOps flash_ops = { ++ .read = flash_read, + .write = flash_write, + .valid.min_access_size = 4, + .valid.max_access_size = 4, +-- +1.8.3.1 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-15469-6.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-15469-6.patch new file mode 100644 index 0000000000..115be68295 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-15469-6.patch @@ -0,0 +1,61 @@ +Backport of: + +From 921604e175b8ec06c39503310e7b3ec1e3eafe9e Mon Sep 17 00:00:00 2001 +From: Prasad J Pandit <pjp@fedoraproject.org> +Date: Tue, 11 Aug 2020 17:11:30 +0530 +Subject: [PATCH] spapr_pci: add spapr msi read method + +Add spapr msi mmio read method to avoid NULL pointer dereference +issue. + +Reported-by: Lei Sun <slei.casper@gmail.com> +Acked-by: David Gibson <david@gibson.dropbear.id.au> +Reviewed-by: Li Qiang <liq3ea@gmail.com> +Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org> +Message-Id: <20200811114133.672647-7-ppandit@redhat.com> +Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> + +CVE: CVE-2020-15469 +Upstream-Status: Backport [import from ubuntu https://git.launchpad.net/ubuntu/+source/qemu/tree/debian/patches/CVE-2020-15469-6.patch?h=ubuntu/focal-security Upstream commit https://github.com/qemu/qemu/commit/921604e175b8ec06c39503310e7b3ec1e3eafe9e] +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> +--- + hw/ppc/spapr_pci.c | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +--- a/hw/ppc/spapr_pci.c ++++ b/hw/ppc/spapr_pci.c +@@ -52,6 +52,7 @@ + #include "sysemu/kvm.h" + #include "sysemu/hostmem.h" + #include "sysemu/numa.h" ++#include "qemu/log.h" + + /* Copied from the kernel arch/powerpc/platforms/pseries/msi.c */ + #define RTAS_QUERY_FN 0 +@@ -738,6 +739,12 @@ static PCIINTxRoute spapr_route_intx_pin + return route; + } + ++static uint64_t spapr_msi_read(void *opaque, hwaddr addr, unsigned size) ++{ ++ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid access\n", __func__); ++ return 0; ++} ++ + /* + * MSI/MSIX memory region implementation. + * The handler handles both MSI and MSIX. +@@ -755,8 +762,11 @@ static void spapr_msi_write(void *opaque + } + + static const MemoryRegionOps spapr_msi_ops = { +- /* There is no .read as the read result is undefined by PCI spec */ +- .read = NULL, ++ /* ++ * .read result is undefined by PCI spec. ++ * define .read method to avoid assert failure in memory_region_init_io ++ */ ++ .read = spapr_msi_read, + .write = spapr_msi_write, + .endianness = DEVICE_LITTLE_ENDIAN + }; diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-15469-7.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-15469-7.patch new file mode 100644 index 0000000000..7d8ec32251 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-15469-7.patch @@ -0,0 +1,50 @@ +From 2c9fb3b784000c1df32231e1c2464bb2e3fc4620 Mon Sep 17 00:00:00 2001 +From: Prasad J Pandit <pjp@fedoraproject.org> +Date: Tue, 11 Aug 2020 17:11:31 +0530 +Subject: [PATCH] tz-ppc: add dummy read/write methods + +Add tz-ppc-dummy mmio read/write methods to avoid assert failure +during initialisation. + +Reviewed-by: Peter Maydell <peter.maydell@linaro.org> +Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org> +Reviewed-by: Li Qiang <liq3ea@gmail.com> +Message-Id: <20200811114133.672647-8-ppandit@redhat.com> +Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> + +CVE: CVE-2020-15469 +Upstream-Status: Backport [import from ubuntu https://git.launchpad.net/ubuntu/+source/qemu/tree/debian/patches/CVE-2020-15469-7.patch?h=ubuntu/focal-security Upstream commit https://github.com/qemu/qemu/commit/2c9fb3b784000c1df32231e1c2464bb2e3fc4620 ] +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> +--- + hw/misc/tz-ppc.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/hw/misc/tz-ppc.c b/hw/misc/tz-ppc.c +index 6431257..36495c6 100644 +--- a/hw/misc/tz-ppc.c ++++ b/hw/misc/tz-ppc.c +@@ -196,7 +196,21 @@ static bool tz_ppc_dummy_accepts(void *opaque, hwaddr addr, + g_assert_not_reached(); + } + ++static uint64_t tz_ppc_dummy_read(void *opaque, hwaddr addr, unsigned size) ++{ ++ g_assert_not_reached(); ++} ++ ++static void tz_ppc_dummy_write(void *opaque, hwaddr addr, ++ uint64_t data, unsigned size) ++{ ++ g_assert_not_reached(); ++} ++ + static const MemoryRegionOps tz_ppc_dummy_ops = { ++ /* define r/w methods to avoid assert failure in memory_region_init_io */ ++ .read = tz_ppc_dummy_read, ++ .write = tz_ppc_dummy_write, + .valid.accepts = tz_ppc_dummy_accepts, + }; + +-- +1.8.3.1 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-15469-8.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-15469-8.patch new file mode 100644 index 0000000000..7857ba266e --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-15469-8.patch @@ -0,0 +1,44 @@ +From 735754aaa15a6ed46db51fd731e88331c446ea54 Mon Sep 17 00:00:00 2001 +From: Prasad J Pandit <pjp@fedoraproject.org> +Date: Tue, 11 Aug 2020 17:11:32 +0530 +Subject: [PATCH] imx7-ccm: add digprog mmio write method + +Add digprog mmio write method to avoid assert failure during +initialisation. + +Reviewed-by: Li Qiang <liq3ea@gmail.com> +Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org> +Message-Id: <20200811114133.672647-9-ppandit@redhat.com> +Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> + +CVE: CVE-2020-15469 +Upstream-Status: Backport [import from ubuntu https://git.launchpad.net/ubuntu/+source/qemu/tree/debian/patches/CVE-2020-15469-8.patch?h=ubuntu/focal-security Upstream commit https://github.com/qemu/qemu/commit/735754aaa15a6ed46db51fd731e88331c446ea54] +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> +--- + hw/misc/imx7_ccm.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/hw/misc/imx7_ccm.c b/hw/misc/imx7_ccm.c +index 02fc1ae..075159e 100644 +--- a/hw/misc/imx7_ccm.c ++++ b/hw/misc/imx7_ccm.c +@@ -131,8 +131,16 @@ static const struct MemoryRegionOps imx7_set_clr_tog_ops = { + }, + }; + ++static void imx7_digprog_write(void *opaque, hwaddr addr, ++ uint64_t data, unsigned size) ++{ ++ qemu_log_mask(LOG_GUEST_ERROR, ++ "Guest write to read-only ANALOG_DIGPROG register\n"); ++} ++ + static const struct MemoryRegionOps imx7_digprog_ops = { + .read = imx7_set_clr_tog_read, ++ .write = imx7_digprog_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + .min_access_size = 4, +-- +1.8.3.1 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-15859.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-15859.patch new file mode 100644 index 0000000000..0f43adeea8 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-15859.patch @@ -0,0 +1,39 @@ +From 22dc8663d9fc7baa22100544c600b6285a63c7a3 Mon Sep 17 00:00:00 2001 +From: Jason Wang <jasowang@redhat.com> +Date: Wed, 22 Jul 2020 16:57:46 +0800 +Subject: [PATCH] net: forbid the reentrant RX + +The memory API allows DMA into NIC's MMIO area. This means the NIC's +RX routine must be reentrant. Instead of auditing all the NIC, we can +simply detect the reentrancy and return early. The queue->delivering +is set and cleared by qemu_net_queue_deliver() for other queue helpers +to know whether the delivering in on going (NIC's receive is being +called). We can check it and return early in qemu_net_queue_flush() to +forbid reentrant RX. + +Signed-off-by: Jason Wang <jasowang@redhat.com> + +CVE: CVE-2020-15859 +Upstream-Status: Backport [import from ubuntu https://git.launchpad.net/ubuntu/+source/qemu/tree/debian/patches/ubuntu/CVE-2020-15859.patch?h=ubuntu/focal-security Upstream commit https://github.com/qemu/qemu/commit/22dc8663d9fc7baa22100544c600b6285a63c7a3 ] +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> +--- + net/queue.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/queue.c b/net/queue.c +index 0164727..19e32c8 100644 +--- a/net/queue.c ++++ b/net/queue.c +@@ -250,6 +250,9 @@ void qemu_net_queue_purge(NetQueue *queue, NetClientState *from) + + bool qemu_net_queue_flush(NetQueue *queue) + { ++ if (queue->delivering) ++ return false; ++ + while (!QTAILQ_EMPTY(&queue->packets)) { + NetPacket *packet; + int ret; +-- +1.8.3.1 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-24165.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-24165.patch new file mode 100644 index 0000000000..e0a27331a8 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-24165.patch @@ -0,0 +1,94 @@ +CVE: CVE-2020-24165 +Upstream-Status: Backport [https://github.com/qemu/qemu/commit/886cc68943ebe8cf7e5f970be33459f95068a441 ] +Signed-off-by: Lee Chee Yang <chee.yang.lee@intel.com> + +From 886cc68943ebe8cf7e5f970be33459f95068a441 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Alex=20Benn=C3=A9e?= <alex.bennee@linaro.org> +Date: Fri, 14 Feb 2020 14:49:52 +0000 +Subject: [PATCH] accel/tcg: fix race in cpu_exec_step_atomic (bug 1863025) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The bug describes a race whereby cpu_exec_step_atomic can acquire a TB +which is invalidated by a tb_flush before we execute it. This doesn't +affect the other cpu_exec modes as a tb_flush by it's nature can only +occur on a quiescent system. The race was described as: + + B2. tcg_cpu_exec => cpu_exec => tb_find => tb_gen_code + B3. tcg_tb_alloc obtains a new TB + + C3. TB obtained with tb_lookup__cpu_state or tb_gen_code + (same TB as B2) + + A3. start_exclusive critical section entered + A4. do_tb_flush is called, TB memory freed/re-allocated + A5. end_exclusive exits critical section + + B2. tcg_cpu_exec => cpu_exec => tb_find => tb_gen_code + B3. tcg_tb_alloc reallocates TB from B2 + + C4. start_exclusive critical section entered + C5. cpu_tb_exec executes the TB code that was free in A4 + +The simplest fix is to widen the exclusive period to include the TB +lookup. As a result we can drop the complication of checking we are in +the exclusive region before we end it. + +Cc: Yifan <me@yifanlu.com> +Buglink: https://bugs.launchpad.net/qemu/+bug/1863025 +Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> +Reviewed-by: Richard Henderson <richard.henderson@linaro.org> +Signed-off-by: Alex Bennée <alex.bennee@linaro.org> +Message-Id: <20200214144952.15502-1-alex.bennee@linaro.org> +Signed-off-by: Richard Henderson <richard.henderson@linaro.org> +--- + accel/tcg/cpu-exec.c | 21 +++++++++++---------- + 1 file changed, 11 insertions(+), 10 deletions(-) + +diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c +index 2560c90eec79..d95c4848a47b 100644 +--- a/accel/tcg/cpu-exec.c ++++ b/accel/tcg/cpu-exec.c +@@ -240,6 +240,8 @@ void cpu_exec_step_atomic(CPUState *cpu) + uint32_t cf_mask = cflags & CF_HASH_MASK; + + if (sigsetjmp(cpu->jmp_env, 0) == 0) { ++ start_exclusive(); ++ + tb = tb_lookup__cpu_state(cpu, &pc, &cs_base, &flags, cf_mask); + if (tb == NULL) { + mmap_lock(); +@@ -247,8 +249,6 @@ void cpu_exec_step_atomic(CPUState *cpu) + mmap_unlock(); + } + +- start_exclusive(); +- + /* Since we got here, we know that parallel_cpus must be true. */ + parallel_cpus = false; + cc->cpu_exec_enter(cpu); +@@ -271,14 +271,15 @@ void cpu_exec_step_atomic(CPUState *cpu) + qemu_plugin_disable_mem_helpers(cpu); + } + +- if (cpu_in_exclusive_context(cpu)) { +- /* We might longjump out of either the codegen or the +- * execution, so must make sure we only end the exclusive +- * region if we started it. +- */ +- parallel_cpus = true; +- end_exclusive(); +- } ++ ++ /* ++ * As we start the exclusive region before codegen we must still ++ * be in the region if we longjump out of either the codegen or ++ * the execution. ++ */ ++ g_assert(cpu_in_exclusive_context(cpu)); ++ parallel_cpus = true; ++ end_exclusive(); + } + + struct tb_desc { diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-25085.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-25085.patch new file mode 100644 index 0000000000..be19256cef --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-25085.patch @@ -0,0 +1,46 @@ +From dfba99f17feb6d4a129da19d38df1bcd8579d1c3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= <f4bug@amsat.org> +Date: Tue, 1 Sep 2020 15:22:06 +0200 +Subject: [PATCH] hw/sd/sdhci: Fix DMA Transfer Block Size field +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The 'Transfer Block Size' field is 12-bit wide. + +See section '2.2.2. Block Size Register (Offset 004h)' in datasheet. + +Two different bug reproducer available: +- https://bugs.launchpad.net/qemu/+bug/1892960 +- https://ruhr-uni-bochum.sciebo.de/s/NNWP2GfwzYKeKwE?path=%2Fsdhci_oob_write1 + +Cc: qemu-stable@nongnu.org +Buglink: https://bugs.launchpad.net/qemu/+bug/1892960 +Fixes: d7dfca0807a ("hw/sdhci: introduce standard SD host controller") +Reported-by: Alexander Bulekov <alxndr@bu.edu> +Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org> +Reviewed-by: Prasad J Pandit <pjp@fedoraproject.org> +Tested-by: Alexander Bulekov <alxndr@bu.edu> +Message-Id: <20200901140411.112150-3-f4bug@amsat.org> + +Upstream-Status: Backport +CVE: CVE-2020-25085 +Signed-off-by: Armin Kuster <akuster@mvista.com> + +--- + hw/sd/sdhci.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: qemu-4.2.0/hw/sd/sdhci.c +=================================================================== +--- qemu-4.2.0.orig/hw/sd/sdhci.c ++++ qemu-4.2.0/hw/sd/sdhci.c +@@ -1129,7 +1129,7 @@ sdhci_write(void *opaque, hwaddr offset, + break; + case SDHC_BLKSIZE: + if (!TRANSFERRING_DATA(s->prnsts)) { +- MASKED_WRITE(s->blksize, mask, value); ++ MASKED_WRITE(s->blksize, mask, extract32(value, 0, 12)); + MASKED_WRITE(s->blkcnt, mask >> 16, value >> 16); + } + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-25624_1.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-25624_1.patch new file mode 100644 index 0000000000..a46b5be193 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-25624_1.patch @@ -0,0 +1,87 @@ +From fbec359e9279ce78908b9f2af2c264e7448336af Mon Sep 17 00:00:00 2001 +From: Guenter Roeck <linux@roeck-us.net> +Date: Mon, 17 Feb 2020 12:48:10 -0800 +Subject: [PATCH] hw: usb: hcd-ohci: Move OHCISysBusState and TYPE_SYSBUS_OHCI + to include file + +We need to be able to use OHCISysBusState outside hcd-ohci.c, so move it +to its include file. + +Reviewed-by: Gerd Hoffmann <kraxel@redhat.com> +Signed-off-by: Guenter Roeck <linux@roeck-us.net> +Tested-by: Niek Linnenbank <nieklinnenbank@gmail.com> +Message-id: 20200217204812.9857-2-linux@roeck-us.net +Signed-off-by: Peter Maydell <peter.maydell@linaro.org> + +Upstream-Status: Backport +CVE: CVE-2020-25624 patch #1 +Signed-off-by: Armin Kuster <akuster@mvista.com> + +--- + hw/usb/hcd-ohci.c | 15 --------------- + hw/usb/hcd-ohci.h | 16 ++++++++++++++++ + 2 files changed, 16 insertions(+), 15 deletions(-) + +diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c +index 8a94bd004a..1e6e85e86a 100644 +--- a/hw/usb/hcd-ohci.c ++++ b/hw/usb/hcd-ohci.c +@@ -1870,21 +1870,6 @@ void ohci_sysbus_die(struct OHCIState *ohci) + ohci_bus_stop(ohci); + } + +-#define TYPE_SYSBUS_OHCI "sysbus-ohci" +-#define SYSBUS_OHCI(obj) OBJECT_CHECK(OHCISysBusState, (obj), TYPE_SYSBUS_OHCI) +- +-typedef struct { +- /*< private >*/ +- SysBusDevice parent_obj; +- /*< public >*/ +- +- OHCIState ohci; +- char *masterbus; +- uint32_t num_ports; +- uint32_t firstport; +- dma_addr_t dma_offset; +-} OHCISysBusState; +- + static void ohci_realize_pxa(DeviceState *dev, Error **errp) + { + OHCISysBusState *s = SYSBUS_OHCI(dev); +diff --git a/hw/usb/hcd-ohci.h b/hw/usb/hcd-ohci.h +index 16e3f1e13a..5c8819aedf 100644 +--- a/hw/usb/hcd-ohci.h ++++ b/hw/usb/hcd-ohci.h +@@ -22,6 +22,7 @@ + #define HCD_OHCI_H + + #include "sysemu/dma.h" ++#include "hw/usb.h" + + /* Number of Downstream Ports on the root hub: */ + #define OHCI_MAX_PORTS 15 +@@ -90,6 +91,21 @@ typedef struct OHCIState { + void (*ohci_die)(struct OHCIState *ohci); + } OHCIState; + ++#define TYPE_SYSBUS_OHCI "sysbus-ohci" ++#define SYSBUS_OHCI(obj) OBJECT_CHECK(OHCISysBusState, (obj), TYPE_SYSBUS_OHCI) ++ ++typedef struct { ++ /*< private >*/ ++ SysBusDevice parent_obj; ++ /*< public >*/ ++ ++ OHCIState ohci; ++ char *masterbus; ++ uint32_t num_ports; ++ uint32_t firstport; ++ dma_addr_t dma_offset; ++} OHCISysBusState; ++ + extern const VMStateDescription vmstate_ohci_state; + + void usb_ohci_init(OHCIState *ohci, DeviceState *dev, uint32_t num_ports, +-- +2.25.1 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-25624_2.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-25624_2.patch new file mode 100644 index 0000000000..8c1275b2f4 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-25624_2.patch @@ -0,0 +1,101 @@ +From 1328fe0c32d5474604105b8105310e944976b058 Mon Sep 17 00:00:00 2001 +From: Prasad J Pandit <pjp@fedoraproject.org> +Date: Tue, 15 Sep 2020 23:52:58 +0530 +Subject: [PATCH] hw: usb: hcd-ohci: check len and frame_number variables + +While servicing the OHCI transfer descriptors(TD), OHCI host +controller derives variables 'start_addr', 'end_addr', 'len' +etc. from values supplied by the host controller driver. +Host controller driver may supply values such that using +above variables leads to out-of-bounds access issues. +Add checks to avoid them. + +AddressSanitizer: stack-buffer-overflow on address 0x7ffd53af76a0 + READ of size 2 at 0x7ffd53af76a0 thread T0 + #0 ohci_service_iso_td ../hw/usb/hcd-ohci.c:734 + #1 ohci_service_ed_list ../hw/usb/hcd-ohci.c:1180 + #2 ohci_process_lists ../hw/usb/hcd-ohci.c:1214 + #3 ohci_frame_boundary ../hw/usb/hcd-ohci.c:1257 + #4 timerlist_run_timers ../util/qemu-timer.c:572 + #5 qemu_clock_run_timers ../util/qemu-timer.c:586 + #6 qemu_clock_run_all_timers ../util/qemu-timer.c:672 + #7 main_loop_wait ../util/main-loop.c:527 + #8 qemu_main_loop ../softmmu/vl.c:1676 + #9 main ../softmmu/main.c:50 + +Reported-by: Gaoning Pan <pgn@zju.edu.cn> +Reported-by: Yongkang Jia <j_kangel@163.com> +Reported-by: Yi Ren <yunye.ry@alibaba-inc.com> +Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org> +Message-id: 20200915182259.68522-2-ppandit@redhat.com +Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> + +Upstream-Status: Backport +CVE: CVE-2020-25624 patch #2 +Signed-off-by: Armin Kuster <akuster@mvista.com> + +--- + hw/usb/hcd-ohci.c | 24 ++++++++++++++++++++++-- + 1 file changed, 22 insertions(+), 2 deletions(-) + +diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c +index 1e6e85e86a..9dc59101f9 100644 +--- a/hw/usb/hcd-ohci.c ++++ b/hw/usb/hcd-ohci.c +@@ -731,7 +731,11 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, + } + + start_offset = iso_td.offset[relative_frame_number]; +- next_offset = iso_td.offset[relative_frame_number + 1]; ++ if (relative_frame_number < frame_count) { ++ next_offset = iso_td.offset[relative_frame_number + 1]; ++ } else { ++ next_offset = iso_td.be; ++ } + + if (!(OHCI_BM(start_offset, TD_PSW_CC) & 0xe) || + ((relative_frame_number < frame_count) && +@@ -764,7 +768,12 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, + } + } else { + /* Last packet in the ISO TD */ +- end_addr = iso_td.be; ++ end_addr = next_offset; ++ } ++ ++ if (start_addr > end_addr) { ++ trace_usb_ohci_iso_td_bad_cc_overrun(start_addr, end_addr); ++ return 1; + } + + if ((start_addr & OHCI_PAGE_MASK) != (end_addr & OHCI_PAGE_MASK)) { +@@ -773,6 +782,9 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, + } else { + len = end_addr - start_addr + 1; + } ++ if (len > sizeof(ohci->usb_buf)) { ++ len = sizeof(ohci->usb_buf); ++ } + + if (len && dir != OHCI_TD_DIR_IN) { + if (ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, len, +@@ -975,8 +987,16 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) + if ((td.cbp & 0xfffff000) != (td.be & 0xfffff000)) { + len = (td.be & 0xfff) + 0x1001 - (td.cbp & 0xfff); + } else { ++ if (td.cbp > td.be) { ++ trace_usb_ohci_iso_td_bad_cc_overrun(td.cbp, td.be); ++ ohci_die(ohci); ++ return 1; ++ } + len = (td.be - td.cbp) + 1; + } ++ if (len > sizeof(ohci->usb_buf)) { ++ len = sizeof(ohci->usb_buf); ++ } + + pktlen = len; + if (len && dir != OHCI_TD_DIR_IN) { +-- +2.25.1 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-25625.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-25625.patch new file mode 100644 index 0000000000..374d7c4562 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-25625.patch @@ -0,0 +1,42 @@ +From 1be90ebecc95b09a2ee5af3f60c412b45a766c4f Mon Sep 17 00:00:00 2001 +From: Prasad J Pandit <pjp@fedoraproject.org> +Date: Tue, 15 Sep 2020 23:52:59 +0530 +Subject: [PATCH] hw: usb: hcd-ohci: check for processed TD before retire + +While servicing OHCI transfer descriptors(TD), ohci_service_iso_td +retires a TD if it has passed its time frame. It does not check if +the TD was already processed once and holds an error code in TD_CC. +It may happen if the TD list has a loop. Add check to avoid an +infinite loop condition. + +Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org> +Reviewed-by: Li Qiang <liq3ea@gmail.com> +Message-id: 20200915182259.68522-3-ppandit@redhat.com +Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> + +Upstream-Status: Backport +CVE: CVE-2020-25625 +Signed-off-by: Armin Kuster <akuster@mvista.com> + +--- + hw/usb/hcd-ohci.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c +index 9dc59101f9..8b912e95d3 100644 +--- a/hw/usb/hcd-ohci.c ++++ b/hw/usb/hcd-ohci.c +@@ -691,6 +691,10 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, + the next ISO TD of the same ED */ + trace_usb_ohci_iso_td_relative_frame_number_big(relative_frame_number, + frame_count); ++ if (OHCI_CC_DATAOVERRUN == OHCI_BM(iso_td.flags, TD_CC)) { ++ /* avoid infinite loop */ ++ return 1; ++ } + OHCI_SET_BM(iso_td.flags, TD_CC, OHCI_CC_DATAOVERRUN); + ed->head &= ~OHCI_DPTR_MASK; + ed->head |= (iso_td.next & OHCI_DPTR_MASK); +-- +2.25.1 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-27617.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-27617.patch new file mode 100644 index 0000000000..7bfc2beecb --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-27617.patch @@ -0,0 +1,49 @@ +From 7564bf7701f00214cdc8a678a9f7df765244def1 Mon Sep 17 00:00:00 2001 +From: Prasad J Pandit <pjp@fedoraproject.org> +Date: Wed, 21 Oct 2020 11:35:50 +0530 +Subject: [PATCH] net: remove an assert call in eth_get_gso_type + +eth_get_gso_type() routine returns segmentation offload type based on +L3 protocol type. It calls g_assert_not_reached if L3 protocol is +unknown, making the following return statement unreachable. Remove the +g_assert call, it maybe triggered by a guest user. + +Reported-by: Gaoning Pan <pgn@zju.edu.cn> +Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org> +Signed-off-by: Jason Wang <jasowang@redhat.com> + +Upsteram-Status: Backport +CVE: CVE-2020-27617 +Signed-off-by: Armin Kuster <akuster@mvista.com> + +--- + net/eth.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/net/eth.c b/net/eth.c +index 0c1d413ee2..1e0821c5f8 100644 +--- a/net/eth.c ++++ b/net/eth.c +@@ -16,6 +16,7 @@ + */ + + #include "qemu/osdep.h" ++#include "qemu/log.h" + #include "net/eth.h" + #include "net/checksum.h" + #include "net/tap.h" +@@ -71,9 +72,8 @@ eth_get_gso_type(uint16_t l3_proto, uint8_t *l3_hdr, uint8_t l4proto) + return VIRTIO_NET_HDR_GSO_TCPV6 | ecn_state; + } + } +- +- /* Unsupported offload */ +- g_assert_not_reached(); ++ qemu_log_mask(LOG_UNIMP, "%s: probably not GSO frame, " ++ "unknown L3 protocol: 0x%04"PRIx16"\n", __func__, l3_proto); + + return VIRTIO_NET_HDR_GSO_NONE | ecn_state; + } +-- +2.25.1 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-27821.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-27821.patch new file mode 100644 index 0000000000..e26bc31bbb --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-27821.patch @@ -0,0 +1,73 @@ +From 15222d4636d742f3395fd211fad0cd7e36d9f43e Mon Sep 17 00:00:00 2001 +From: Hitendra Prajapati <hprajapati@mvista.com> +Date: Tue, 16 Aug 2022 10:07:01 +0530 +Subject: [PATCH] CVE-2020-27821 + +Upstream-Status: Backport [https://git.qemu.org/?p=qemu.git;a=commit;h=4bfb024bc76973d40a359476dc0291f46e435442] +CVE: CVE-2020-27821 +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> + +memory: clamp cached translation in case it points to an MMIO region + +In using the address_space_translate_internal API, address_space_cache_init +forgot one piece of advice that can be found in the code for +address_space_translate_internal: + + /* MMIO registers can be expected to perform full-width accesses based only + * on their address, without considering adjacent registers that could + * decode to completely different MemoryRegions. When such registers + * exist (e.g. I/O ports 0xcf8 and 0xcf9 on most PC chipsets), MMIO + * regions overlap wildly. For this reason we cannot clamp the accesses + * here. + * + * If the length is small (as is the case for address_space_ldl/stl), + * everything works fine. If the incoming length is large, however, + * the caller really has to do the clamping through memory_access_size. + */ + +address_space_cache_init is exactly one such case where "the incoming length +is large", therefore we need to clamp the resulting length---not to +memory_access_size though, since we are not doing an access yet, but to +the size of the resulting section. This ensures that subsequent accesses +to the cached MemoryRegionSection will be in range. + +With this patch, the enclosed testcase notices that the used ring does +not fit into the MSI-X table and prints a "qemu-system-x86_64: Cannot map used" +error. + +Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> +--- + exec.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/exec.c b/exec.c +index 2d6add46..1360051a 100644 +--- a/exec.c ++++ b/exec.c +@@ -3632,6 +3632,7 @@ int64_t address_space_cache_init(MemoryRegionCache *cache, + AddressSpaceDispatch *d; + hwaddr l; + MemoryRegion *mr; ++ Int128 diff; + + assert(len > 0); + +@@ -3640,6 +3641,15 @@ int64_t address_space_cache_init(MemoryRegionCache *cache, + d = flatview_to_dispatch(cache->fv); + cache->mrs = *address_space_translate_internal(d, addr, &cache->xlat, &l, true); + ++ /* ++ * cache->xlat is now relative to cache->mrs.mr, not to the section itself. ++ * Take that into account to compute how many bytes are there between ++ * cache->xlat and the end of the section. ++ */ ++ diff = int128_sub(cache->mrs.size, ++ int128_make64(cache->xlat - cache->mrs.offset_within_region)); ++ l = int128_get64(int128_min(diff, int128_make64(l))); ++ + mr = cache->mrs.mr; + memory_region_ref(mr); + if (memory_access_is_direct(mr, is_write)) { +-- +2.25.1 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-28916.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-28916.patch new file mode 100644 index 0000000000..756b1c1495 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-28916.patch @@ -0,0 +1,48 @@ +From c2cb511634012344e3d0fe49a037a33b12d8a98a Mon Sep 17 00:00:00 2001 +From: Prasad J Pandit <pjp@fedoraproject.org> +Date: Wed, 11 Nov 2020 18:36:36 +0530 +Subject: [PATCH] hw/net/e1000e: advance desc_offset in case of null descriptor + +While receiving packets via e1000e_write_packet_to_guest() routine, +'desc_offset' is advanced only when RX descriptor is processed. And +RX descriptor is not processed if it has NULL buffer address. +This may lead to an infinite loop condition. Increament 'desc_offset' +to process next descriptor in the ring to avoid infinite loop. + +Reported-by: Cheol-woo Myung <330cjfdn@gmail.com> +Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org> +Signed-off-by: Jason Wang <jasowang@redhat.com> + +Upstream-Status: Backport +CVE: CVE-2020-28916 +Signed-off-by: Armin Kuster <akuster@mvista.com> + +--- + hw/net/e1000e_core.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c +index d8b9e4b2f4..095c01ebc6 100644 +--- a/hw/net/e1000e_core.c ++++ b/hw/net/e1000e_core.c +@@ -1596,13 +1596,13 @@ e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt, + (const char *) &fcs_pad, e1000x_fcs_len(core->mac)); + } + } +- desc_offset += desc_size; +- if (desc_offset >= total_size) { +- is_last = true; +- } + } else { /* as per intel docs; skip descriptors with null buf addr */ + trace_e1000e_rx_null_descriptor(); + } ++ desc_offset += desc_size; ++ if (desc_offset >= total_size) { ++ is_last = true; ++ } + + e1000e_write_rx_descr(core, desc, is_last ? core->rx_pkt : NULL, + rss_info, do_ps ? ps_hdr_len : 0, &bastate.written); +-- +2.25.1 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-29443.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-29443.patch new file mode 100644 index 0000000000..1528d5c2fd --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-29443.patch @@ -0,0 +1,45 @@ +From 813212288970c39b1800f63e83ac6e96588095c6 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini <pbonzini@redhat.com> +Date: Tue, 1 Dec 2020 13:09:26 +0100 +Subject: [PATCH] ide: atapi: assert that the buffer pointer is in range + +A case was reported where s->io_buffer_index can be out of range. +The report skimped on the details but it seems to be triggered +by s->lba == -1 on the READ/READ CD paths (e.g. by sending an +ATAPI command with LBA = 0xFFFFFFFF). For now paper over it +with assertions. The first one ensures that there is no overflow +when incrementing s->io_buffer_index, the second checks for the +buffer overrun. + +Note that the buffer overrun is only a read, so I am not sure +if the assertion failure is actually less harmful than the overrun. + +Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> +Message-id: 20201201120926.56559-1-pbonzini@redhat.com +Reviewed-by: Kevin Wolf <kwolf@redhat.com> +Signed-off-by: Peter Maydell <peter.maydell@linaro.org> + +Upstream-Status: Backport +CVE: CVE-2020-29443 +Signed-off-by: Armin Kuster <akuster@mvista.com> + +--- + hw/ide/atapi.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c +index 14a2b0bb2f..e79157863f 100644 +--- a/hw/ide/atapi.c ++++ b/hw/ide/atapi.c +@@ -276,6 +276,8 @@ void ide_atapi_cmd_reply_end(IDEState *s) + s->packet_transfer_size -= size; + s->elementary_transfer_size -= size; + s->io_buffer_index += size; ++ assert(size <= s->io_buffer_total_len); ++ assert(s->io_buffer_index <= s->io_buffer_total_len); + + /* Some adapters process PIO data right away. In that case, we need + * to avoid mutual recursion between ide_transfer_start +-- +2.25.1 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-35504.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-35504.patch new file mode 100644 index 0000000000..97d32589d8 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-35504.patch @@ -0,0 +1,51 @@ +Backport of: + +From 0db895361b8a82e1114372ff9f4857abea605701 Mon Sep 17 00:00:00 2001 +From: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> +Date: Wed, 7 Apr 2021 20:57:50 +0100 +Subject: [PATCH] esp: always check current_req is not NULL before use in DMA + callbacks + +After issuing a SCSI command the SCSI layer can call the SCSIBusInfo .cancel +callback which resets both current_req and current_dev to NULL. If any data +is left in the transfer buffer (async_len != 0) then the next TI (Transfer +Information) command will attempt to reference the NULL pointer causing a +segfault. + +Buglink: https://bugs.launchpad.net/qemu/+bug/1910723 +Buglink: https://bugs.launchpad.net/qemu/+bug/1909247 +Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> +Tested-by: Alexander Bulekov <alxndr@bu.edu> +Message-Id: <20210407195801.685-2-mark.cave-ayland@ilande.co.uk> + +CVE: CVE-2020-35504 +Upstream-Status: Backport [import from ubuntu https://git.launchpad.net/ubuntu/+source/qemu/tree/debian/patches/CVE-2020-35504.patch?h=ubuntu/focal-security Upstream commit https://github.com/qemu/qemu/commit/0db895361b8a82e1114372ff9f4857abea605701 ] +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> +--- + hw/scsi/esp.c | 19 ++++++++++++++----- + 1 file changed, 14 insertions(+), 5 deletions(-) + +--- a/hw/scsi/esp.c ++++ b/hw/scsi/esp.c +@@ -362,6 +362,11 @@ static void do_dma_pdma_cb(ESPState *s) + do_cmd(s, s->cmdbuf); + return; + } ++ ++ if (!s->current_req) { ++ return; ++ } ++ + s->dma_left -= len; + s->async_buf += len; + s->async_len -= len; +@@ -415,6 +420,9 @@ static void esp_do_dma(ESPState *s) + do_cmd(s, s->cmdbuf); + return; + } ++ if (!s->current_req) { ++ return; ++ } + if (s->async_len == 0) { + /* Defer until data is available. */ + return; diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2020-35505.patch b/meta/recipes-devtools/qemu/qemu/CVE-2020-35505.patch new file mode 100644 index 0000000000..40c0b1e74f --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2020-35505.patch @@ -0,0 +1,45 @@ +Backport of: + +From 99545751734035b76bd372c4e7215bb337428d89 Mon Sep 17 00:00:00 2001 +From: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> +Date: Wed, 7 Apr 2021 20:57:55 +0100 +Subject: [PATCH] esp: ensure cmdfifo is not empty and current_dev is non-NULL +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf8 +Content-Transfer-Encoding: 8bit + +When about to execute a SCSI command, ensure that cmdfifo is not empty and +current_dev is non-NULL. This can happen if the guest tries to execute a TI +(Transfer Information) command without issuing one of the select commands +first. + +Buglink: https://bugs.launchpad.net/qemu/+bug/1910723 +Buglink: https://bugs.launchpad.net/qemu/+bug/1909247 +Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> +Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> +Tested-by: Alexander Bulekov <alxndr@bu.edu> +Message-Id: <20210407195801.685-7-mark.cave-ayland@ilande.co.uk> + +CVE: CVE-2020-35505 +Upstream-Status: Backport [import from ubuntu https://git.launchpad.net/ubuntu/+source/qemu/tree/debian/patches/CVE-2020-35505.patch?h=ubuntu/focal-security Upstream commit https://github.com/qemu/qemu/commit/99545751734035b76bd372c4e7215bb337428d89 ] +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> +Signed-off-by: Emily Vekariya <emily.vekariya@einfochips.com> +--- + hw/scsi/esp.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c +index c7d701bf..c2a67bc8 100644 +--- a/hw/scsi/esp.c ++++ b/hw/scsi/esp.c +@@ -193,6 +193,10 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid) + + trace_esp_do_busid_cmd(busid); + lun = busid & 7; ++ ++ if (!s->current_dev) { ++ return; ++ } + current_lun = scsi_device_find(&s->bus, 0, s->current_dev->id, lun); + s->current_req = scsi_req_new(current_lun, 0, lun, buf, s); + datalen = scsi_req_enqueue(s->current_req); diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-20181.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-20181.patch new file mode 100644 index 0000000000..1b8c77f838 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-20181.patch @@ -0,0 +1,81 @@ +From c2d2d14e8deece958bbc4fc649d22c3564bc4e7e Mon Sep 17 00:00:00 2001 +From: Greg Kurz <groug@kaod.org> +Date: Thu, 14 Jan 2021 17:04:12 +0100 +Subject: [PATCH] 9pfs: Fully restart unreclaim loop (CVE-2021-20181) + +Depending on the client activity, the server can be asked to open a huge +number of file descriptors and eventually hit RLIMIT_NOFILE. This is +currently mitigated using a reclaim logic : the server closes the file +descriptors of idle fids, based on the assumption that it will be able +to re-open them later. This assumption doesn't hold of course if the +client requests the file to be unlinked. In this case, we loop on the +entire fid list and mark all related fids as unreclaimable (the reclaim +logic will just ignore them) and, of course, we open or re-open their +file descriptors if needed since we're about to unlink the file. + +This is the purpose of v9fs_mark_fids_unreclaim(). Since the actual +opening of a file can cause the coroutine to yield, another client +request could possibly add a new fid that we may want to mark as +non-reclaimable as well. The loop is thus restarted if the re-open +request was actually transmitted to the backend. This is achieved +by keeping a reference on the first fid (head) before traversing +the list. + +This is wrong in several ways: +- a potential clunk request from the client could tear the first + fid down and cause the reference to be stale. This leads to a + use-after-free error that can be detected with ASAN, using a + custom 9p client +- fids are added at the head of the list : restarting from the + previous head will always miss fids added by a some other + potential request + +All these problems could be avoided if fids were being added at the +end of the list. This can be achieved with a QSIMPLEQ, but this is +probably too much change for a bug fix. For now let's keep it +simple and just restart the loop from the current head. + +Fixes: CVE-2021-20181 +Buglink: https://bugs.launchpad.net/qemu/+bug/1911666 +Reported-by: Zero Day Initiative <zdi-disclosures@trendmicro.com> +Reviewed-by: Christian Schoenebeck <qemu_oss@crudebyte.com> +Reviewed-by: Stefano Stabellini <sstabellini@kernel.org> +Message-Id: <161064025265.1838153.15185571283519390907.stgit@bahia.lan> +Signed-off-by: Greg Kurz <groug@kaod.org> + +Upstream-Status: Backport [89fbea8737e8f7b954745a1ffc4238d377055305] +CVE: CVE-2021-20181 + +Signed-off-by: Sakib Sajal <sakib.sajal@windriver.com> +--- + hw/9pfs/9p.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c +index 94df440fc..6026b51a1 100644 +--- a/hw/9pfs/9p.c ++++ b/hw/9pfs/9p.c +@@ -502,9 +502,9 @@ static int coroutine_fn v9fs_mark_fids_unreclaim(V9fsPDU *pdu, V9fsPath *path) + { + int err; + V9fsState *s = pdu->s; +- V9fsFidState *fidp, head_fid; ++ V9fsFidState *fidp; + +- head_fid.next = s->fid_list; ++again: + for (fidp = s->fid_list; fidp; fidp = fidp->next) { + if (fidp->path.size != path->size) { + continue; +@@ -524,7 +524,7 @@ static int coroutine_fn v9fs_mark_fids_unreclaim(V9fsPDU *pdu, V9fsPath *path) + * switched to the worker thread + */ + if (err == 0) { +- fidp = &head_fid; ++ goto again; + } + } + } +-- +2.29.2 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-20196.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-20196.patch new file mode 100644 index 0000000000..e9b815740f --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-20196.patch @@ -0,0 +1,62 @@ +From 94608c59045791dfd35102bc59b792e96f2cfa30 Mon Sep 17 00:00:00 2001 +From: Vivek Kumbhar <vkumbhar@mvista.com> +Date: Tue, 29 Nov 2022 15:57:13 +0530 +Subject: [PATCH] CVE-2021-20196 + +Upstream-Status: Backport [https://gitlab.com/qemu-project/qemu/-/commit/1ab95af033a419e7a64e2d58e67dd96b20af5233] +CVE: CVE-2021-20196 +Signed-off-by: Vivek Kumbhar <vkumbhar@mvista.com> + +hw/block/fdc: Kludge missing floppy drive to fix CVE-2021-20196 + +Guest might select another drive on the bus by setting the +DRIVE_SEL bit of the DIGITAL OUTPUT REGISTER (DOR). +The current controller model doesn't expect a BlockBackend +to be NULL. A simple way to fix CVE-2021-20196 is to create +an empty BlockBackend when it is missing. All further +accesses will be safely handled, and the controller state +machines keep behaving correctly. +--- + hw/block/fdc.c | 19 ++++++++++++++++++- + 1 file changed, 18 insertions(+), 1 deletion(-) + +diff --git a/hw/block/fdc.c b/hw/block/fdc.c +index ac5d31e8..e128e975 100644 +--- a/hw/block/fdc.c ++++ b/hw/block/fdc.c +@@ -58,6 +58,11 @@ + } \ + } while (0) + ++/* Anonymous BlockBackend for empty drive */ ++static BlockBackend *blk_create_empty_drive(void) ++{ ++ return blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL); ++} + + /********************************************************/ + /* qdev floppy bus */ +@@ -1356,7 +1361,19 @@ static FDrive *get_drv(FDCtrl *fdctrl, int unit) + + static FDrive *get_cur_drv(FDCtrl *fdctrl) + { +- return get_drv(fdctrl, fdctrl->cur_drv); ++ FDrive *cur_drv = get_drv(fdctrl, fdctrl->cur_drv); ++ ++ if (!cur_drv->blk) { ++ /* ++ * Kludge: empty drive line selected. Create an anonymous ++ * BlockBackend to avoid NULL deref with various BlockBackend ++ * API calls within this model (CVE-2021-20196). ++ * Due to the controller QOM model limitations, we don't ++ * attach the created to the controller device. ++ */ ++ cur_drv->blk = blk_create_empty_drive(); ++ } ++ return cur_drv; + } + + /* Status A register : 0x00 (read-only) */ +-- +2.25.1 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-20221.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-20221.patch new file mode 100644 index 0000000000..46c9ab4184 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-20221.patch @@ -0,0 +1,67 @@ +From edfe2eb4360cde4ed5d95bda7777edcb3510f76a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= <f4bug@amsat.org> +Date: Sun, 31 Jan 2021 11:34:01 +0100 +Subject: [PATCH] hw/intc/arm_gic: Fix interrupt ID in GICD_SGIR register +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Per the ARM Generic Interrupt Controller Architecture specification +(document "ARM IHI 0048B.b (ID072613)"), the SGIINTID field is 4 bit, +not 10: + + - 4.3 Distributor register descriptions + - 4.3.15 Software Generated Interrupt Register, GICD_SG + + - Table 4-21 GICD_SGIR bit assignments + + The Interrupt ID of the SGI to forward to the specified CPU + interfaces. The value of this field is the Interrupt ID, in + the range 0-15, for example a value of 0b0011 specifies + Interrupt ID 3. + +Correct the irq mask to fix an undefined behavior (which eventually +lead to a heap-buffer-overflow, see [Buglink]): + + $ echo 'writel 0x8000f00 0xff4affb0' | qemu-system-aarch64 -M virt,accel=qtest -qtest stdio + [I 1612088147.116987] OPENED + [R +0.278293] writel 0x8000f00 0xff4affb0 + ../hw/intc/arm_gic.c:1498:13: runtime error: index 944 out of bounds for type 'uint8_t [16][8]' + SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior ../hw/intc/arm_gic.c:1498:13 + +This fixes a security issue when running with KVM on Arm with +kernel-irqchip=off. (The default is kernel-irqchip=on, which is +unaffected, and which is also the correct choice for performance.) + +Cc: qemu-stable@nongnu.org +Fixes: CVE-2021-20221 +Fixes: 9ee6e8bb853 ("ARMv7 support.") +Buglink: https://bugs.launchpad.net/qemu/+bug/1913916 +Buglink: https://bugs.launchpad.net/qemu/+bug/1913917 +Reported-by: Alexander Bulekov <alxndr@bu.edu> +Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org> +Message-id: 20210131103401.217160-1-f4bug@amsat.org +Reviewed-by: Peter Maydell <peter.maydell@linaro.org> +Signed-off-by: Peter Maydell <peter.maydell@linaro.org> + +Upstream-Status: Backport +CVE: CVE-2021-20221 +Signed-off-by: Armin Kuster <akuster@mvista.com> + +--- + hw/intc/arm_gic.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: qemu-4.2.0/hw/intc/arm_gic.c +=================================================================== +--- qemu-4.2.0.orig/hw/intc/arm_gic.c ++++ qemu-4.2.0/hw/intc/arm_gic.c +@@ -1455,7 +1455,7 @@ static void gic_dist_writel(void *opaque + int target_cpu; + + cpu = gic_get_current_cpu(s); +- irq = value & 0x3ff; ++ irq = value & 0xf; + switch ((value >> 24) & 3) { + case 0: + mask = (value >> 16) & ALL_CPU_MASK; diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-20257.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-20257.patch new file mode 100644 index 0000000000..7175b24e99 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-20257.patch @@ -0,0 +1,55 @@ +From affdf476543405045c281a7c67d1eaedbcea8135 Mon Sep 17 00:00:00 2001 +From: Jason Wang <jasowang@redhat.com> +Date: Wed, 24 Feb 2021 13:45:28 +0800 +Subject: [PATCH] e1000: fail early for evil descriptor + +During procss_tx_desc(), driver can try to chain data descriptor with +legacy descriptor, when will lead underflow for the following +calculation in process_tx_desc() for bytes: + + if (tp->size + bytes > msh) + bytes = msh - tp->size; + +This will lead a infinite loop. So check and fail early if tp->size if +greater or equal to msh. + +Reported-by: Alexander Bulekov <alxndr@bu.edu> +Reported-by: Cheolwoo Myung <cwmyung@snu.ac.kr> +Reported-by: Ruhr-University Bochum <bugs-syssec@rub.de> +Cc: Prasad J Pandit <ppandit@redhat.com> +Cc: qemu-stable@nongnu.org +Signed-off-by: Jason Wang <jasowang@redhat.com> + +Upstream-Status: Backport [3de46e6fc489c52c9431a8a832ad8170a7569bd8] +CVE: CVE-2021-20257 + +Signed-off-by: Sakib Sajal <sakib.sajal@windriver.com> +--- + hw/net/e1000.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/hw/net/e1000.c b/hw/net/e1000.c +index cf22c4f07..c3564c7ce 100644 +--- a/hw/net/e1000.c ++++ b/hw/net/e1000.c +@@ -670,6 +670,9 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) + msh = tp->tso_props.hdr_len + tp->tso_props.mss; + do { + bytes = split_size; ++ if (tp->size >= msh) { ++ goto eop; ++ } + if (tp->size + bytes > msh) + bytes = msh - tp->size; + +@@ -695,6 +698,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) + tp->size += split_size; + } + ++eop: + if (!(txd_lower & E1000_TXD_CMD_EOP)) + return; + if (!(tp->cptse && tp->size < tp->tso_props.hdr_len)) { +-- +2.29.2 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-3409-1.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-3409-1.patch new file mode 100644 index 0000000000..d53383247e --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-3409-1.patch @@ -0,0 +1,85 @@ +From b263d8f928001b5cfa2a993ea43b7a5b3a1811e8 Mon Sep 17 00:00:00 2001 +From: Bin Meng <bmeng.cn@gmail.com> +Date: Wed, 3 Mar 2021 20:26:35 +0800 +Subject: [PATCH] hw/sd: sdhci: Don't transfer any data when command time out +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf8 +Content-Transfer-Encoding: 8bit + +At the end of sdhci_send_command(), it starts a data transfer if the +command register indicates data is associated. But the data transfer +should only be initiated when the command execution has succeeded. + +With this fix, the following reproducer: + +outl 0xcf8 0x80001810 +outl 0xcfc 0xe1068000 +outl 0xcf8 0x80001804 +outw 0xcfc 0x7 +write 0xe106802c 0x1 0x0f +write 0xe1068004 0xc 0x2801d10101fffffbff28a384 +write 0xe106800c 0x1f 0x9dacbbcad9e8f7061524334251606f7e8d9cabbac9d8e7f60514233241505f +write 0xe1068003 0x28 0x80d000251480d000252280d000253080d000253e80d000254c80d000255a80d000256880d0002576 +write 0xe1068003 0x1 0xfe + +cannot be reproduced with the following QEMU command line: + +$ qemu-system-x86_64 -nographic -M pc-q35-5.0 \ + -device sdhci-pci,sd-spec-version=3 \ + -drive if=sd,index=0,file=null-co://,format=raw,id=mydrive \ + -device sd-card,drive=mydrive \ + -monitor none -serial none -qtest stdio + +Cc: qemu-stable@nongnu.org +Fixes: CVE-2020-17380 +Fixes: CVE-2020-25085 +Fixes: CVE-2021-3409 +Fixes: d7dfca0807a0 ("hw/sdhci: introduce standard SD host controller") +Reported-by: Alexander Bulekov <alxndr@bu.edu> +Reported-by: Cornelius Aschermann (Ruhr-Universität Bochum) +Reported-by: Sergej Schumilo (Ruhr-Universität Bochum) +Reported-by: Simon Wörner (Ruhr-Universität Bochum) +Buglink: https://bugs.launchpad.net/qemu/+bug/1892960 +Buglink: https://bugs.launchpad.net/qemu/+bug/1909418 +Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1928146 +Acked-by: Alistair Francis <alistair.francis@wdc.com> +Tested-by: Alexander Bulekov <alxndr@bu.edu> +Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org> +Signed-off-by: Bin Meng <bmeng.cn@gmail.com> +Message-Id: <20210303122639.20004-2-bmeng.cn@gmail.com> +Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org> + +CVE: CVE-2021-3409 CVE-2020-17380 +Upstream-Status: Backport [import from ubuntu https://git.launchpad.net/ubuntu/+source/qemu/tree/debian/patches/CVE-2021-3409-1.patch?h=ubuntu/focal-security Upstream commit https://github.com/qemu/qemu/commit/b263d8f928001b5cfa2a993ea43b7a5b3a1811e8 ] +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> +--- + hw/sd/sdhci.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/hw/sd/sdhci.c ++++ b/hw/sd/sdhci.c +@@ -316,6 +316,7 @@ static void sdhci_send_command(SDHCIStat + SDRequest request; + uint8_t response[16]; + int rlen; ++ bool timeout = false; + + s->errintsts = 0; + s->acmd12errsts = 0; +@@ -339,6 +340,7 @@ static void sdhci_send_command(SDHCIStat + trace_sdhci_response16(s->rspreg[3], s->rspreg[2], + s->rspreg[1], s->rspreg[0]); + } else { ++ timeout = true; + trace_sdhci_error("timeout waiting for command response"); + if (s->errintstsen & SDHC_EISEN_CMDTIMEOUT) { + s->errintsts |= SDHC_EIS_CMDTIMEOUT; +@@ -359,7 +361,7 @@ static void sdhci_send_command(SDHCIStat + + sdhci_update_irq(s); + +- if (s->blksize && (s->cmdreg & SDHC_CMD_DATA_PRESENT)) { ++ if (!timeout && s->blksize && (s->cmdreg & SDHC_CMD_DATA_PRESENT)) { + s->data_count = 0; + sdhci_data_transfer(s); + } diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-3409-2.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-3409-2.patch new file mode 100644 index 0000000000..dc00f76ec9 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-3409-2.patch @@ -0,0 +1,103 @@ +From 8be45cc947832b3c02144c9d52921f499f2d77fe Mon Sep 17 00:00:00 2001 +From: Bin Meng <bmeng.cn@gmail.com> +Date: Wed, 3 Mar 2021 20:26:36 +0800 +Subject: [PATCH] hw/sd: sdhci: Don't write to SDHC_SYSAD register when + transfer is in progress +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf8 +Content-Transfer-Encoding: 8bit + +Per "SD Host Controller Standard Specification Version 7.00" +chapter 2.2.1 SDMA System Address Register: + +This register can be accessed only if no transaction is executing +(i.e., after a transaction has stopped). + +With this fix, the following reproducer: + +outl 0xcf8 0x80001010 +outl 0xcfc 0xfbefff00 +outl 0xcf8 0x80001001 +outl 0xcfc 0x06000000 +write 0xfbefff2c 0x1 0x05 +write 0xfbefff0f 0x1 0x37 +write 0xfbefff0a 0x1 0x01 +write 0xfbefff0f 0x1 0x29 +write 0xfbefff0f 0x1 0x02 +write 0xfbefff0f 0x1 0x03 +write 0xfbefff04 0x1 0x01 +write 0xfbefff05 0x1 0x01 +write 0xfbefff07 0x1 0x02 +write 0xfbefff0c 0x1 0x33 +write 0xfbefff0e 0x1 0x20 +write 0xfbefff0f 0x1 0x00 +write 0xfbefff2a 0x1 0x01 +write 0xfbefff0c 0x1 0x00 +write 0xfbefff03 0x1 0x00 +write 0xfbefff05 0x1 0x00 +write 0xfbefff2a 0x1 0x02 +write 0xfbefff0c 0x1 0x32 +write 0xfbefff01 0x1 0x01 +write 0xfbefff02 0x1 0x01 +write 0xfbefff03 0x1 0x01 + +cannot be reproduced with the following QEMU command line: + +$ qemu-system-x86_64 -nographic -machine accel=qtest -m 512M \ + -nodefaults -device sdhci-pci,sd-spec-version=3 \ + -drive if=sd,index=0,file=null-co://,format=raw,id=mydrive \ + -device sd-card,drive=mydrive -qtest stdio + +Cc: qemu-stable@nongnu.org +Fixes: CVE-2020-17380 +Fixes: CVE-2020-25085 +Fixes: CVE-2021-3409 +Fixes: d7dfca0807a0 ("hw/sdhci: introduce standard SD host controller") +Reported-by: Alexander Bulekov <alxndr@bu.edu> +Reported-by: Cornelius Aschermann (Ruhr-Universität Bochum) +Reported-by: Sergej Schumilo (Ruhr-Universität Bochum) +Reported-by: Simon Wörner (Ruhr-Universität Bochum) +Buglink: https://bugs.launchpad.net/qemu/+bug/1892960 +Buglink: https://bugs.launchpad.net/qemu/+bug/1909418 +Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1928146 +Tested-by: Alexander Bulekov <alxndr@bu.edu> +Signed-off-by: Bin Meng <bmeng.cn@gmail.com> +Message-Id: <20210303122639.20004-3-bmeng.cn@gmail.com> +Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org> + +CVE: CVE-2021-3409 CVE-2020-17380 +Upstream-Status: Backport [import from ubuntu https://git.launchpad.net/ubuntu/+source/qemu/tree/debian/patches/CVE-2021-3409-2.patch?h=ubuntu/focal-security Upstream commit https://github.com/qemu/qemu/commit/8be45cc947832b3c02144c9d52921f499f2d77fe ] +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> +--- + hw/sd/sdhci.c | 20 +++++++++++--------- + 1 file changed, 11 insertions(+), 9 deletions(-) + +--- a/hw/sd/sdhci.c ++++ b/hw/sd/sdhci.c +@@ -1117,15 +1117,17 @@ sdhci_write(void *opaque, hwaddr offset, + + switch (offset & ~0x3) { + case SDHC_SYSAD: +- s->sdmasysad = (s->sdmasysad & mask) | value; +- MASKED_WRITE(s->sdmasysad, mask, value); +- /* Writing to last byte of sdmasysad might trigger transfer */ +- if (!(mask & 0xFF000000) && TRANSFERRING_DATA(s->prnsts) && s->blkcnt && +- s->blksize && SDHC_DMA_TYPE(s->hostctl1) == SDHC_CTRL_SDMA) { +- if (s->trnmod & SDHC_TRNS_MULTI) { +- sdhci_sdma_transfer_multi_blocks(s); +- } else { +- sdhci_sdma_transfer_single_block(s); ++ if (!TRANSFERRING_DATA(s->prnsts)) { ++ s->sdmasysad = (s->sdmasysad & mask) | value; ++ MASKED_WRITE(s->sdmasysad, mask, value); ++ /* Writing to last byte of sdmasysad might trigger transfer */ ++ if (!(mask & 0xFF000000) && s->blkcnt && s->blksize && ++ SDHC_DMA_TYPE(s->hostctl1) == SDHC_CTRL_SDMA) { ++ if (s->trnmod & SDHC_TRNS_MULTI) { ++ sdhci_sdma_transfer_multi_blocks(s); ++ } else { ++ sdhci_sdma_transfer_single_block(s); ++ } + } + } + break; diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-3409-3.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-3409-3.patch new file mode 100644 index 0000000000..d06ac0ed3c --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-3409-3.patch @@ -0,0 +1,71 @@ +Backport of: + +From bc6f28995ff88f5d82c38afcfd65406f0ae375aa Mon Sep 17 00:00:00 2001 +From: Bin Meng <bmeng.cn@gmail.com> +Date: Wed, 3 Mar 2021 20:26:37 +0800 +Subject: [PATCH] hw/sd: sdhci: Correctly set the controller status for ADMA +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf8 +Content-Transfer-Encoding: 8bit + +When an ADMA transfer is started, the codes forget to set the +controller status to indicate a transfer is in progress. + +With this fix, the following 2 reproducers: + +https://paste.debian.net/plain/1185136 +https://paste.debian.net/plain/1185141 + +cannot be reproduced with the following QEMU command line: + +$ qemu-system-x86_64 -nographic -machine accel=qtest -m 512M \ + -nodefaults -device sdhci-pci,sd-spec-version=3 \ + -drive if=sd,index=0,file=null-co://,format=raw,id=mydrive \ + -device sd-card,drive=mydrive -qtest stdio + +Cc: qemu-stable@nongnu.org +Fixes: CVE-2020-17380 +Fixes: CVE-2020-25085 +Fixes: CVE-2021-3409 +Fixes: d7dfca0807a0 ("hw/sdhci: introduce standard SD host controller") +Reported-by: Alexander Bulekov <alxndr@bu.edu> +Reported-by: Cornelius Aschermann (Ruhr-Universität Bochum) +Reported-by: Sergej Schumilo (Ruhr-Universität Bochum) +Reported-by: Simon Wörner (Ruhr-Universität Bochum) +Buglink: https://bugs.launchpad.net/qemu/+bug/1892960 +Buglink: https://bugs.launchpad.net/qemu/+bug/1909418 +Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1928146 +Tested-by: Alexander Bulekov <alxndr@bu.edu> +Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> +Signed-off-by: Bin Meng <bmeng.cn@gmail.com> +Message-Id: <20210303122639.20004-4-bmeng.cn@gmail.com> +Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org> + +CVE: CVE-2021-3409 CVE-2020-17380 +Upstream-Status: Backport [import from ubuntu https://git.launchpad.net/ubuntu/+source/qemu/tree/debian/patches/CVE-2021-3409-3.patch?h=ubuntu/focal-security Upstream commit https://github.com/qemu/qemu/commit/bc6f28995ff88f5d82c38afcfd65406f0ae375aa ] +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> +--- + hw/sd/sdhci.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/hw/sd/sdhci.c ++++ b/hw/sd/sdhci.c +@@ -776,8 +776,9 @@ static void sdhci_do_adma(SDHCIState *s) + + switch (dscr.attr & SDHC_ADMA_ATTR_ACT_MASK) { + case SDHC_ADMA_ATTR_ACT_TRAN: /* data transfer */ +- ++ s->prnsts |= SDHC_DATA_INHIBIT | SDHC_DAT_LINE_ACTIVE; + if (s->trnmod & SDHC_TRNS_READ) { ++ s->prnsts |= SDHC_DOING_READ; + while (length) { + if (s->data_count == 0) { + for (n = 0; n < block_size; n++) { +@@ -807,6 +808,7 @@ static void sdhci_do_adma(SDHCIState *s) + } + } + } else { ++ s->prnsts |= SDHC_DOING_WRITE; + while (length) { + begin = s->data_count; + if ((length + begin) < block_size) { diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-3409-4.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-3409-4.patch new file mode 100644 index 0000000000..2e49e3bc18 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-3409-4.patch @@ -0,0 +1,52 @@ +Backport of: + +From 5cd7aa3451b76bb19c0f6adc2b931f091e5d7fcd Mon Sep 17 00:00:00 2001 +From: Bin Meng <bmeng.cn@gmail.com> +Date: Wed, 3 Mar 2021 20:26:38 +0800 +Subject: [PATCH] hw/sd: sdhci: Limit block size only when SDHC_BLKSIZE + register is writable +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf8 +Content-Transfer-Encoding: 8bit + +The codes to limit the maximum block size is only necessary when +SDHC_BLKSIZE register is writable. + +Tested-by: Alexander Bulekov <alxndr@bu.edu> +Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> +Signed-off-by: Bin Meng <bmeng.cn@gmail.com> +Message-Id: <20210303122639.20004-5-bmeng.cn@gmail.com> +Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org> + +CVE: CVE-2021-3409 CVE-2020-17380 +Upstream-Status: Backport [import from ubuntu https://git.launchpad.net/ubuntu/+source/qemu/tree/debian/patches/CVE-2021-3409-4.patch?h=ubuntu/focal-security Upstream commit https://github.com/qemu/qemu/commit/5cd7aa3451b76bb19c0f6adc2b931f091e5d7fcd ] +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> +--- + hw/sd/sdhci.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +--- a/hw/sd/sdhci.c ++++ b/hw/sd/sdhci.c +@@ -1137,15 +1137,15 @@ sdhci_write(void *opaque, hwaddr offset, + if (!TRANSFERRING_DATA(s->prnsts)) { + MASKED_WRITE(s->blksize, mask, extract32(value, 0, 12)); + MASKED_WRITE(s->blkcnt, mask >> 16, value >> 16); +- } + +- /* Limit block size to the maximum buffer size */ +- if (extract32(s->blksize, 0, 12) > s->buf_maxsz) { +- qemu_log_mask(LOG_GUEST_ERROR, "%s: Size 0x%x is larger than " \ +- "the maximum buffer 0x%x", __func__, s->blksize, +- s->buf_maxsz); ++ /* Limit block size to the maximum buffer size */ ++ if (extract32(s->blksize, 0, 12) > s->buf_maxsz) { ++ qemu_log_mask(LOG_GUEST_ERROR, "%s: Size 0x%x is larger than " ++ "the maximum buffer 0x%x\n", __func__, s->blksize, ++ s->buf_maxsz); + +- s->blksize = deposit32(s->blksize, 0, 12, s->buf_maxsz); ++ s->blksize = deposit32(s->blksize, 0, 12, s->buf_maxsz); ++ } + } + + break; diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-3409-5.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-3409-5.patch new file mode 100644 index 0000000000..7b436809e9 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-3409-5.patch @@ -0,0 +1,93 @@ +From cffb446e8fd19a14e1634c7a3a8b07be3f01d5c9 Mon Sep 17 00:00:00 2001 +From: Bin Meng <bmeng.cn@gmail.com> +Date: Wed, 3 Mar 2021 20:26:39 +0800 +Subject: [PATCH] hw/sd: sdhci: Reset the data pointer of s->fifo_buffer[] when + a different block size is programmed +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf8 +Content-Transfer-Encoding: 8bit + +If the block size is programmed to a different value from the +previous one, reset the data pointer of s->fifo_buffer[] so that +s->fifo_buffer[] can be filled in using the new block size in +the next transfer. + +With this fix, the following reproducer: + +outl 0xcf8 0x80001010 +outl 0xcfc 0xe0000000 +outl 0xcf8 0x80001001 +outl 0xcfc 0x06000000 +write 0xe000002c 0x1 0x05 +write 0xe0000005 0x1 0x02 +write 0xe0000007 0x1 0x01 +write 0xe0000028 0x1 0x10 +write 0x0 0x1 0x23 +write 0x2 0x1 0x08 +write 0xe000000c 0x1 0x01 +write 0xe000000e 0x1 0x20 +write 0xe000000f 0x1 0x00 +write 0xe000000c 0x1 0x32 +write 0xe0000004 0x2 0x0200 +write 0xe0000028 0x1 0x00 +write 0xe0000003 0x1 0x40 + +cannot be reproduced with the following QEMU command line: + +$ qemu-system-x86_64 -nographic -machine accel=qtest -m 512M \ + -nodefaults -device sdhci-pci,sd-spec-version=3 \ + -drive if=sd,index=0,file=null-co://,format=raw,id=mydrive \ + -device sd-card,drive=mydrive -qtest stdio + +Cc: qemu-stable@nongnu.org +Fixes: CVE-2020-17380 +Fixes: CVE-2020-25085 +Fixes: CVE-2021-3409 +Fixes: d7dfca0807a0 ("hw/sdhci: introduce standard SD host controller") +Reported-by: Alexander Bulekov <alxndr@bu.edu> +Reported-by: Cornelius Aschermann (Ruhr-Universität Bochum) +Reported-by: Sergej Schumilo (Ruhr-Universität Bochum) +Reported-by: Simon Wörner (Ruhr-Universität Bochum) +Buglink: https://bugs.launchpad.net/qemu/+bug/1892960 +Buglink: https://bugs.launchpad.net/qemu/+bug/1909418 +Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1928146 +Tested-by: Alexander Bulekov <alxndr@bu.edu> +Signed-off-by: Bin Meng <bmeng.cn@gmail.com> +Message-Id: <20210303122639.20004-6-bmeng.cn@gmail.com> +Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org> + +CVE: CVE-2021-3409 CVE-2020-17380 +Upstream-Status: Backport [import from ubuntu https://git.launchpad.net/ubuntu/+source/qemu/tree/debian/patches/CVE-2021-3409-5.patch?h=ubuntu/focal-security Upstream commit https://github.com/qemu/qemu/commit/cffb446e8fd19a14e1634c7a3a8b07be3f01d5c9 ] +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> +--- + hw/sd/sdhci.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +--- a/hw/sd/sdhci.c ++++ b/hw/sd/sdhci.c +@@ -1135,6 +1135,8 @@ sdhci_write(void *opaque, hwaddr offset, + break; + case SDHC_BLKSIZE: + if (!TRANSFERRING_DATA(s->prnsts)) { ++ uint16_t blksize = s->blksize; ++ + MASKED_WRITE(s->blksize, mask, extract32(value, 0, 12)); + MASKED_WRITE(s->blkcnt, mask >> 16, value >> 16); + +@@ -1146,6 +1148,16 @@ sdhci_write(void *opaque, hwaddr offset, + + s->blksize = deposit32(s->blksize, 0, 12, s->buf_maxsz); + } ++ ++ /* ++ * If the block size is programmed to a different value from ++ * the previous one, reset the data pointer of s->fifo_buffer[] ++ * so that s->fifo_buffer[] can be filled in using the new block ++ * size in the next transfer. ++ */ ++ if (blksize != s->blksize) { ++ s->data_count = 0; ++ } + } + + break; diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-3416_1.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-3416_1.patch new file mode 100644 index 0000000000..5bacd67481 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-3416_1.patch @@ -0,0 +1,177 @@ +From 4b1988a29d67277d6c8ce1df52975f5616592913 Mon Sep 17 00:00:00 2001 +From: Jason Wang <jasowang@redhat.com> +Date: Wed, 24 Feb 2021 11:44:36 +0800 +Subject: [PATCH 01/10] net: introduce qemu_receive_packet() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Some NIC supports loopback mode and this is done by calling +nc->info->receive() directly which in fact suppresses the effort of +reentrancy check that is done in qemu_net_queue_send(). + +Unfortunately we can't use qemu_net_queue_send() here since for +loopback there's no sender as peer, so this patch introduce a +qemu_receive_packet() which is used for implementing loopback mode +for a NIC with this check. + +NIC that supports loopback mode will be converted to this helper. + +This is intended to address CVE-2021-3416. + +Cc: Prasad J Pandit <ppandit@redhat.com> +Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> +Cc: qemu-stable@nongnu.org +Signed-off-by: Jason Wang <jasowang@redhat.com> + +Upstream-Status: Backport [705df5466c98f3efdd2b68d3b31dad86858acad7] +CVE: CVE-2021-3416 + +Signed-off-by: Sakib Sajal <sakib.sajal@windriver.com> +--- + include/net/net.h | 5 +++++ + include/net/queue.h | 8 ++++++++ + net/net.c | 38 +++++++++++++++++++++++++++++++------- + net/queue.c | 22 ++++++++++++++++++++++ + 4 files changed, 66 insertions(+), 7 deletions(-) + +diff --git a/include/net/net.h b/include/net/net.h +index 778fc787c..03f058ecb 100644 +--- a/include/net/net.h ++++ b/include/net/net.h +@@ -143,12 +143,17 @@ void *qemu_get_nic_opaque(NetClientState *nc); + void qemu_del_net_client(NetClientState *nc); + typedef void (*qemu_nic_foreach)(NICState *nic, void *opaque); + void qemu_foreach_nic(qemu_nic_foreach func, void *opaque); ++int qemu_can_receive_packet(NetClientState *nc); + int qemu_can_send_packet(NetClientState *nc); + ssize_t qemu_sendv_packet(NetClientState *nc, const struct iovec *iov, + int iovcnt); + ssize_t qemu_sendv_packet_async(NetClientState *nc, const struct iovec *iov, + int iovcnt, NetPacketSent *sent_cb); + ssize_t qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size); ++ssize_t qemu_receive_packet(NetClientState *nc, const uint8_t *buf, int size); ++ssize_t qemu_receive_packet_iov(NetClientState *nc, ++ const struct iovec *iov, ++ int iovcnt); + ssize_t qemu_send_packet_raw(NetClientState *nc, const uint8_t *buf, int size); + ssize_t qemu_send_packet_async(NetClientState *nc, const uint8_t *buf, + int size, NetPacketSent *sent_cb); +diff --git a/include/net/queue.h b/include/net/queue.h +index c0269bb1d..9f2f289d7 100644 +--- a/include/net/queue.h ++++ b/include/net/queue.h +@@ -55,6 +55,14 @@ void qemu_net_queue_append_iov(NetQueue *queue, + + void qemu_del_net_queue(NetQueue *queue); + ++ssize_t qemu_net_queue_receive(NetQueue *queue, ++ const uint8_t *data, ++ size_t size); ++ ++ssize_t qemu_net_queue_receive_iov(NetQueue *queue, ++ const struct iovec *iov, ++ int iovcnt); ++ + ssize_t qemu_net_queue_send(NetQueue *queue, + NetClientState *sender, + unsigned flags, +diff --git a/net/net.c b/net/net.c +index 6a2c3d956..5e15e5d27 100644 +--- a/net/net.c ++++ b/net/net.c +@@ -528,6 +528,17 @@ int qemu_set_vnet_be(NetClientState *nc, bool is_be) + #endif + } + ++int qemu_can_receive_packet(NetClientState *nc) ++{ ++ if (nc->receive_disabled) { ++ return 0; ++ } else if (nc->info->can_receive && ++ !nc->info->can_receive(nc)) { ++ return 0; ++ } ++ return 1; ++} ++ + int qemu_can_send_packet(NetClientState *sender) + { + int vm_running = runstate_is_running(); +@@ -540,13 +551,7 @@ int qemu_can_send_packet(NetClientState *sender) + return 1; + } + +- if (sender->peer->receive_disabled) { +- return 0; +- } else if (sender->peer->info->can_receive && +- !sender->peer->info->can_receive(sender->peer)) { +- return 0; +- } +- return 1; ++ return qemu_can_receive_packet(sender->peer); + } + + static ssize_t filter_receive_iov(NetClientState *nc, +@@ -679,6 +684,25 @@ ssize_t qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size) + return qemu_send_packet_async(nc, buf, size, NULL); + } + ++ssize_t qemu_receive_packet(NetClientState *nc, const uint8_t *buf, int size) ++{ ++ if (!qemu_can_receive_packet(nc)) { ++ return 0; ++ } ++ ++ return qemu_net_queue_receive(nc->incoming_queue, buf, size); ++} ++ ++ssize_t qemu_receive_packet_iov(NetClientState *nc, const struct iovec *iov, ++ int iovcnt) ++{ ++ if (!qemu_can_receive_packet(nc)) { ++ return 0; ++ } ++ ++ return qemu_net_queue_receive_iov(nc->incoming_queue, iov, iovcnt); ++} ++ + ssize_t qemu_send_packet_raw(NetClientState *nc, const uint8_t *buf, int size) + { + return qemu_send_packet_async_with_flags(nc, QEMU_NET_PACKET_FLAG_RAW, +diff --git a/net/queue.c b/net/queue.c +index 19e32c80f..c872d51df 100644 +--- a/net/queue.c ++++ b/net/queue.c +@@ -182,6 +182,28 @@ static ssize_t qemu_net_queue_deliver_iov(NetQueue *queue, + return ret; + } + ++ssize_t qemu_net_queue_receive(NetQueue *queue, ++ const uint8_t *data, ++ size_t size) ++{ ++ if (queue->delivering) { ++ return 0; ++ } ++ ++ return qemu_net_queue_deliver(queue, NULL, 0, data, size); ++} ++ ++ssize_t qemu_net_queue_receive_iov(NetQueue *queue, ++ const struct iovec *iov, ++ int iovcnt) ++{ ++ if (queue->delivering) { ++ return 0; ++ } ++ ++ return qemu_net_queue_deliver_iov(queue, NULL, 0, iov, iovcnt); ++} ++ + ssize_t qemu_net_queue_send(NetQueue *queue, + NetClientState *sender, + unsigned flags, +-- +2.29.2 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-3416_10.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-3416_10.patch new file mode 100644 index 0000000000..fdb4894e44 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-3416_10.patch @@ -0,0 +1,41 @@ +From 65b851efd3d0280425c202f4e5880c48f8334dae Mon Sep 17 00:00:00 2001 +From: Alexander Bulekov <alxndr@bu.edu> +Date: Mon, 1 Mar 2021 14:35:30 -0500 +Subject: [PATCH 10/10] lan9118: switch to use qemu_receive_packet() for + loopback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch switches to use qemu_receive_packet() which can detect +reentrancy and return early. + +This is intended to address CVE-2021-3416. + +Cc: Prasad J Pandit <ppandit@redhat.com> +Cc: qemu-stable@nongnu.org +Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com +Signed-off-by: Alexander Bulekov <alxndr@bu.edu> +Signed-off-by: Jason Wang <jasowang@redhat.com> + +Upstream-Status: Backport [37cee01784ff0df13e5209517e1b3594a5e792d1] +CVE: CVE-2021-3416 + +Signed-off-by: Sakib Sajal <sakib.sajal@windriver.com> +--- + hw/net/lan9118.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: qemu-4.2.0/hw/net/lan9118.c +=================================================================== +--- qemu-4.2.0.orig/hw/net/lan9118.c ++++ qemu-4.2.0/hw/net/lan9118.c +@@ -667,7 +667,7 @@ static void do_tx_packet(lan9118_state * + /* FIXME: Honor TX disable, and allow queueing of packets. */ + if (s->phy_control & 0x4000) { + /* This assumes the receive routine doesn't touch the VLANClient. */ +- lan9118_receive(qemu_get_queue(s->nic), s->txp->data, s->txp->len); ++ qemu_receive_packet(qemu_get_queue(s->nic), s->txp->data, s->txp->len); + } else { + qemu_send_packet(qemu_get_queue(s->nic), s->txp->data, s->txp->len); + } diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-3416_2.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-3416_2.patch new file mode 100644 index 0000000000..5e53e20bac --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-3416_2.patch @@ -0,0 +1,42 @@ +From e2a48a3c7cc33dbbe89f896e0f07462cb04ff6b5 Mon Sep 17 00:00:00 2001 +From: Jason Wang <jasowang@redhat.com> +Date: Wed, 24 Feb 2021 12:13:22 +0800 +Subject: [PATCH 02/10] e1000: switch to use qemu_receive_packet() for loopback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch switches to use qemu_receive_packet() which can detect +reentrancy and return early. + +This is intended to address CVE-2021-3416. + +Cc: Prasad J Pandit <ppandit@redhat.com> +Cc: qemu-stable@nongnu.org +Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> +Signed-off-by: Jason Wang <jasowang@redhat.com> + +Upstream-Status: Backport [1caff0340f49c93d535c6558a5138d20d475315c] +CVE: CVE-2021-3416 + +Signed-off-by: Sakib Sajal <sakib.sajal@windriver.com> +--- + hw/net/e1000.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/net/e1000.c b/hw/net/e1000.c +index d7d05ae30..cf22c4f07 100644 +--- a/hw/net/e1000.c ++++ b/hw/net/e1000.c +@@ -546,7 +546,7 @@ e1000_send_packet(E1000State *s, const uint8_t *buf, int size) + + NetClientState *nc = qemu_get_queue(s->nic); + if (s->phy_reg[PHY_CTRL] & MII_CR_LOOPBACK) { +- nc->info->receive(nc, buf, size); ++ qemu_receive_packet(nc, buf, size); + } else { + qemu_send_packet(nc, buf, size); + } +-- +2.29.2 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-3416_3.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-3416_3.patch new file mode 100644 index 0000000000..3fc469e3e3 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-3416_3.patch @@ -0,0 +1,43 @@ +From c041a4da1ff119715e0ccf2d4a7af62568f17b93 Mon Sep 17 00:00:00 2001 +From: Jason Wang <jasowang@redhat.com> +Date: Wed, 24 Feb 2021 12:57:40 +0800 +Subject: [PATCH 03/10] dp8393x: switch to use qemu_receive_packet() for + loopback packet +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch switches to use qemu_receive_packet() which can detect +reentrancy and return early. + +This is intended to address CVE-2021-3416. + +Cc: Prasad J Pandit <ppandit@redhat.com> +Cc: qemu-stable@nongnu.org +Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com +Signed-off-by: Jason Wang <jasowang@redhat.com> + +Upstream-Status: Backport [331d2ac9ea307c990dc86e6493e8f0c48d14bb33] +CVE: CVE-2021-3416 + +Signed-off-by: Sakib Sajal <sakib.sajal@windriver.com> +--- + hw/net/dp8393x.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c +index 205c0decc..533a8304d 100644 +--- a/hw/net/dp8393x.c ++++ b/hw/net/dp8393x.c +@@ -506,7 +506,7 @@ static void dp8393x_do_transmit_packets(dp8393xState *s) + s->regs[SONIC_TCR] |= SONIC_TCR_CRSL; + if (nc->info->can_receive(nc)) { + s->loopback_packet = 1; +- nc->info->receive(nc, s->tx_buffer, tx_len); ++ qemu_receive_packet(nc, s->tx_buffer, tx_len); + } + } else { + /* Transmit packet */ +-- +2.29.2 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-3416_5.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-3416_5.patch new file mode 100644 index 0000000000..93202ebcef --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-3416_5.patch @@ -0,0 +1,42 @@ +From d465dc79c9ee729d91ef086b993e956b1935be69 Mon Sep 17 00:00:00 2001 +From: Jason Wang <jasowang@redhat.com> +Date: Wed, 24 Feb 2021 13:14:35 +0800 +Subject: [PATCH 05/10] sungem: switch to use qemu_receive_packet() for + loopback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch switches to use qemu_receive_packet() which can detect +reentrancy and return early. + +This is intended to address CVE-2021-3416. + +Cc: Prasad J Pandit <ppandit@redhat.com> +Cc: qemu-stable@nongnu.org +Reviewed-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> +Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> +Reviewed-by: Alistair Francis <alistair.francis@wdc.com> +Signed-off-by: Jason Wang <jasowang@redhat.com> + +Upstream-Status: Backport [8c92060d3c0248bd4d515719a35922cd2391b9b4] +CVE: CVE-2021-3416 + +Signed-off-by: Sakib Sajal <sakib.sajal@windriver.com> +--- + hw/net/sungem.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: qemu-4.2.0/hw/net/sungem.c +=================================================================== +--- qemu-4.2.0.orig/hw/net/sungem.c ++++ qemu-4.2.0/hw/net/sungem.c +@@ -305,7 +305,7 @@ static void sungem_send_packet(SunGEMSta + NetClientState *nc = qemu_get_queue(s->nic); + + if (s->macregs[MAC_XIFCFG >> 2] & MAC_XIFCFG_LBCK) { +- nc->info->receive(nc, buf, size); ++ qemu_receive_packet(nc, buf, size); + } else { + qemu_send_packet(nc, buf, size); + } diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-3416_6.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-3416_6.patch new file mode 100644 index 0000000000..40b4bd96e7 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-3416_6.patch @@ -0,0 +1,40 @@ +From c0010f9b2bafe866fe32e3c2688454bc24147136 Mon Sep 17 00:00:00 2001 +From: Jason Wang <jasowang@redhat.com> +Date: Wed, 24 Feb 2021 13:27:52 +0800 +Subject: [PATCH 06/10] tx_pkt: switch to use qemu_receive_packet_iov() for + loopback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch switches to use qemu_receive_receive_iov() which can detect +reentrancy and return early. + +This is intended to address CVE-2021-3416. + +Cc: Prasad J Pandit <ppandit@redhat.com> +Cc: qemu-stable@nongnu.org +Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> +Signed-off-by: Jason Wang <jasowang@redhat.com> + +Upstream-Status: Backport [8c552542b81e56ff532dd27ec6e5328954bdda73] +CVE: CVE-2021-3416 + +Signed-off-by: Sakib Sajal <sakib.sajal@windriver.com> +--- + hw/net/net_tx_pkt.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: qemu-4.2.0/hw/net/net_tx_pkt.c +=================================================================== +--- qemu-4.2.0.orig/hw/net/net_tx_pkt.c ++++ qemu-4.2.0/hw/net/net_tx_pkt.c +@@ -544,7 +544,7 @@ static inline void net_tx_pkt_sendv(stru + NetClientState *nc, const struct iovec *iov, int iov_cnt) + { + if (pkt->is_loopback) { +- nc->info->receive_iov(nc, iov, iov_cnt); ++ qemu_receive_packet_iov(nc, iov, iov_cnt); + } else { + qemu_sendv_packet(nc, iov, iov_cnt); + } diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-3416_7.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-3416_7.patch new file mode 100644 index 0000000000..b3b702cca4 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-3416_7.patch @@ -0,0 +1,42 @@ +From 64b38675c728354e4015e4bec3d975cd4cb8a981 Mon Sep 17 00:00:00 2001 +From: Alexander Bulekov <alxndr@bu.edu> +Date: Fri, 26 Feb 2021 13:47:53 -0500 +Subject: [PATCH 07/10] rtl8139: switch to use qemu_receive_packet() for + loopback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch switches to use qemu_receive_packet() which can detect +reentrancy and return early. + +This is intended to address CVE-2021-3416. + +Cc: Prasad J Pandit <ppandit@redhat.com> +Cc: qemu-stable@nongnu.org +Buglink: https://bugs.launchpad.net/qemu/+bug/1910826 +Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com +Signed-off-by: Alexander Bulekov <alxndr@bu.edu> +Signed-off-by: Jason Wang <jasowang@redhat.com> + +Upstream-Status: Backport [5311fb805a4403bba024e83886fa0e7572265de4] +CVE: CVE-2021-3416 + +Signed-off-by: Sakib Sajal <sakib.sajal@windriver.com> +--- + hw/net/rtl8139.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: qemu-4.2.0/hw/net/rtl8139.c +=================================================================== +--- qemu-4.2.0.orig/hw/net/rtl8139.c ++++ qemu-4.2.0/hw/net/rtl8139.c +@@ -1793,7 +1793,7 @@ static void rtl8139_transfer_frame(RTL81 + } + + DPRINTF("+++ transmit loopback mode\n"); +- rtl8139_do_receive(qemu_get_queue(s->nic), buf, size, do_interrupt); ++ qemu_receive_packet(qemu_get_queue(s->nic), buf, size); + + if (iov) { + g_free(buf2); diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-3416_8.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-3416_8.patch new file mode 100644 index 0000000000..ed716468dc --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-3416_8.patch @@ -0,0 +1,44 @@ +From 023ce62f0a788ad3a8233c7a828554bceeafd031 Mon Sep 17 00:00:00 2001 +From: Alexander Bulekov <alxndr@bu.edu> +Date: Mon, 1 Mar 2021 10:33:34 -0500 +Subject: [PATCH 08/10] pcnet: switch to use qemu_receive_packet() for loopback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch switches to use qemu_receive_packet() which can detect +reentrancy and return early. + +This is intended to address CVE-2021-3416. + +Cc: Prasad J Pandit <ppandit@redhat.com> +Cc: qemu-stable@nongnu.org +Buglink: https://bugs.launchpad.net/qemu/+bug/1917085 +Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com +Signed-off-by: Alexander Bulekov <alxndr@bu.edu> +Signed-off-by: Jason Wang <jasowang@redhat.com> + +Upstream-Status: Backport [99ccfaa1edafd79f7a3a0ff7b58ae4da7c514928] +CVE: CVE-2021-3416 + +Signed-off-by: Sakib Sajal <sakib.sajal@windriver.com> +--- + hw/net/pcnet.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/net/pcnet.c b/hw/net/pcnet.c +index f3f18d859..dcd3fc494 100644 +--- a/hw/net/pcnet.c ++++ b/hw/net/pcnet.c +@@ -1250,7 +1250,7 @@ txagain: + if (BCR_SWSTYLE(s) == 1) + add_crc = !GET_FIELD(tmd.status, TMDS, NOFCS); + s->looptest = add_crc ? PCNET_LOOPTEST_CRC : PCNET_LOOPTEST_NOCRC; +- pcnet_receive(qemu_get_queue(s->nic), s->buffer, s->xmit_pos); ++ qemu_receive_packet(qemu_get_queue(s->nic), s->buffer, s->xmit_pos); + s->looptest = 0; + } else { + if (s->nic) { +-- +2.29.2 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-3416_9.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-3416_9.patch new file mode 100644 index 0000000000..f4a985604e --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-3416_9.patch @@ -0,0 +1,41 @@ +From ecf7e62bb2cb02c9bd40082504ae376f3e19ffd2 Mon Sep 17 00:00:00 2001 +From: Alexander Bulekov <alxndr@bu.edu> +Date: Mon, 1 Mar 2021 14:33:43 -0500 +Subject: [PATCH 09/10] cadence_gem: switch to use qemu_receive_packet() for + loopback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch switches to use qemu_receive_packet() which can detect +reentrancy and return early. + +This is intended to address CVE-2021-3416. + +Cc: Prasad J Pandit <ppandit@redhat.com> +Cc: qemu-stable@nongnu.org +Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> +Signed-off-by: Alexander Bulekov <alxndr@bu.edu> +Signed-off-by: Jason Wang <jasowang@redhat.com> + +Upstream-Status: Backport [e73adfbeec9d4e008630c814759052ed945c3fed] +CVE: CVE-2021-3416 + +Signed-off-by: Sakib Sajal <sakib.sajal@windriver.com> +--- + hw/net/cadence_gem.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +Index: qemu-4.2.0/hw/net/cadence_gem.c +=================================================================== +--- qemu-4.2.0.orig/hw/net/cadence_gem.c ++++ qemu-4.2.0/hw/net/cadence_gem.c +@@ -1225,7 +1225,7 @@ static void gem_transmit(CadenceGEMState + /* Send the packet somewhere */ + if (s->phy_loop || (s->regs[GEM_NWCTRL] & + GEM_NWCTRL_LOCALLOOP)) { +- gem_receive(qemu_get_queue(s->nic), tx_packet, ++ qemu_receive_packet(qemu_get_queue(s->nic), tx_packet, + total_bytes); + } else { + qemu_send_packet(qemu_get_queue(s->nic), tx_packet, diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-3507.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-3507.patch new file mode 100644 index 0000000000..4ff3413f8e --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-3507.patch @@ -0,0 +1,87 @@ +From defac5e2fbddf8423a354ff0454283a2115e1367 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= <philmd@redhat.com> +Date: Thu, 18 Nov 2021 12:57:32 +0100 +Subject: [PATCH] hw/block/fdc: Prevent end-of-track overrun (CVE-2021-3507) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Per the 82078 datasheet, if the end-of-track (EOT byte in +the FIFO) is more than the number of sectors per side, the +command is terminated unsuccessfully: + +* 5.2.5 DATA TRANSFER TERMINATION + + The 82078 supports terminal count explicitly through + the TC pin and implicitly through the underrun/over- + run and end-of-track (EOT) functions. For full sector + transfers, the EOT parameter can define the last + sector to be transferred in a single or multisector + transfer. If the last sector to be transferred is a par- + tial sector, the host can stop transferring the data in + mid-sector, and the 82078 will continue to complete + the sector as if a hardware TC was received. The + only difference between these implicit functions and + TC is that they return "abnormal termination" result + status. Such status indications can be ignored if they + were expected. + +* 6.1.3 READ TRACK + + This command terminates when the EOT specified + number of sectors have been read. If the 82078 + does not find an I D Address Mark on the diskette + after the second· occurrence of a pulse on the + INDX# pin, then it sets the IC code in Status Regis- + ter 0 to "01" (Abnormal termination), sets the MA bit + in Status Register 1 to "1", and terminates the com- + mand. + +* 6.1.6 VERIFY + + Refer to Table 6-6 and Table 6-7 for information + concerning the values of MT and EC versus SC and + EOT value. + +* Table 6·6. Result Phase Table + +* Table 6-7. Verify Command Result Phase Table + +Fix by aborting the transfer when EOT > # Sectors Per Side. + +Cc: qemu-stable@nongnu.org +Cc: Hervé Poussineau <hpoussin@reactos.org> +Fixes: baca51faff0 ("floppy driver: disk geometry auto detect") +Reported-by: Alexander Bulekov <alxndr@bu.edu> +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/339 +Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com> +Message-Id: <20211118115733.4038610-2-philmd@redhat.com> +Reviewed-by: Hanna Reitz <hreitz@redhat.com> +Signed-off-by: Kevin Wolf <kwolf@redhat.com> + +Upstream-Status: Backport [https://github.com/qemu/qemu/commit/defac5e2fbddf8423a354ff0454283a2115e1367] +CVE: CVE-2021-3507 +Signed-off-by: Vivek Kumbhar <vkumbhar@mvista.com> +--- + hw/block/fdc.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/hw/block/fdc.c b/hw/block/fdc.c +index 347875a0cdae..57bb355794a9 100644 +--- a/hw/block/fdc.c ++++ b/hw/block/fdc.c +@@ -1530,6 +1530,14 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction) + int tmp; + fdctrl->data_len = 128 << (fdctrl->fifo[5] > 7 ? 7 : fdctrl->fifo[5]); + tmp = (fdctrl->fifo[6] - ks + 1); ++ if (tmp < 0) { ++ FLOPPY_DPRINTF("invalid EOT: %d\n", tmp); ++ fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_MA, 0x00); ++ fdctrl->fifo[3] = kt; ++ fdctrl->fifo[4] = kh; ++ fdctrl->fifo[5] = ks; ++ return; ++ } + if (fdctrl->fifo[0] & 0x80) + tmp += fdctrl->fifo[6]; + fdctrl->data_len *= tmp; diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-3527-1.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-3527-1.patch new file mode 100644 index 0000000000..77a5385692 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-3527-1.patch @@ -0,0 +1,42 @@ +From 05a40b172e4d691371534828078be47e7fff524c Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann <kraxel@redhat.com> +Date: Mon, 3 May 2021 15:29:15 +0200 +Subject: [PATCH] usb: limit combined packets to 1 MiB (CVE-2021-3527) + +usb-host and usb-redirect try to batch bulk transfers by combining many +small usb packets into a single, large transfer request, to reduce the +overhead and improve performance. + +This patch adds a size limit of 1 MiB for those combined packets to +restrict the host resources the guest can bind that way. + +Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> +Message-Id: <20210503132915.2335822-6-kraxel@redhat.com> + +Upstream-Status: Backport +https://gitlab.com/qemu-project/qemu/-/commit/05a40b172e4d691371534828078be47e7fff524c +CVE: CVE-2021-3527 +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> + +--- + hw/usb/combined-packet.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/hw/usb/combined-packet.c b/hw/usb/combined-packet.c +index 5d57e883dc..e56802f89a 100644 +--- a/hw/usb/combined-packet.c ++++ b/hw/usb/combined-packet.c +@@ -171,7 +171,9 @@ void usb_ep_combine_input_packets(USBEndpoint *ep) + if ((p->iov.size % ep->max_packet_size) != 0 || !p->short_not_ok || + next == NULL || + /* Work around for Linux usbfs bulk splitting + migration */ +- (totalsize == (16 * KiB - 36) && p->int_req)) { ++ (totalsize == (16 * KiB - 36) && p->int_req) || ++ /* Next package may grow combined package over 1MiB */ ++ totalsize > 1 * MiB - ep->max_packet_size) { + usb_device_handle_data(ep->dev, first); + assert(first->status == USB_RET_ASYNC); + if (first->combined) { +-- +GitLab + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-3527-2.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-3527-2.patch new file mode 100644 index 0000000000..6371aced12 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-3527-2.patch @@ -0,0 +1,59 @@ +From 7ec54f9eb62b5d177e30eb8b1cad795a5f8d8986 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann <kraxel@redhat.com> +Date: Mon, 3 May 2021 15:29:12 +0200 +Subject: [PATCH] usb/redir: avoid dynamic stack allocation (CVE-2021-3527) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Use autofree heap allocation instead. + +Fixes: 4f4321c11ff ("usb: use iovecs in USBPacket") +Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> +Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> +Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com> +Message-Id: <20210503132915.2335822-3-kraxel@redhat.com> + +Upstream-Status: Backport +https://gitlab.com/qemu-project/qemu/-/commit/7ec54f9eb62b5d177e30eb8b1cad795a5f8d8986 +CVE: CVE-2021-3527 +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> + +--- + hw/usb/redirect.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index 17f06f3417..6a75b0dc4a 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -620,7 +620,7 @@ static void usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, + .endpoint = ep, + .length = p->iov.size + }; +- uint8_t buf[p->iov.size]; ++ g_autofree uint8_t *buf = g_malloc(p->iov.size); + /* No id, we look at the ep when receiving a status back */ + usb_packet_copy(p, buf, p->iov.size); + usbredirparser_send_iso_packet(dev->parser, 0, &iso_packet, +@@ -818,7 +818,7 @@ static void usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p, + usbredirparser_send_bulk_packet(dev->parser, p->id, + &bulk_packet, NULL, 0); + } else { +- uint8_t buf[size]; ++ g_autofree uint8_t *buf = g_malloc(size); + usb_packet_copy(p, buf, size); + usbredir_log_data(dev, "bulk data out:", buf, size); + usbredirparser_send_bulk_packet(dev->parser, p->id, +@@ -923,7 +923,7 @@ static void usbredir_handle_interrupt_out_data(USBRedirDevice *dev, + USBPacket *p, uint8_t ep) + { + struct usb_redir_interrupt_packet_header interrupt_packet; +- uint8_t buf[p->iov.size]; ++ g_autofree uint8_t *buf = g_malloc(p->iov.size); + + DPRINTF("interrupt-out ep %02X len %zd id %"PRIu64"\n", ep, + p->iov.size, p->id); +-- +GitLab + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-3544.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-3544.patch new file mode 100644 index 0000000000..1b4fcbfb60 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-3544.patch @@ -0,0 +1,29 @@ +vhost-user-gpu: fix resource leak in 'vg_resource_create_2d' (CVE-2021-3544) + +Call 'vugbm_buffer_destroy' in error path to avoid resource leak. + +Fixes: CVE-2021-3544 +Reported-by: default avatarLi Qiang <liq3ea@163.com> +Reviewed-by: default avatarPrasad J Pandit <pjp@fedoraproject.org> +Signed-off-by: default avatarLi Qiang <liq3ea@163.com> +Reviewed-by: Marc-André Lureau's avatarMarc-André Lureau <marcandre.lureau@redhat.com> +Message-Id: <20210516030403.107723-3-liq3ea@163.com> +Signed-off-by: Gerd Hoffmann's avatarGerd Hoffmann <kraxel@redhat.com> + +Upstream-Status: Backport +[vhost-user-gpu does not exist in 4.2.0] +CVE: CVE-2021-3544 +Signed-off-by: Armin Kuster <akuster@mvista.com> + +Index: qemu-4.2.0/contrib/vhost-user-gpu/main.c +=================================================================== +--- qemu-4.2.0.orig/contrib/vhost-user-gpu/main.c ++++ qemu-4.2.0/contrib/vhost-user-gpu/main.c +@@ -328,6 +328,7 @@ vg_resource_create_2d(VuGpu *g, + g_critical("%s: resource creation failed %d %d %d", + __func__, c2d.resource_id, c2d.width, c2d.height); + g_free(res); ++ vugbm_buffer_destroy(&res->buffer); + cmd->error = VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY; + return; + } diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-3544_2.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-3544_2.patch new file mode 100644 index 0000000000..36cbb127f8 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-3544_2.patch @@ -0,0 +1,39 @@ +vhost-user-gpu: fix memory leak in vg_resource_attach_backing (CVE-2021-3544) + + +Check whether the 'res' has already been attach_backing to avoid +memory leak. + +Fixes: CVE-2021-3544 +Reported-by: default avatarLi Qiang <liq3ea@163.com> +virtio-gpu fix: 204f01b3 + + ("virtio-gpu: fix memory leak + in resource attach backing") + Signed-off-by: default avatarLi Qiang <liq3ea@163.com> + Reviewed-by: Marc-André Lureau's avatarMarc-André Lureau <marcandre.lureau@redhat.com> + Message-Id: <20210516030403.107723-4-liq3ea@163.com> + Signed-off-by: Gerd Hoffmann's avatarGerd Hoffmann <kraxel@redhat.com> + +Upstream-Status: Backport +[vhost-user-gpu does not exist in 4.2.0 context] +CVE: CVE-2021-3544 +Signed-off-by: Armin Kuster <akuster@mvista.com> + + +Index: qemu-4.2.0/contrib/vhost-user-gpu/main.c +=================================================================== +--- qemu-4.2.0.orig/contrib/vhost-user-gpu/main.c ++++ qemu-4.2.0/contrib/vhost-user-gpu/main.c +@@ -468,6 +468,11 @@ vg_resource_attach_backing(VuGpu *g, + return; + } + ++ if (res->iov) { ++ cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; ++ return; ++ } ++ + ret = vg_create_mapping_iov(g, &ab, cmd, &res->iov); + if (ret != 0) { + cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-3544_3.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-3544_3.patch new file mode 100644 index 0000000000..c534f4c24f --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-3544_3.patch @@ -0,0 +1,39 @@ +vhost-user-gpu: fix memory leak while calling 'vg_resource_unref' (CVE-2021-3544) + +If the guest trigger following sequences, the attach_backing will be leaked: + +vg_resource_create_2d +vg_resource_attach_backing +vg_resource_unref + +This patch fix this by freeing 'res->iov' in vg_resource_destroy. + +Fixes: CVE-2021-3544 +Reported-by: default avatarLi Qiang <liq3ea@163.com> +virtio-gpu fix: 5e8e3c4c + +("virtio-gpu: fix resource leak +in virgl_cmd_resource_unref") +Reviewed-by: default avatarPrasad J Pandit <pjp@fedoraproject.org> +Signed-off-by: default avatarLi Qiang <liq3ea@163.com> +Reviewed-by: Marc-André Lureau's avatarMarc-André Lureau <marcandre.lureau@redhat.com> +Message-Id: <20210516030403.107723-5-liq3ea@163.com> +Signed-off-by: Gerd Hoffmann's avatarGerd Hoffmann <kraxel@redhat.com> + +Upstream-Status: Backport +CVE: CVE-2021-3544 +[vhost-user-gpu does not exist in the 4.2.0] +Signed-off-by: Armin Kuster <akuster@mvista.com> + +Index: qemu-4.2.0/contrib/vhost-user-gpu/main.c +=================================================================== +--- qemu-4.2.0.orig/contrib/vhost-user-gpu/main.c ++++ qemu-4.2.0/contrib/vhost-user-gpu/main.c +@@ -379,6 +379,7 @@ vg_resource_destroy(VuGpu *g, + } + + vugbm_buffer_destroy(&res->buffer); ++ g_free(res->iov); + pixman_image_unref(res->image); + QTAILQ_REMOVE(&g->reslist, res, next); + g_free(res); diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-3544_4.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-3544_4.patch new file mode 100644 index 0000000000..96e36eb854 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-3544_4.patch @@ -0,0 +1,46 @@ +vhost-user-gpu: fix memory leak in 'virgl_cmd_resource_unref' (CVE-2021-3544) + +The 'res->iov' will be leaked if the guest trigger following sequences: + +virgl_cmd_create_resource_2d +virgl_resource_attach_backing +virgl_cmd_resource_unref + +This patch fixes this. + +Fixes: CVE-2021-3544 +Reported-by: default avatarLi Qiang <liq3ea@163.com> +virtio-gpu fix: 5e8e3c4c + +("virtio-gpu: fix resource leak +in virgl_cmd_resource_unref" +Signed-off-by: default avatarLi Qiang <liq3ea@163.com> +Reviewed-by: Marc-André Lureau's avatarMarc-André Lureau <marcandre.lureau@redhat.com> +Message-Id: <20210516030403.107723-6-liq3ea@163.com> +Signed-off-by: Gerd Hoffmann's avatarGerd Hoffmann <kraxel@redhat.com> + +Upstream-Status: Backport +CVE: CVE-2021-3544 +Signed-off-by: Armin Kuster <akuster@mvista.com> + +Index: qemu-4.2.0/contrib/vhost-user-gpu/virgl.c +=================================================================== +--- qemu-4.2.0.orig/contrib/vhost-user-gpu/virgl.c ++++ qemu-4.2.0/contrib/vhost-user-gpu/virgl.c +@@ -105,9 +105,16 @@ virgl_cmd_resource_unref(VuGpu *g, + struct virtio_gpu_ctrl_command *cmd) + { + struct virtio_gpu_resource_unref unref; ++ struct iovec *res_iovs = NULL; ++ int num_iovs = 0; + + VUGPU_FILL_CMD(unref); + ++ virgl_renderer_resource_detach_iov(unref.resource_id, ++ &res_iovs, ++ &num_iovs); ++ g_free(res_iovs); ++ + virgl_renderer_resource_unref(unref.resource_id); + } + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-3544_5.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-3544_5.patch new file mode 100644 index 0000000000..e592ce50e2 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-3544_5.patch @@ -0,0 +1,47 @@ +From 63736af5a6571d9def93769431e0d7e38c6677bf Mon Sep 17 00:00:00 2001 +From: Li Qiang <liq3ea@163.com> +Date: Sat, 15 May 2021 20:04:01 -0700 +Subject: [PATCH] vhost-user-gpu: fix memory leak in + 'virgl_resource_attach_backing' (CVE-2021-3544) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If 'virgl_renderer_resource_attach_iov' failed, the 'res_iovs' will +be leaked. + +Fixes: CVE-2021-3544 +Reported-by: Li Qiang <liq3ea@163.com> +virtio-gpu fix: 33243031da ("virtio-gpu-3d: fix memory leak +in resource attach backing") + +Signed-off-by: Li Qiang <liq3ea@163.com> +Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com> +Message-Id: <20210516030403.107723-7-liq3ea@163.com> +Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> + +Upstream-Status: Backport +CVE: CVE-2021-3544 +Signed-off-by: Armin Kuster <akuster@mvista.com> + +--- + contrib/vhost-user-gpu/virgl.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +Index: qemu-4.2.0/contrib/vhost-user-gpu/virgl.c +=================================================================== +--- qemu-4.2.0.orig/contrib/vhost-user-gpu/virgl.c ++++ qemu-4.2.0/contrib/vhost-user-gpu/virgl.c +@@ -283,8 +283,11 @@ virgl_resource_attach_backing(VuGpu *g, + return; + } + +- virgl_renderer_resource_attach_iov(att_rb.resource_id, ++ ret = virgl_renderer_resource_attach_iov(att_rb.resource_id, + res_iovs, att_rb.nr_entries); ++ if (ret != 0) { ++ g_free(res_iovs); ++ } + } + + static void diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-3545.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-3545.patch new file mode 100644 index 0000000000..fcdda64437 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-3545.patch @@ -0,0 +1,41 @@ +From 121841b25d72d13f8cad554363138c360f1250ea Mon Sep 17 00:00:00 2001 +From: Li Qiang <liq3ea@163.com> +Date: Sat, 15 May 2021 20:03:56 -0700 +Subject: [PATCH] vhost-user-gpu: fix memory disclosure in + virgl_cmd_get_capset_info (CVE-2021-3545) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Otherwise some of the 'resp' will be leaked to guest. + +Fixes: CVE-2021-3545 +Reported-by: Li Qiang <liq3ea@163.com> +virtio-gpu fix: 42a8dadc74 ("virtio-gpu: fix information leak +in getting capset info dispatch") + +Signed-off-by: Li Qiang <liq3ea@163.com> +Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com> +Message-Id: <20210516030403.107723-2-liq3ea@163.com> +Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> + +Upstream-Status: Backport +CVE: CVE-2021-3545 +Signed-off-by: Armin Kuster <akuster@mvista.com> + +--- + contrib/vhost-user-gpu/virgl.c | 1 + + 1 file changed, 1 insertion(+) + +Index: qemu-4.2.0/contrib/vhost-user-gpu/virgl.c +=================================================================== +--- qemu-4.2.0.orig/contrib/vhost-user-gpu/virgl.c ++++ qemu-4.2.0/contrib/vhost-user-gpu/virgl.c +@@ -132,6 +132,7 @@ virgl_cmd_get_capset_info(VuGpu *g, + + VUGPU_FILL_CMD(info); + ++ memset(&resp, 0, sizeof(resp)); + if (info.capset_index == 0) { + resp.capset_id = VIRTIO_GPU_CAPSET_VIRGL; + virgl_renderer_get_cap_set(resp.capset_id, diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-3546.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-3546.patch new file mode 100644 index 0000000000..f8da428233 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-3546.patch @@ -0,0 +1,47 @@ +From 9f22893adcb02580aee5968f32baa2cd109b3ec2 Mon Sep 17 00:00:00 2001 +From: Li Qiang <liq3ea@163.com> +Date: Sat, 15 May 2021 20:04:02 -0700 +Subject: [PATCH] vhost-user-gpu: fix OOB write in 'virgl_cmd_get_capset' + (CVE-2021-3546) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If 'virgl_cmd_get_capset' set 'max_size' to 0, +the 'virgl_renderer_fill_caps' will write the data after the 'resp'. +This patch avoid this by checking the returned 'max_size'. + +virtio-gpu fix: abd7f08b23 ("display: virtio-gpu-3d: check +virgl capabilities max_size") + +Fixes: CVE-2021-3546 +Reported-by: Li Qiang <liq3ea@163.com> +Reviewed-by: Prasad J Pandit <pjp@fedoraproject.org> +Signed-off-by: Li Qiang <liq3ea@163.com> +Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com> +Message-Id: <20210516030403.107723-8-liq3ea@163.com> +Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> + +Upstream-Status: Backport +CVE: CVE-2021-3546 +Signed-off-by: Armin Kuster <akuster@mvista.com> + +--- + contrib/vhost-user-gpu/virgl.c | 4 ++++ + 1 file changed, 4 insertions(+) + +Index: qemu-4.2.0/contrib/vhost-user-gpu/virgl.c +=================================================================== +--- qemu-4.2.0.orig/contrib/vhost-user-gpu/virgl.c ++++ qemu-4.2.0/contrib/vhost-user-gpu/virgl.c +@@ -174,6 +174,10 @@ virgl_cmd_get_capset(VuGpu *g, + + virgl_renderer_get_cap_set(gc.capset_id, &max_ver, + &max_size); ++ if (!max_size) { ++ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; ++ return; ++ } + resp = g_malloc0(sizeof(*resp) + max_size); + + resp->hdr.type = VIRTIO_GPU_RESP_OK_CAPSET; diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-3582.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-3582.patch new file mode 100644 index 0000000000..7a88e29384 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-3582.patch @@ -0,0 +1,47 @@ +From 284f191b4abad213aed04cb0458e1600fd18d7c4 Mon Sep 17 00:00:00 2001 +From: Marcel Apfelbaum <marcel@redhat.com> +Date: Wed, 16 Jun 2021 14:06:00 +0300 +Subject: [PATCH] hw/rdma: Fix possible mremap overflow in the pvrdma device + (CVE-2021-3582) + +Ensure mremap boundaries not trusting the guest kernel to +pass the correct buffer length. + +Fixes: CVE-2021-3582 +Reported-by: VictorV (Kunlun Lab) <vv474172261@gmail.com> +Tested-by: VictorV (Kunlun Lab) <vv474172261@gmail.com> +Signed-off-by: Marcel Apfelbaum <marcel@redhat.com> +Message-Id: <20210616110600.20889-1-marcel.apfelbaum@gmail.com> +Reviewed-by: Yuval Shaia <yuval.shaia.ml@gmail.com> +Tested-by: Yuval Shaia <yuval.shaia.ml@gmail.com> +Reviewed-by: Prasad J Pandit <pjp@fedoraproject.org> +Signed-off-by: Marcel Apfelbaum <marcel.apfelbaum@gmail.com> + +CVE: CVE-2021-3582 +Upstream-Status: Backport [284f191b4abad213aed04cb0458e1600fd18d7c4] +Signed-off-by: Sakib Sajal <sakib.sajal@windriver.com> +--- + hw/rdma/vmw/pvrdma_cmd.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/hw/rdma/vmw/pvrdma_cmd.c b/hw/rdma/vmw/pvrdma_cmd.c +index f59879e257..da7ddfa548 100644 +--- a/hw/rdma/vmw/pvrdma_cmd.c ++++ b/hw/rdma/vmw/pvrdma_cmd.c +@@ -38,6 +38,13 @@ static void *pvrdma_map_to_pdir(PCIDevice *pdev, uint64_t pdir_dma, + return NULL; + } + ++ length = ROUND_UP(length, TARGET_PAGE_SIZE); ++ if (nchunks * TARGET_PAGE_SIZE != length) { ++ rdma_error_report("Invalid nchunks/length (%u, %lu)", nchunks, ++ (unsigned long)length); ++ return NULL; ++ } ++ + dir = rdma_pci_dma_map(pdev, pdir_dma, TARGET_PAGE_SIZE); + if (!dir) { + rdma_error_report("Failed to map to page directory"); +-- +2.25.1 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-3607.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-3607.patch new file mode 100644 index 0000000000..0547c74484 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-3607.patch @@ -0,0 +1,43 @@ +From 32e5703cfea07c91e6e84bcb0313f633bb146534 Mon Sep 17 00:00:00 2001 +From: Marcel Apfelbaum <marcel.apfelbaum@gmail.com> +Date: Wed, 30 Jun 2021 14:46:34 +0300 +Subject: [PATCH] pvrdma: Ensure correct input on ring init (CVE-2021-3607) + +Check the guest passed a non zero page count +for pvrdma device ring buffers. + +Fixes: CVE-2021-3607 +Reported-by: VictorV (Kunlun Lab) <vv474172261@gmail.com> +Reviewed-by: VictorV (Kunlun Lab) <vv474172261@gmail.com> +Signed-off-by: Marcel Apfelbaum <marcel@redhat.com> +Message-Id: <20210630114634.2168872-1-marcel@redhat.com> +Reviewed-by: Yuval Shaia <yuval.shaia.ml@gmail.com> +Tested-by: Yuval Shaia <yuval.shaia.ml@gmail.com> +Signed-off-by: Marcel Apfelbaum <marcel.apfelbaum@gmail.com> + +CVE: CVE-2021-3607 +Upstream-Status: Backport [32e5703cfea07c91e6e84bcb0313f633bb146534] +Signed-off-by: Sakib Sajal <sakib.sajal@windriver.com> +--- + hw/rdma/vmw/pvrdma_main.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/hw/rdma/vmw/pvrdma_main.c b/hw/rdma/vmw/pvrdma_main.c +index 84ae8024fc..7c0c3551a8 100644 +--- a/hw/rdma/vmw/pvrdma_main.c ++++ b/hw/rdma/vmw/pvrdma_main.c +@@ -92,6 +92,11 @@ static int init_dev_ring(PvrdmaRing *ring, PvrdmaRingState **ring_state, + uint64_t *dir, *tbl; + int rc = 0; + ++ if (!num_pages) { ++ rdma_error_report("Ring pages count must be strictly positive"); ++ return -EINVAL; ++ } ++ + dir = rdma_pci_dma_map(pci_dev, dir_addr, TARGET_PAGE_SIZE); + if (!dir) { + rdma_error_report("Failed to map to page directory (ring %s)", name); +-- +2.25.1 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-3608.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-3608.patch new file mode 100644 index 0000000000..7055ec3d23 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-3608.patch @@ -0,0 +1,40 @@ +From 66ae37d8cc313f89272e711174a846a229bcdbd3 Mon Sep 17 00:00:00 2001 +From: Marcel Apfelbaum <marcel.apfelbaum@gmail.com> +Date: Wed, 30 Jun 2021 14:52:46 +0300 +Subject: [PATCH] pvrdma: Fix the ring init error flow (CVE-2021-3608) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Do not unmap uninitialized dma addresses. + +Fixes: CVE-2021-3608 +Reviewed-by: VictorV (Kunlun Lab) <vv474172261@gmail.com> +Tested-by: VictorV (Kunlun Lab) <vv474172261@gmail.com> +Signed-off-by: Marcel Apfelbaum <marcel@redhat.com> +Message-Id: <20210630115246.2178219-1-marcel@redhat.com> +Tested-by: Yuval Shaia <yuval.shaia.ml@gmail.com> +Reviewed-by: Yuval Shaia <yuval.shaia.ml@gmail.com> +Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> +Signed-off-by: Marcel Apfelbaum <marcel.apfelbaum@gmail.com> + +CVE: CVE-2021-3608 +Upstream-Status: Backport [66ae37d8cc313f89272e711174a846a229bcdbd3] +Signed-off-by: Sakib Sajal <sakib.sajal@windriver.com> +--- + hw/rdma/vmw/pvrdma_dev_ring.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: qemu-4.2.0/hw/rdma/vmw/pvrdma_dev_ring.c +=================================================================== +--- qemu-4.2.0.orig/hw/rdma/vmw/pvrdma_dev_ring.c ++++ qemu-4.2.0/hw/rdma/vmw/pvrdma_dev_ring.c +@@ -41,7 +41,7 @@ int pvrdma_ring_init(PvrdmaRing *ring, c + atomic_set(&ring->ring_state->cons_head, 0); + */ + ring->npages = npages; +- ring->pages = g_malloc(npages * sizeof(void *)); ++ ring->pages = g_malloc0(npages * sizeof(void *)); + + for (i = 0; i < npages; i++) { + if (!tbl[i]) { diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-3638.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-3638.patch new file mode 100644 index 0000000000..6e7af8540a --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-3638.patch @@ -0,0 +1,80 @@ +From b68d13531d8882ba66994b9f767b6a8f822464f3 Mon Sep 17 00:00:00 2001 +From: Vivek Kumbhar <vkumbhar@mvista.com> +Date: Fri, 11 Nov 2022 12:43:26 +0530 +Subject: [PATCH] CVE-2021-3638 + +Upstream-Status: Backport [https://lists.nongnu.org/archive/html/qemu-devel/2021-09/msg01682.html] +CVE: CVE-2021-3638 +Signed-off-by: Vivek Kumbhar <vkumbhar@mvista.com> + +When building QEMU with DEBUG_ATI defined then running with +'-device ati-vga,romfile="" -d unimp,guest_errors -trace ati\*' +we get: + + ati_mm_write 4 0x16c0 DP_CNTL <- 0x1 + ati_mm_write 4 0x146c DP_GUI_MASTER_CNTL <- 0x2 + ati_mm_write 4 0x16c8 DP_MIX <- 0xff0000 + ati_mm_write 4 0x16c4 DP_DATATYPE <- 0x2 + ati_mm_write 4 0x224 CRTC_OFFSET <- 0x0 + ati_mm_write 4 0x142c DST_PITCH_OFFSET <- 0xfe00000 + ati_mm_write 4 0x1420 DST_Y <- 0x3fff + ati_mm_write 4 0x1410 DST_HEIGHT <- 0x3fff + ati_mm_write 4 0x1588 DST_WIDTH_X <- 0x3fff3fff + ati_2d_blt: vram:0x7fff5fa00000 addr:0 ds:0x7fff61273800 stride:2560 bpp:32 +rop:0xff + ati_2d_blt: 0 0 0, 0 127 0, (0,0) -> (16383,16383) 16383x16383 > ^ + ati_2d_blt: pixman_fill(dst:0x7fff5fa00000, stride:254, bpp:8, x:16383, +y:16383, w:16383, h:16383, xor:0xff000000) + Thread 3 "qemu-system-i38" received signal SIGSEGV, Segmentation fault. + (gdb) bt + #0 0x00007ffff7f62ce0 in sse2_fill.lto_priv () at /lib64/libpixman-1.so.0 + #1 0x00007ffff7f09278 in pixman_fill () at /lib64/libpixman-1.so.0 + #2 0x0000555557b5a9af in ati_2d_blt (s=0x631000028800) at +hw/display/ati_2d.c:196 + #3 0x0000555557b4b5a2 in ati_mm_write (opaque=0x631000028800, addr=5512, +data=1073692671, size=4) at hw/display/ati.c:843 + #4 0x0000555558b90ec4 in memory_region_write_accessor (mr=0x631000039cc0, +addr=5512, ..., size=4, ...) at softmmu/memory.c:492 + +Commit 584acf34cb0 ("ati-vga: Fix reverse bit blts") introduced +the local dst_x and dst_y which adjust the (x, y) coordinates +depending on the direction in the SRCCOPY ROP3 operation, but +forgot to address the same issue for the PATCOPY, BLACKNESS and +WHITENESS operations, which also call pixman_fill(). + +Fix that now by using the adjusted coordinates in the pixman_fill +call, and update the related debug printf(). +--- + hw/display/ati_2d.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/hw/display/ati_2d.c b/hw/display/ati_2d.c +index 4dc10ea7..692bec91 100644 +--- a/hw/display/ati_2d.c ++++ b/hw/display/ati_2d.c +@@ -84,7 +84,7 @@ void ati_2d_blt(ATIVGAState *s) + DPRINTF("%d %d %d, %d %d %d, (%d,%d) -> (%d,%d) %dx%d %c %c\n", + s->regs.src_offset, s->regs.dst_offset, s->regs.default_offset, + s->regs.src_pitch, s->regs.dst_pitch, s->regs.default_pitch, +- s->regs.src_x, s->regs.src_y, s->regs.dst_x, s->regs.dst_y, ++ s->regs.src_x, s->regs.src_y, dst_x, dst_y, + s->regs.dst_width, s->regs.dst_height, + (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ? '>' : '<'), + (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ? 'v' : '^')); +@@ -180,11 +180,11 @@ void ati_2d_blt(ATIVGAState *s) + dst_stride /= sizeof(uint32_t); + DPRINTF("pixman_fill(%p, %d, %d, %d, %d, %d, %d, %x)\n", + dst_bits, dst_stride, bpp, +- s->regs.dst_x, s->regs.dst_y, ++ dst_x, dst_y, + s->regs.dst_width, s->regs.dst_height, + filler); + pixman_fill((uint32_t *)dst_bits, dst_stride, bpp, +- s->regs.dst_x, s->regs.dst_y, ++ dst_x, dst_y, + s->regs.dst_width, s->regs.dst_height, + filler); + if (dst_bits >= s->vga.vram_ptr + s->vga.vbe_start_addr && +-- +2.25.1 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-3682.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-3682.patch new file mode 100644 index 0000000000..50a49233d3 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-3682.patch @@ -0,0 +1,41 @@ +From 5e796671e6b8d5de4b0b423dce1b3eba144a92c9 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann <kraxel@redhat.com> +Date: Thu, 22 Jul 2021 09:27:56 +0200 +Subject: [PATCH] usbredir: fix free call +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +data might point into the middle of a larger buffer, there is a separate +free_on_destroy pointer passed into bufp_alloc() to handle that. It is +only used in the normal workflow though, not when dropping packets due +to the queue being full. Fix that. + +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/491 +Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> +Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com> +Message-Id: <20210722072756.647673-1-kraxel@redhat.com> + +CVE: CVE-2021-3682 +Upstream-Status: Backport [5e796671e6b8d5de4b0b423dce1b3eba144a92c9] +Signed-off-by: Sakib Sajal <sakib.sajal@windriver.com> +--- + hw/usb/redirect.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index 4ec9326e05..1ec909a63a 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -476,7 +476,7 @@ static int bufp_alloc(USBRedirDevice *dev, uint8_t *data, uint16_t len, + if (dev->endpoint[EP2I(ep)].bufpq_dropping_packets) { + if (dev->endpoint[EP2I(ep)].bufpq_size > + dev->endpoint[EP2I(ep)].bufpq_target_size) { +- free(data); ++ free(free_on_destroy); + return -1; + } + dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0; +-- +2.25.1 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-3713.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-3713.patch new file mode 100644 index 0000000000..cdd9c38db9 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-3713.patch @@ -0,0 +1,67 @@ +From a114d6baedf2cccb454a46d36e399fec1bc3e1c0 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann <kraxel@redhat.com> +Date: Wed, 18 Aug 2021 14:05:05 +0200 +Subject: [PATCH] uas: add stream number sanity checks. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The device uses the guest-supplied stream number unchecked, which can +lead to guest-triggered out-of-band access to the UASDevice->data3 and +UASDevice->status3 fields. Add the missing checks. + +Fixes: CVE-2021-3713 +Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> +Reported-by: Chen Zhe <chenzhe@huawei.com> +Reported-by: Tan Jingguo <tanjingguo@huawei.com> +Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> +Message-Id: <20210818120505.1258262-2-kraxel@redhat.com> + +https://gitlab.com/qemu-project/qemu/-/commit/13b250b12ad3c59114a6a17d59caf073ce45b33a +CVE: CVE-2021-3713 +Upstream-Status: Backport +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> +--- + hw/usb/dev-uas.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c +index 6d6d1073..0b8cd4dd 100644 +--- a/hw/usb/dev-uas.c ++++ b/hw/usb/dev-uas.c +@@ -830,6 +830,9 @@ static void usb_uas_handle_data(USBDevice *dev, USBPacket *p) + } + break; + case UAS_PIPE_ID_STATUS: ++ if (p->stream > UAS_MAX_STREAMS) { ++ goto err_stream; ++ } + if (p->stream) { + QTAILQ_FOREACH(st, &uas->results, next) { + if (st->stream == p->stream) { +@@ -857,6 +860,9 @@ static void usb_uas_handle_data(USBDevice *dev, USBPacket *p) + break; + case UAS_PIPE_ID_DATA_IN: + case UAS_PIPE_ID_DATA_OUT: ++ if (p->stream > UAS_MAX_STREAMS) { ++ goto err_stream; ++ } + if (p->stream) { + req = usb_uas_find_request(uas, p->stream); + } else { +@@ -892,6 +898,11 @@ static void usb_uas_handle_data(USBDevice *dev, USBPacket *p) + p->status = USB_RET_STALL; + break; + } ++ ++err_stream: ++ error_report("%s: invalid stream %d", __func__, p->stream); ++ p->status = USB_RET_STALL; ++ return; + } + + static void usb_uas_unrealize(USBDevice *dev, Error **errp) diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-3748.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-3748.patch new file mode 100644 index 0000000000..b291ade4e3 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-3748.patch @@ -0,0 +1,124 @@ +From bedd7e93d01961fcb16a97ae45d93acf357e11f6 Mon Sep 17 00:00:00 2001 +From: Jason Wang <jasowang@redhat.com> +Date: Thu, 2 Sep 2021 13:44:12 +0800 +Subject: [PATCH] virtio-net: fix use after unmap/free for sg + +When mergeable buffer is enabled, we try to set the num_buffers after +the virtqueue elem has been unmapped. This will lead several issues, +E.g a use after free when the descriptor has an address which belongs +to the non direct access region. In this case we use bounce buffer +that is allocated during address_space_map() and freed during +address_space_unmap(). + +Fixing this by storing the elems temporarily in an array and delay the +unmap after we set the the num_buffers. + +This addresses CVE-2021-3748. + +Reported-by: Alexander Bulekov <alxndr@bu.edu> +Fixes: fbe78f4f55c6 ("virtio-net support") +Cc: qemu-stable@nongnu.org +Signed-off-by: Jason Wang <jasowang@redhat.com> + +https://github.com/qemu/qemu/commit/bedd7e93d01961fcb16a97ae45d93acf357e11f6 +CVE: CVE-2021-3748 +Upstream-Status: Backport +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> +--- + hw/net/virtio-net.c | 39 ++++++++++++++++++++++++++++++++------- + 1 file changed, 32 insertions(+), 7 deletions(-) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index 16d20cdee52a..f205331dcf8c 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -1746,10 +1746,13 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, + VirtIONet *n = qemu_get_nic_opaque(nc); + VirtIONetQueue *q = virtio_net_get_subqueue(nc); + VirtIODevice *vdev = VIRTIO_DEVICE(n); ++ VirtQueueElement *elems[VIRTQUEUE_MAX_SIZE]; ++ size_t lens[VIRTQUEUE_MAX_SIZE]; + struct iovec mhdr_sg[VIRTQUEUE_MAX_SIZE]; + struct virtio_net_hdr_mrg_rxbuf mhdr; + unsigned mhdr_cnt = 0; +- size_t offset, i, guest_offset; ++ size_t offset, i, guest_offset, j; ++ ssize_t err; + + if (!virtio_net_can_receive(nc)) { + return -1; +@@ -1780,6 +1783,12 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, + + total = 0; + ++ if (i == VIRTQUEUE_MAX_SIZE) { ++ virtio_error(vdev, "virtio-net unexpected long buffer chain"); ++ err = size; ++ goto err; ++ } ++ + elem = virtqueue_pop(q->rx_vq, sizeof(VirtQueueElement)); + if (!elem) { + if (i) { +@@ -1791,7 +1800,8 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, + n->guest_hdr_len, n->host_hdr_len, + vdev->guest_features); + } +- return -1; ++ err = -1; ++ goto err; + } + + if (elem->in_num < 1) { +@@ -1799,7 +1809,8 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, + "virtio-net receive queue contains no in buffers"); + virtqueue_detach_element(q->rx_vq, elem, 0); + g_free(elem); +- return -1; ++ err = -1; ++ goto err; + } + + sg = elem->in_sg; +@@ -1836,12 +1847,13 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, + if (!n->mergeable_rx_bufs && offset < size) { + virtqueue_unpop(q->rx_vq, elem, total); + g_free(elem); +- return size; ++ err = size; ++ goto err; + } + +- /* signal other side */ +- virtqueue_fill(q->rx_vq, elem, total, i++); +- g_free(elem); ++ elems[i] = elem; ++ lens[i] = total; ++ i++; + } + + if (mhdr_cnt) { +@@ -1851,10 +1863,23 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, + &mhdr.num_buffers, sizeof mhdr.num_buffers); + } + ++ for (j = 0; j < i; j++) { ++ /* signal other side */ ++ virtqueue_fill(q->rx_vq, elems[j], lens[j], j); ++ g_free(elems[j]); ++ } ++ + virtqueue_flush(q->rx_vq, i); + virtio_notify(vdev, q->rx_vq); + + return size; ++ ++err: ++ for (j = 0; j < i; j++) { ++ g_free(elems[j]); ++ } ++ ++ return err; + } + + static ssize_t virtio_net_do_receive(NetClientState *nc, const uint8_t *buf, diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-3750.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-3750.patch new file mode 100644 index 0000000000..43630e71fb --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-3750.patch @@ -0,0 +1,180 @@ +From 1938fbc7ec197e2612ab2ce36dd69bff19208aa5 Mon Sep 17 00:00:00 2001 +From: Hitendra Prajapati <hprajapati@mvista.com> +Date: Mon, 10 Oct 2022 17:44:41 +0530 +Subject: [PATCH] CVE-2021-3750 + +Upstream-Status: Backport [https://git.qemu.org/?p=qemu.git;a=commit;h=b9d383ab797f54ae5fa8746117770709921dc529 && https://git.qemu.org/?p=qemu.git;a=commit;h=3ab6fdc91b72e156da22848f0003ff4225690ced && https://git.qemu.org/?p=qemu.git;a=commit;h=58e74682baf4e1ad26b064d8c02e5bc99c75c5d9] +CVE: CVE-2021-3750 +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> +--- + exec.c | 55 +++++++++++++++++++++++++++++++------- + hw/intc/arm_gicv3_redist.c | 4 +-- + include/exec/memattrs.h | 9 +++++++ + 3 files changed, 56 insertions(+), 12 deletions(-) + +diff --git a/exec.c b/exec.c +index 1360051a..10581d8d 100644 +--- a/exec.c ++++ b/exec.c +@@ -39,6 +39,7 @@ + #include "qemu/config-file.h" + #include "qemu/error-report.h" + #include "qemu/qemu-print.h" ++#include "qemu/log.h" + #if defined(CONFIG_USER_ONLY) + #include "qemu.h" + #else /* !CONFIG_USER_ONLY */ +@@ -3118,6 +3119,33 @@ static bool prepare_mmio_access(MemoryRegion *mr) + return release_lock; + } + ++/** +++ * flatview_access_allowed +++ * @mr: #MemoryRegion to be accessed +++ * @attrs: memory transaction attributes +++ * @addr: address within that memory region +++ * @len: the number of bytes to access +++ * +++ * Check if a memory transaction is allowed. +++ * +++ * Returns: true if transaction is allowed, false if denied. +++ */ ++static bool flatview_access_allowed(MemoryRegion *mr, MemTxAttrs attrs, ++ hwaddr addr, hwaddr len) ++{ ++ if (likely(!attrs.memory)) { ++ return true; ++ } ++ if (memory_region_is_ram(mr)) { ++ return true; ++ } ++ qemu_log_mask(LOG_GUEST_ERROR, ++ "Invalid access to non-RAM device at " ++ "addr 0x%" HWADDR_PRIX ", size %" HWADDR_PRIu ", " ++ "region '%s'\n", addr, len, memory_region_name(mr)); ++ return false; ++} ++ + /* Called within RCU critical section. */ + static MemTxResult flatview_write_continue(FlatView *fv, hwaddr addr, + MemTxAttrs attrs, +@@ -3131,7 +3159,10 @@ static MemTxResult flatview_write_continue(FlatView *fv, hwaddr addr, + bool release_lock = false; + + for (;;) { +- if (!memory_access_is_direct(mr, true)) { ++ if (!flatview_access_allowed(mr, attrs, addr1, l)) { ++ result |= MEMTX_ACCESS_ERROR; ++ /* Keep going. */ ++ } else if (!memory_access_is_direct(mr, true)) { + release_lock |= prepare_mmio_access(mr); + l = memory_access_size(mr, l, addr1); + /* XXX: could force current_cpu to NULL to avoid +@@ -3173,14 +3204,14 @@ static MemTxResult flatview_write(FlatView *fv, hwaddr addr, MemTxAttrs attrs, + hwaddr l; + hwaddr addr1; + MemoryRegion *mr; +- MemTxResult result = MEMTX_OK; + + l = len; + mr = flatview_translate(fv, addr, &addr1, &l, true, attrs); +- result = flatview_write_continue(fv, addr, attrs, buf, len, +- addr1, l, mr); +- +- return result; ++ if (!flatview_access_allowed(mr, attrs, addr, len)) { ++ return MEMTX_ACCESS_ERROR; ++ } ++ return flatview_write_continue(fv, addr, attrs, buf, len, ++ addr1, l, mr); + } + + /* Called within RCU critical section. */ +@@ -3195,7 +3226,10 @@ MemTxResult flatview_read_continue(FlatView *fv, hwaddr addr, + bool release_lock = false; + + for (;;) { +- if (!memory_access_is_direct(mr, false)) { ++ if (!flatview_access_allowed(mr, attrs, addr1, l)) { ++ result |= MEMTX_ACCESS_ERROR; ++ /* Keep going. */ ++ } else if (!memory_access_is_direct(mr, false)) { + /* I/O case */ + release_lock |= prepare_mmio_access(mr); + l = memory_access_size(mr, l, addr1); +@@ -3238,6 +3272,9 @@ static MemTxResult flatview_read(FlatView *fv, hwaddr addr, + + l = len; + mr = flatview_translate(fv, addr, &addr1, &l, false, attrs); ++ if (!flatview_access_allowed(mr, attrs, addr, len)) { ++ return MEMTX_ACCESS_ERROR; ++ } + return flatview_read_continue(fv, addr, attrs, buf, len, + addr1, l, mr); + } +@@ -3474,12 +3511,10 @@ bool address_space_access_valid(AddressSpace *as, hwaddr addr, + MemTxAttrs attrs) + { + FlatView *fv; +- bool result; + + RCU_READ_LOCK_GUARD(); + fv = address_space_to_flatview(as); +- result = flatview_access_valid(fv, addr, len, is_write, attrs); +- return result; ++ return flatview_access_valid(fv, addr, len, is_write, attrs); + } + + static hwaddr +diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c +index 8645220d..44368e28 100644 +--- a/hw/intc/arm_gicv3_redist.c ++++ b/hw/intc/arm_gicv3_redist.c +@@ -450,7 +450,7 @@ MemTxResult gicv3_redist_read(void *opaque, hwaddr offset, uint64_t *data, + break; + } + +- if (r == MEMTX_ERROR) { ++ if (r != MEMTX_OK) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid guest read at offset " TARGET_FMT_plx + "size %u\n", __func__, offset, size); +@@ -507,7 +507,7 @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data, + break; + } + +- if (r == MEMTX_ERROR) { ++ if (r != MEMTX_OK) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid guest write at offset " TARGET_FMT_plx + "size %u\n", __func__, offset, size); +diff --git a/include/exec/memattrs.h b/include/exec/memattrs.h +index 95f2d20d..9fb98bc1 100644 +--- a/include/exec/memattrs.h ++++ b/include/exec/memattrs.h +@@ -35,6 +35,14 @@ typedef struct MemTxAttrs { + unsigned int secure:1; + /* Memory access is usermode (unprivileged) */ + unsigned int user:1; ++ /* ++ * Bus interconnect and peripherals can access anything (memories, ++ * devices) by default. By setting the 'memory' bit, bus transaction ++ * are restricted to "normal" memories (per the AMBA documentation) ++ * versus devices. Access to devices will be logged and rejected ++ * (see MEMTX_ACCESS_ERROR). ++ */ ++ unsigned int memory:1; + /* Requester ID (for MSI for example) */ + unsigned int requester_id:16; + /* Invert endianness for this page */ +@@ -66,6 +74,7 @@ typedef struct MemTxAttrs { + #define MEMTX_OK 0 + #define MEMTX_ERROR (1U << 0) /* device returned an error */ + #define MEMTX_DECODE_ERROR (1U << 1) /* nothing at that address */ ++#define MEMTX_ACCESS_ERROR (1U << 2) /* access denied */ + typedef uint32_t MemTxResult; + + #endif +-- +2.25.1 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-3929.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-3929.patch new file mode 100644 index 0000000000..a1862f1226 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-3929.patch @@ -0,0 +1,81 @@ +From 2c682b5975b41495f98cc34b8243042c446eec44 Mon Sep 17 00:00:00 2001 +From: Gaurav Gupta <gauragup@cisco.com> +Date: Wed, 29 Mar 2023 14:36:16 -0700 +Subject: [PATCH] hw/nvme: fix CVE-2021-3929 MIME-Version: 1.0 Content-Type: + text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This fixes CVE-2021-3929 "locally" by denying DMA to the iomem of the +device itself. This still allows DMA to MMIO regions of other devices +(e.g. doing P2P DMA to the controller memory buffer of another NVMe +device). + +Fixes: CVE-2021-3929 +Reported-by: Qiuhao Li <Qiuhao.Li@outlook.com> +Reviewed-by: Keith Busch <kbusch@kernel.org> +Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> +Signed-off-by: Klaus Jensen <k.jensen@samsung.com> + +Upstream-Status: Backport +[https://gitlab.com/qemu-project/qemu/-/commit/736b01642d85be832385] +CVE: CVE-2021-3929 +Signed-off-by: Vivek Kumbhar <vkumbhar@mvista.com> +Signed-off-by: Gaurav Gupta <gauragup@cisco.com> +--- + hw/block/nvme.c | 23 +++++++++++++++++++++++ + hw/block/nvme.h | 1 + + 2 files changed, 24 insertions(+) + +diff --git a/hw/block/nvme.c b/hw/block/nvme.c +index bda446d..ae9b19f 100644 +--- a/hw/block/nvme.c ++++ b/hw/block/nvme.c +@@ -60,8 +60,31 @@ static bool nvme_addr_is_cmb(NvmeCtrl *n, hwaddr addr) + return addr >= low && addr < hi; + } + ++static inline bool nvme_addr_is_iomem(NvmeCtrl *n, hwaddr addr) ++{ ++ hwaddr hi, lo; ++ ++ /* ++ * The purpose of this check is to guard against invalid "local" access to ++ * the iomem (i.e. controller registers). Thus, we check against the range ++ * covered by the 'bar0' MemoryRegion since that is currently composed of ++ * two subregions (the NVMe "MBAR" and the MSI-X table/pba). Note, however, ++ * that if the device model is ever changed to allow the CMB to be located ++ * in BAR0 as well, then this must be changed. ++ */ ++ lo = n->bar0.addr; ++ hi = lo + int128_get64(n->bar0.size); ++ ++ return addr >= lo && addr < hi; ++} ++ + static int nvme_addr_read(NvmeCtrl *n, hwaddr addr, void *buf, int size) + { ++ ++ if (nvme_addr_is_iomem(n, addr)) { ++ return NVME_DATA_TRAS_ERROR; ++ } ++ + if (n->cmbsz && nvme_addr_is_cmb(n, addr)) { + memcpy(buf, (void *)&n->cmbuf[addr - n->ctrl_mem.addr], size); + return 0; +diff --git a/hw/block/nvme.h b/hw/block/nvme.h +index 557194e..5a2b119 100644 +--- a/hw/block/nvme.h ++++ b/hw/block/nvme.h +@@ -59,6 +59,7 @@ typedef struct NvmeNamespace { + + typedef struct NvmeCtrl { + PCIDevice parent_obj; ++ MemoryRegion bar0; + MemoryRegion iomem; + MemoryRegion ctrl_mem; + NvmeBar bar; +-- +1.8.3.1 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-3930.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-3930.patch new file mode 100644 index 0000000000..b1b5558647 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-3930.patch @@ -0,0 +1,53 @@ +From b3af7fdf9cc537f8f0dd3e2423d83f5c99a457e8 Mon Sep 17 00:00:00 2001 +From: Mauro Matteo Cascella <mcascell@redhat.com> +Date: Thu, 4 Nov 2021 17:31:38 +0100 +Subject: [PATCH] hw/scsi/scsi-disk: MODE_PAGE_ALLS not allowed in MODE SELECT + commands + +This avoids an off-by-one read of 'mode_sense_valid' buffer in +hw/scsi/scsi-disk.c:mode_sense_page(). + +Fixes: CVE-2021-3930 +Cc: qemu-stable@nongnu.org +Reported-by: Alexander Bulekov <alxndr@bu.edu> +Fixes: a8f4bbe2900 ("scsi-disk: store valid mode pages in a table") +Fixes: #546 +Reported-by: Qiuhao Li <Qiuhao.Li@outlook.com> +Signed-off-by: Mauro Matteo Cascella <mcascell@redhat.com> +Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> + +https://gitlab.com/qemu-project/qemu/-/commit/b3af7fdf9cc537f8f0dd3e2423d83f5c99a457e8 +CVE: CVE-2021-3930 +Upstream-Status: Backport +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> +--- + hw/scsi/scsi-disk.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c +index e8a547dbb7..d4914178ea 100644 +--- a/hw/scsi/scsi-disk.c ++++ b/hw/scsi/scsi-disk.c +@@ -1087,6 +1087,7 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf, + uint8_t *p = *p_outbuf + 2; + int length; + ++ assert(page < ARRAY_SIZE(mode_sense_valid)); + if ((mode_sense_valid[page] & (1 << s->qdev.type)) == 0) { + return -1; + } +@@ -1428,6 +1429,11 @@ static int scsi_disk_check_mode_select(SCSIDiskState *s, int page, + return -1; + } + ++ /* MODE_PAGE_ALLS is only valid for MODE SENSE commands */ ++ if (page == MODE_PAGE_ALLS) { ++ return -1; ++ } ++ + p = mode_current; + memset(mode_current, 0, inlen + 2); + len = mode_sense_page(s, page, &p, 0); +-- +GitLab + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-4206.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-4206.patch new file mode 100644 index 0000000000..80ad49e4ed --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-4206.patch @@ -0,0 +1,89 @@ +From fa892e9abb728e76afcf27323ab29c57fb0fe7aa Mon Sep 17 00:00:00 2001 +From: Mauro Matteo Cascella <mcascell@redhat.com> +Date: Thu, 7 Apr 2022 10:17:12 +0200 +Subject: [PATCH] ui/cursor: fix integer overflow in cursor_alloc + (CVE-2021-4206) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Prevent potential integer overflow by limiting 'width' and 'height' to +512x512. Also change 'datasize' type to size_t. Refer to security +advisory https://starlabs.sg/advisories/22-4206/ for more information. + +Fixes: CVE-2021-4206 +Signed-off-by: Mauro Matteo Cascella <mcascell@redhat.com> +Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com> +Message-Id: <20220407081712.345609-1-mcascell@redhat.com> +Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> + +https://gitlab.com/qemu-project/qemu/-/commit/fa892e9a +CVE: CVE-2021-4206 +Upstream-Status: Backport +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> +--- + hw/display/qxl-render.c | 7 +++++++ + hw/display/vmware_vga.c | 2 ++ + ui/cursor.c | 8 +++++++- + 3 files changed, 16 insertions(+), 1 deletion(-) + +diff --git a/hw/display/qxl-render.c b/hw/display/qxl-render.c +index 237ed293ba..ca217004bf 100644 +--- a/hw/display/qxl-render.c ++++ b/hw/display/qxl-render.c +@@ -247,6 +247,13 @@ static QEMUCursor *qxl_cursor(PCIQXLDevice *qxl, QXLCursor *cursor, + size_t size; + + c = cursor_alloc(cursor->header.width, cursor->header.height); ++ ++ if (!c) { ++ qxl_set_guest_bug(qxl, "%s: cursor %ux%u alloc error", __func__, ++ cursor->header.width, cursor->header.height); ++ goto fail; ++ } ++ + c->hot_x = cursor->header.hot_spot_x; + c->hot_y = cursor->header.hot_spot_y; + switch (cursor->header.type) { +diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c +index 98c83474ad..45d06cbe25 100644 +--- a/hw/display/vmware_vga.c ++++ b/hw/display/vmware_vga.c +@@ -515,6 +515,8 @@ static inline void vmsvga_cursor_define(struct vmsvga_state_s *s, + int i, pixels; + + qc = cursor_alloc(c->width, c->height); ++ assert(qc != NULL); ++ + qc->hot_x = c->hot_x; + qc->hot_y = c->hot_y; + switch (c->bpp) { +diff --git a/ui/cursor.c b/ui/cursor.c +index 1d62ddd4d0..835f0802f9 100644 +--- a/ui/cursor.c ++++ b/ui/cursor.c +@@ -46,6 +46,8 @@ static QEMUCursor *cursor_parse_xpm(const char *xpm[]) + + /* parse pixel data */ + c = cursor_alloc(width, height); ++ assert(c != NULL); ++ + for (pixel = 0, y = 0; y < height; y++, line++) { + for (x = 0; x < height; x++, pixel++) { + idx = xpm[line][x]; +@@ -91,7 +93,11 @@ QEMUCursor *cursor_builtin_left_ptr(void) + QEMUCursor *cursor_alloc(int width, int height) + { + QEMUCursor *c; +- int datasize = width * height * sizeof(uint32_t); ++ size_t datasize = width * height * sizeof(uint32_t); ++ ++ if (width > 512 || height > 512) { ++ return NULL; ++ } + + c = g_malloc0(sizeof(QEMUCursor) + datasize); + c->width = width; +-- +GitLab + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2021-4207.patch b/meta/recipes-devtools/qemu/qemu/CVE-2021-4207.patch new file mode 100644 index 0000000000..8418246247 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2021-4207.patch @@ -0,0 +1,43 @@ +From 9569f5cb5b4bffa9d3ebc8ba7da1e03830a9a895 Mon Sep 17 00:00:00 2001 +From: Mauro Matteo Cascella <mcascell@redhat.com> +Date: Thu, 7 Apr 2022 10:11:06 +0200 +Subject: [PATCH] display/qxl-render: fix race condition in qxl_cursor + (CVE-2021-4207) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Avoid fetching 'width' and 'height' a second time to prevent possible +race condition. Refer to security advisory +https://starlabs.sg/advisories/22-4207/ for more information. + +Fixes: CVE-2021-4207 +Signed-off-by: Mauro Matteo Cascella <mcascell@redhat.com> +Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com> +Message-Id: <20220407081106.343235-1-mcascell@redhat.com> +Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> + +https://gitlab.com/qemu-project/qemu/-/commit/9569f5cb +CVE: CVE-2021-4207 +Upstream-Status: Backport +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> +--- + hw/display/qxl-render.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/display/qxl-render.c b/hw/display/qxl-render.c +index d28849b121..237ed293ba 100644 +--- a/hw/display/qxl-render.c ++++ b/hw/display/qxl-render.c +@@ -266,7 +266,7 @@ static QEMUCursor *qxl_cursor(PCIQXLDevice *qxl, QXLCursor *cursor, + } + break; + case SPICE_CURSOR_TYPE_ALPHA: +- size = sizeof(uint32_t) * cursor->header.width * cursor->header.height; ++ size = sizeof(uint32_t) * c->width * c->height; + qxl_unpack_chunks(c->data, size, qxl, &cursor->chunk, group_id); + if (qxl->debug > 2) { + cursor_print_ascii_art(c, "qxl/alpha"); +-- +GitLab + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2022-0216-1.patch b/meta/recipes-devtools/qemu/qemu/CVE-2022-0216-1.patch new file mode 100644 index 0000000000..6a7ce0e26c --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2022-0216-1.patch @@ -0,0 +1,42 @@ +From 6c8fa961da5e60f574bb52fd3ad44b1e9e8ad4b8 Mon Sep 17 00:00:00 2001 +From: Mauro Matteo Cascella <mcascell@redhat.com> +Date: Tue, 5 Jul 2022 22:05:43 +0200 +Subject: [PATCH] scsi/lsi53c895a: fix use-after-free in lsi_do_msgout + (CVE-2022-0216) + +Set current_req->req to NULL to prevent reusing a free'd buffer in case of +repeated SCSI cancel requests. Thanks to Thomas Huth for suggesting the patch. + +Fixes: CVE-2022-0216 +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/972 +Signed-off-by: Mauro Matteo Cascella <mcascell@redhat.com> +Reviewed-by: Thomas Huth <thuth@redhat.com> +Message-Id: <20220705200543.2366809-1-mcascell@redhat.com> +Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> + +https://gitlab.com/qemu-project/qemu/-/commit/6c8fa961da5e60f574bb52fd3ad44b1e9e8ad4b8 +CVE: CVE-2022-0216 +Upstream-Status: Backport +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> +--- + hw/scsi/lsi53c895a.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c +index c8773f73f7..99ea42d49b 100644 +--- a/hw/scsi/lsi53c895a.c ++++ b/hw/scsi/lsi53c895a.c +@@ -1028,8 +1028,9 @@ static void lsi_do_msgout(LSIState *s) + case 0x0d: + /* The ABORT TAG message clears the current I/O process only. */ + trace_lsi_do_msgout_abort(current_tag); +- if (current_req) { ++ if (current_req && current_req->req) { + scsi_req_cancel(current_req->req); ++ current_req->req = NULL; + } + lsi_disconnect(s); + break; +-- +GitLab + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2022-0216-2.patch b/meta/recipes-devtools/qemu/qemu/CVE-2022-0216-2.patch new file mode 100644 index 0000000000..137906cd30 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2022-0216-2.patch @@ -0,0 +1,52 @@ +From 4367a20cc442c56b05611b4224de9a61908f9eac Mon Sep 17 00:00:00 2001 +From: Mauro Matteo Cascella <mcascell@redhat.com> +Date: Mon, 11 Jul 2022 14:33:16 +0200 +Subject: [PATCH] scsi/lsi53c895a: really fix use-after-free in lsi_do_msgout + (CVE-2022-0216) + +Set current_req to NULL, not current_req->req, to prevent reusing a free'd +buffer in case of repeated SCSI cancel requests. Also apply the fix to +CLEAR QUEUE and BUS DEVICE RESET messages as well, since they also cancel +the request. + +Thanks to Alexander Bulekov for providing a reproducer. + +Fixes: CVE-2022-0216 +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/972 +Signed-off-by: Mauro Matteo Cascella <mcascell@redhat.com> +Tested-by: Alexander Bulekov <alxndr@bu.edu> +Message-Id: <20220711123316.421279-1-mcascell@redhat.com> +Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> + +https://gitlab.com/qemu-project/qemu/-/commit/4367a20cc4 +CVE: CVE-2022-0216 +Upstream-Status: Backport +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> +--- + hw/scsi/lsi53c895a.c | 3 +- + 1 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c +index 99ea42d49b..ad5f5e5f39 100644 +--- a/hw/scsi/lsi53c895a.c ++++ b/hw/scsi/lsi53c895a.c +@@ -1030,7 +1030,7 @@ static void lsi_do_msgout(LSIState *s) + trace_lsi_do_msgout_abort(current_tag); + if (current_req && current_req->req) { + scsi_req_cancel(current_req->req); +- current_req->req = NULL; ++ current_req = NULL; + } + lsi_disconnect(s); + break; +@@ -1056,6 +1056,7 @@ static void lsi_do_msgout(LSIState *s) + /* clear the current I/O process */ + if (s->current) { + scsi_req_cancel(s->current->req); ++ current_req = NULL; + } + + /* As the current implemented devices scsi_disk and scsi_generic +-- +GitLab + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2022-26354.patch b/meta/recipes-devtools/qemu/qemu/CVE-2022-26354.patch new file mode 100644 index 0000000000..fc4d6cf3df --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2022-26354.patch @@ -0,0 +1,57 @@ +Backport of: + +From 8d1b247f3748ac4078524130c6d7ae42b6140aaf Mon Sep 17 00:00:00 2001 +From: Stefano Garzarella <sgarzare@redhat.com> +Date: Mon, 28 Feb 2022 10:50:58 +0100 +Subject: [PATCH] vhost-vsock: detach the virqueue element in case of error + +In vhost_vsock_common_send_transport_reset(), if an element popped from +the virtqueue is invalid, we should call virtqueue_detach_element() to +detach it from the virtqueue before freeing its memory. + +Fixes: fc0b9b0e1c ("vhost-vsock: add virtio sockets device") +Fixes: CVE-2022-26354 +Cc: qemu-stable@nongnu.org +Reported-by: VictorV <vv474172261@gmail.com> +Signed-off-by: Stefano Garzarella <sgarzare@redhat.com> +Message-Id: <20220228095058.27899-1-sgarzare@redhat.com> +Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> +Reviewed-by: Michael S. Tsirkin <mst@redhat.com> +Signed-off-by: Michael S. Tsirkin <mst@redhat.com> + +CVE: CVE-2022-26354 +Upstream-Status: Backport [import from ubuntu https://git.launchpad.net/ubuntu/+source/qemu/tree/debian/patches/CVE-2022-26354.patch?h=ubuntu/focal-security Upstream commit https://github.com/qemu/qemu/commit/8d1b247f3748ac4078524130c6d7ae42b6140aaf ] +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> +--- + hw/virtio/vhost-vsock-common.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +--- a/hw/virtio/vhost-vsock.c ++++ b/hw/virtio/vhost-vsock.c +@@ -221,19 +221,23 @@ static void vhost_vsock_send_transport_r + if (elem->out_num) { + error_report("invalid vhost-vsock event virtqueue element with " + "out buffers"); +- goto out; ++ goto err; + } + + if (iov_from_buf(elem->in_sg, elem->in_num, 0, + &event, sizeof(event)) != sizeof(event)) { + error_report("vhost-vsock event virtqueue element is too short"); +- goto out; ++ goto err; + } + + virtqueue_push(vq, elem, sizeof(event)); + virtio_notify(VIRTIO_DEVICE(vsock), vq); + +-out: ++ g_free(elem); ++ return; ++ ++err: ++ virtqueue_detach_element(vq, elem, 0); + g_free(elem); + } + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2022-35414.patch b/meta/recipes-devtools/qemu/qemu/CVE-2022-35414.patch new file mode 100644 index 0000000000..4196ebcf98 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2022-35414.patch @@ -0,0 +1,53 @@ +From 09a07b5b39c87423df9e8f6574c19a14d36beac5 Mon Sep 17 00:00:00 2001 +From: Hitendra Prajapati <hprajapati@mvista.com> +Date: Wed, 27 Jul 2022 10:34:12 +0530 +Subject: [PATCH] CVE-2022-35414 + +Upstream-Status: Backport [https://github.com/qemu/qemu/commit/418ade7849ce7641c0f7333718caf5091a02fd4c] +CVE: CVE-2022-35414 +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> +--- + exec.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/exec.c b/exec.c +index 43c70ffb..2d6add46 100644 +--- a/exec.c ++++ b/exec.c +@@ -685,7 +685,7 @@ static void tcg_iommu_free_notifier_list(CPUState *cpu) + + /* Called from RCU critical section */ + MemoryRegionSection * +-address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr addr, ++address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr orig_addr, + hwaddr *xlat, hwaddr *plen, + MemTxAttrs attrs, int *prot) + { +@@ -694,6 +694,7 @@ address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr addr, + IOMMUMemoryRegionClass *imrc; + IOMMUTLBEntry iotlb; + int iommu_idx; ++ hwaddr addr = orig_addr; + AddressSpaceDispatch *d = atomic_rcu_read(&cpu->cpu_ases[asidx].memory_dispatch); + + for (;;) { +@@ -737,6 +738,16 @@ address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr addr, + return section; + + translate_fail: ++ /* ++ * We should be given a page-aligned address -- certainly ++ * tlb_set_page_with_attrs() does so. The page offset of xlat ++ * is used to index sections[], and PHYS_SECTION_UNASSIGNED = 0. ++ * The page portion of xlat will be logged by memory_region_access_valid() ++ * when this memory access is rejected, so use the original untranslated ++ * physical address. ++ */ ++ assert((orig_addr & ~TARGET_PAGE_MASK) == 0); ++ *xlat = orig_addr; + return &d->map.sections[PHYS_SECTION_UNASSIGNED]; + } + #endif +-- +2.25.1 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2022-4144.patch b/meta/recipes-devtools/qemu/qemu/CVE-2022-4144.patch new file mode 100644 index 0000000000..3f0d5fbd5c --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2022-4144.patch @@ -0,0 +1,103 @@ +From 6dbbf055148c6f1b7d8a3251a65bd6f3d1e1f622 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= <philmd@linaro.org> +Date: Mon, 28 Nov 2022 21:27:40 +0100 +Subject: [PATCH] hw/display/qxl: Avoid buffer overrun in qxl_phys2virt + (CVE-2022-4144) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Have qxl_get_check_slot_offset() return false if the requested +buffer size does not fit within the slot memory region. + +Similarly qxl_phys2virt() now returns NULL in such case, and +qxl_dirty_one_surface() aborts. + +This avoids buffer overrun in the host pointer returned by +memory_region_get_ram_ptr(). + +Fixes: CVE-2022-4144 (out-of-bounds read) +Reported-by: Wenxu Yin (@awxylitol) +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1336 + +Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> +Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> +Message-Id: <20221128202741.4945-5-philmd@linaro.org> + +Upstream-Status: Backport [https://gitlab.com/qemu-project/qemu/-/commit/6dbbf055148c6f1b7d8a3251a65bd6f3d1e1f622] +CVE: CVE-2022-4144 +Comments: Deleted patch hunk in qxl.h,as it contains change +in comments which is not present in current version of qemu. + +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> +--- + hw/display/qxl.c | 27 +++++++++++++++++++++++---- + 1 file changed, 23 insertions(+), 4 deletions(-) + +diff --git a/hw/display/qxl.c b/hw/display/qxl.c +index cd7eb39d..6bc8385b 100644 +--- a/hw/display/qxl.c ++++ b/hw/display/qxl.c +@@ -1440,11 +1440,13 @@ static void qxl_reset_surfaces(PCIQXLDevice *d) + + /* can be also called from spice server thread context */ + static bool qxl_get_check_slot_offset(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, +- uint32_t *s, uint64_t *o) ++ uint32_t *s, uint64_t *o, ++ size_t size_requested) + { + uint64_t phys = le64_to_cpu(pqxl); + uint32_t slot = (phys >> (64 - 8)) & 0xff; + uint64_t offset = phys & 0xffffffffffff; ++ uint64_t size_available; + + if (slot >= NUM_MEMSLOTS) { + qxl_set_guest_bug(qxl, "slot too large %d >= %d", slot, +@@ -1468,6 +1470,23 @@ static bool qxl_get_check_slot_offset(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, + slot, offset, qxl->guest_slots[slot].size); + return false; + } ++ size_available = memory_region_size(qxl->guest_slots[slot].mr); ++ if (qxl->guest_slots[slot].offset + offset >= size_available) { ++ qxl_set_guest_bug(qxl, ++ "slot %d offset %"PRIu64" > region size %"PRIu64"\n", ++ slot, qxl->guest_slots[slot].offset + offset, ++ size_available); ++ return false; ++ } ++ size_available -= qxl->guest_slots[slot].offset + offset; ++ if (size_requested > size_available) { ++ qxl_set_guest_bug(qxl, ++ "slot %d offset %"PRIu64" size %zu: " ++ "overrun by %"PRIu64" bytes\n", ++ slot, offset, size_requested, ++ size_requested - size_available); ++ return false; ++ } + + *s = slot; + *o = offset; +@@ -1486,7 +1505,7 @@ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id) + offset = le64_to_cpu(pqxl) & 0xffffffffffff; + return (void *)(intptr_t)offset; + case MEMSLOT_GROUP_GUEST: +- if (!qxl_get_check_slot_offset(qxl, pqxl, &slot, &offset)) { ++ if (!qxl_get_check_slot_offset(qxl, pqxl, &slot, &offset, size)) { + return NULL; + } + ptr = memory_region_get_ram_ptr(qxl->guest_slots[slot].mr); +@@ -1944,9 +1963,9 @@ static void qxl_dirty_one_surface(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, + uint32_t slot; + bool rc; + +- rc = qxl_get_check_slot_offset(qxl, pqxl, &slot, &offset); +- assert(rc == true); + size = (uint64_t)height * abs(stride); ++ rc = qxl_get_check_slot_offset(qxl, pqxl, &slot, &offset, size); ++ assert(rc == true); + trace_qxl_surfaces_dirty(qxl->id, offset, size); + qxl_set_dirty(qxl->guest_slots[slot].mr, + qxl->guest_slots[slot].offset + offset, +-- +2.25.1 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2023-0330.patch b/meta/recipes-devtools/qemu/qemu/CVE-2023-0330.patch new file mode 100644 index 0000000000..26e22b4c31 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2023-0330.patch @@ -0,0 +1,77 @@ +[Ubuntu note: remove fuzz-lsi53c895a-test.c changes since the file does not + exist for this release] +From b987718bbb1d0eabf95499b976212dd5f0120d75 Mon Sep 17 00:00:00 2001 +From: Thomas Huth <thuth@redhat.com> +Date: Mon, 22 May 2023 11:10:11 +0200 +Subject: [PATCH] hw/scsi/lsi53c895a: Fix reentrancy issues in the LSI + controller (CVE-2023-0330) + +We cannot use the generic reentrancy guard in the LSI code, so +we have to manually prevent endless reentrancy here. The problematic +lsi_execute_script() function has already a way to detect whether +too many instructions have been executed - we just have to slightly +change the logic here that it also takes into account if the function +has been called too often in a reentrant way. + +The code in fuzz-lsi53c895a-test.c has been taken from an earlier +patch by Mauro Matteo Cascella. + +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1563 +Message-Id: <20230522091011.1082574-1-thuth@redhat.com> +Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> +Reviewed-by: Alexander Bulekov <alxndr@bu.edu> +Signed-off-by: Thomas Huth <thuth@redhat.com> + +Reference: https://launchpad.net/ubuntu/+source/qemu/1:4.2-3ubuntu6.27 + +Upstream-Status: Backport [import from ubuntu https://git.launchpad.net/ubuntu/+source/qemu/tree/debian/patches/CVE-2023-0330.patch?h=ubuntu/focal-security +Upstream commit https://gitlab.com/qemu-project/qemu/-/commit/b987718bbb1d0eabf95499b976212dd5f0120d75] +CVE: CVE-2023-0330 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + hw/scsi/lsi53c895a.c | 23 +++++++++++++++------ + tests/qtest/fuzz-lsi53c895a-test.c | 33 ++++++++++++++++++++++++++++++ + 2 files changed, 50 insertions(+), 6 deletions(-) + +--- qemu-4.2.orig/hw/scsi/lsi53c895a.c ++++ qemu-4.2/hw/scsi/lsi53c895a.c +@@ -1135,15 +1135,24 @@ static void lsi_execute_script(LSIState + uint32_t addr, addr_high; + int opcode; + int insn_processed = 0; ++ static int reentrancy_level; ++ ++ reentrancy_level++; + + s->istat1 |= LSI_ISTAT1_SRUN; + again: +- if (++insn_processed > LSI_MAX_INSN) { +- /* Some windows drivers make the device spin waiting for a memory +- location to change. If we have been executed a lot of code then +- assume this is the case and force an unexpected device disconnect. +- This is apparently sufficient to beat the drivers into submission. +- */ ++ /* ++ * Some windows drivers make the device spin waiting for a memory location ++ * to change. If we have executed more than LSI_MAX_INSN instructions then ++ * assume this is the case and force an unexpected device disconnect. This ++ * is apparently sufficient to beat the drivers into submission. ++ * ++ * Another issue (CVE-2023-0330) can occur if the script is programmed to ++ * trigger itself again and again. Avoid this problem by stopping after ++ * being called multiple times in a reentrant way (8 is an arbitrary value ++ * which should be enough for all valid use cases). ++ */ ++ if (++insn_processed > LSI_MAX_INSN || reentrancy_level > 8) { + if (!(s->sien0 & LSI_SIST0_UDC)) { + qemu_log_mask(LOG_GUEST_ERROR, + "lsi_scsi: inf. loop with UDC masked"); +@@ -1597,6 +1606,8 @@ again: + } + } + trace_lsi_execute_script_stop(); ++ ++ reentrancy_level--; + } + + static uint8_t lsi_reg_readb(LSIState *s, int offset) diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2023-2861.patch b/meta/recipes-devtools/qemu/qemu/CVE-2023-2861.patch new file mode 100644 index 0000000000..70b7d6c562 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2023-2861.patch @@ -0,0 +1,178 @@ +From f6b0de53fb87ddefed348a39284c8e2f28dc4eda Mon Sep 17 00:00:00 2001 +From: Christian Schoenebeck <qemu_oss@crudebyte.com> +Date: Wed, 7 Jun 2023 18:29:33 +0200 +Subject: [PATCH] 9pfs: prevent opening special files (CVE-2023-2861) + +The 9p protocol does not specifically define how server shall behave when +client tries to open a special file, however from security POV it does +make sense for 9p server to prohibit opening any special file on host side +in general. A sane Linux 9p client for instance would never attempt to +open a special file on host side, it would always handle those exclusively +on its guest side. A malicious client however could potentially escape +from the exported 9p tree by creating and opening a device file on host +side. + +With QEMU this could only be exploited in the following unsafe setups: + + - Running QEMU binary as root AND 9p 'local' fs driver AND 'passthrough' + security model. + +or + + - Using 9p 'proxy' fs driver (which is running its helper daemon as + root). + +These setups were already discouraged for safety reasons before, +however for obvious reasons we are now tightening behaviour on this. + +Fixes: CVE-2023-2861 +Reported-by: Yanwu Shen <ywsPlz@gmail.com> +Reported-by: Jietao Xiao <shawtao1125@gmail.com> +Reported-by: Jinku Li <jkli@xidian.edu.cn> +Reported-by: Wenbo Shen <shenwenbo@zju.edu.cn> +Signed-off-by: Christian Schoenebeck <qemu_oss@crudebyte.com> +Reviewed-by: Greg Kurz <groug@kaod.org> +Reviewed-by: Michael Tokarev <mjt@tls.msk.ru> +Message-Id: <E1q6w7r-0000Q0-NM@lizzy.crudebyte.com> + +Upstream-Status: Backport [https://gitlab.com/qemu-project/qemu/-/commit/f6b0de53fb87ddefed348a39284c8e2f28dc4eda] +CVE: CVE-2023-2861 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + fsdev/virtfs-proxy-helper.c | 27 +++++++++++++++++++++++-- + hw/9pfs/9p-util.h | 40 +++++++++++++++++++++++++++++++++++++ + 2 files changed, 65 insertions(+), 2 deletions(-) + +diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c +index 6f132c5f..300c9765 100644 +--- a/fsdev/virtfs-proxy-helper.c ++++ b/fsdev/virtfs-proxy-helper.c +@@ -26,6 +26,7 @@ + #include "qemu/xattr.h" + #include "9p-iov-marshal.h" + #include "hw/9pfs/9p-proxy.h" ++#include "hw/9pfs/9p-util.h" + #include "fsdev/9p-iov-marshal.h" + + #define PROGNAME "virtfs-proxy-helper" +@@ -350,6 +351,28 @@ static void resetugid(int suid, int sgid) + } + } + ++/* ++ * Open regular file or directory. Attempts to open any special file are ++ * rejected. ++ * ++ * returns file descriptor or -1 on error ++ */ ++static int open_regular(const char *pathname, int flags, mode_t mode) ++{ ++ int fd; ++ ++ fd = open(pathname, flags, mode); ++ if (fd < 0) { ++ return fd; ++ } ++ ++ if (close_if_special_file(fd) < 0) { ++ return -1; ++ } ++ ++ return fd; ++} ++ + /* + * send response in two parts + * 1) ProxyHeader +@@ -694,7 +717,7 @@ static int do_create(struct iovec *iovec) + if (ret < 0) { + goto unmarshal_err_out; + } +- ret = open(path.data, flags, mode); ++ ret = open_regular(path.data, flags, mode); + if (ret < 0) { + ret = -errno; + } +@@ -719,7 +742,7 @@ static int do_open(struct iovec *iovec) + if (ret < 0) { + goto err_out; + } +- ret = open(path.data, flags); ++ ret = open_regular(path.data, flags, 0); + if (ret < 0) { + ret = -errno; + } +diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h +index 546f46dc..79fdd2a3 100644 +--- a/hw/9pfs/9p-util.h ++++ b/hw/9pfs/9p-util.h +@@ -13,12 +13,16 @@ + #ifndef QEMU_9P_UTIL_H + #define QEMU_9P_UTIL_H + ++#include "qemu/error-report.h" ++ + #ifdef O_PATH + #define O_PATH_9P_UTIL O_PATH + #else + #define O_PATH_9P_UTIL 0 + #endif + ++#define qemu_fstat fstat ++ + static inline void close_preserve_errno(int fd) + { + int serrno = errno; +@@ -26,6 +30,38 @@ static inline void close_preserve_errno(int fd) + errno = serrno; + } + ++/** ++ * close_if_special_file() - Close @fd if neither regular file nor directory. ++ * ++ * @fd: file descriptor of open file ++ * Return: 0 on regular file or directory, -1 otherwise ++ * ++ * CVE-2023-2861: Prohibit opening any special file directly on host ++ * (especially device files), as a compromised client could potentially gain ++ * access outside exported tree under certain, unsafe setups. We expect ++ * client to handle I/O on special files exclusively on guest side. ++ */ ++static inline int close_if_special_file(int fd) ++{ ++ struct stat stbuf; ++ ++ if (qemu_fstat(fd, &stbuf) < 0) { ++ close_preserve_errno(fd); ++ return -1; ++ } ++ if (!S_ISREG(stbuf.st_mode) && !S_ISDIR(stbuf.st_mode)) { ++ error_report_once( ++ "9p: broken or compromised client detected; attempt to open " ++ "special file (i.e. neither regular file, nor directory)" ++ ); ++ close(fd); ++ errno = ENXIO; ++ return -1; ++ } ++ ++ return 0; ++} ++ + static inline int openat_dir(int dirfd, const char *name) + { + return openat(dirfd, name, +@@ -56,6 +92,10 @@ again: + return -1; + } + ++ if (close_if_special_file(fd) < 0) { ++ return -1; ++ } ++ + serrno = errno; + /* O_NONBLOCK was only needed to open the file. Let's drop it. We don't + * do that with O_PATH since fcntl(F_SETFL) isn't supported, and openat() +-- +2.25.1 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2023-3180.patch b/meta/recipes-devtools/qemu/qemu/CVE-2023-3180.patch new file mode 100644 index 0000000000..7144bdca46 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2023-3180.patch @@ -0,0 +1,49 @@ +From 9d38a8434721a6479fe03fb5afb150ca793d3980 Mon Sep 17 00:00:00 2001 +From: zhenwei pi <pizhenwei@bytedance.com> +Date: Thu, 3 Aug 2023 10:43:13 +0800 +Subject: [PATCH] virtio-crypto: verify src&dst buffer length for sym request + +For symmetric algorithms, the length of ciphertext must be as same +as the plaintext. +The missing verification of the src_len and the dst_len in +virtio_crypto_sym_op_helper() may lead buffer overflow/divulged. + +This patch is originally written by Yiming Tao for QEMU-SECURITY, +resend it(a few changes of error message) in qemu-devel. + +Fixes: CVE-2023-3180 +Fixes: 04b9b37edda("virtio-crypto: add data queue processing handler") +Cc: Gonglei <arei.gonglei@huawei.com> +Cc: Mauro Matteo Cascella <mcascell@redhat.com> +Cc: Yiming Tao <taoym@zju.edu.cn> +Signed-off-by: zhenwei pi <pizhenwei@bytedance.com> +Message-Id: <20230803024314.29962-2-pizhenwei@bytedance.com> +Reviewed-by: Michael S. Tsirkin <mst@redhat.com> +Signed-off-by: Michael S. Tsirkin <mst@redhat.com> + +Upstream-Status: Backport from [https://gitlab.com/qemu-project/qemu/-/commit/9d38a8434721a6479fe03fb5afb150ca793d3980] +CVE: CVE-2023-3180 +Signed-off-by: Ashish Sharma <asharma@mvista.com> + + hw/virtio/virtio-crypto.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c +index 44faf5a522b..13aec771e11 100644 +--- a/hw/virtio/virtio-crypto.c ++++ b/hw/virtio/virtio-crypto.c +@@ -634,6 +634,11 @@ virtio_crypto_sym_op_helper(VirtIODevice *vdev, + return NULL; + } + ++ if (unlikely(src_len != dst_len)) { ++ virtio_error(vdev, "sym request src len is different from dst len"); ++ return NULL; ++ } ++ + max_len = (uint64_t)iv_len + aad_len + src_len + dst_len + hash_result_len; + if (unlikely(max_len > vcrypto->conf.max_size)) { + virtio_error(vdev, "virtio-crypto too big length"); +-- +GitLab + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2023-3354.patch b/meta/recipes-devtools/qemu/qemu/CVE-2023-3354.patch new file mode 100644 index 0000000000..2942e84cac --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2023-3354.patch @@ -0,0 +1,87 @@ +From 10be627d2b5ec2d6b3dce045144aa739eef678b4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com> +Date: Tue, 20 Jun 2023 09:45:34 +0100 +Subject: [PATCH] io: remove io watch if TLS channel is closed during handshake +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The TLS handshake make take some time to complete, during which time an +I/O watch might be registered with the main loop. If the owner of the +I/O channel invokes qio_channel_close() while the handshake is waiting +to continue the I/O watch must be removed. Failing to remove it will +later trigger the completion callback which the owner is not expecting +to receive. In the case of the VNC server, this results in a SEGV as +vnc_disconnect_start() tries to shutdown a client connection that is +already gone / NULL. + +CVE-2023-3354 +Reported-by: jiangyegen <jiangyegen@huawei.com> +Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> + +Upstream-Status: Backport [https://gitlab.com/qemu-project/qemu/-/commit/10be627d2b5ec2d6b3dce045144aa739eef678b4] +CVE: CVE-2023-3354 +Signed-off-by: Vivek Kumbhar <vkumbhar@mvista.com> +--- + include/io/channel-tls.h | 1 + + io/channel-tls.c | 18 ++++++++++++------ + 2 files changed, 13 insertions(+), 6 deletions(-) + +diff --git a/include/io/channel-tls.h b/include/io/channel-tls.h +index fdbdf12f..e49e2831 100644 +--- a/include/io/channel-tls.h ++++ b/include/io/channel-tls.h +@@ -49,6 +49,7 @@ struct QIOChannelTLS { + QIOChannel *master; + QCryptoTLSSession *session; + QIOChannelShutdown shutdown; ++ guint hs_ioc_tag; + }; + + /** +diff --git a/io/channel-tls.c b/io/channel-tls.c +index 7ec8ceff..8b32fbde 100644 +--- a/io/channel-tls.c ++++ b/io/channel-tls.c +@@ -194,12 +194,13 @@ static void qio_channel_tls_handshake_task(QIOChannelTLS *ioc, + } + + trace_qio_channel_tls_handshake_pending(ioc, status); +- qio_channel_add_watch_full(ioc->master, +- condition, +- qio_channel_tls_handshake_io, +- data, +- NULL, +- context); ++ ioc->hs_ioc_tag = ++ qio_channel_add_watch_full(ioc->master, ++ condition, ++ qio_channel_tls_handshake_io, ++ data, ++ NULL, ++ context); + } + } + +@@ -214,6 +215,7 @@ static gboolean qio_channel_tls_handshake_io(QIOChannel *ioc, + QIOChannelTLS *tioc = QIO_CHANNEL_TLS( + qio_task_get_source(task)); + ++ tioc->hs_ioc_tag = 0; + g_free(data); + qio_channel_tls_handshake_task(tioc, task, context); + +@@ -371,6 +373,10 @@ static int qio_channel_tls_close(QIOChannel *ioc, + { + QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc); + ++ if (tioc->hs_ioc_tag) { ++ g_clear_handle_id(&tioc->hs_ioc_tag, g_source_remove); ++ } ++ + return qio_channel_close(tioc->master, errp); + } + +-- +2.25.1 + diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2023-5088.patch b/meta/recipes-devtools/qemu/qemu/CVE-2023-5088.patch new file mode 100644 index 0000000000..db02210fa4 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2023-5088.patch @@ -0,0 +1,114 @@ +From 7d7512019fc40c577e2bdd61f114f31a9eb84a8e Mon Sep 17 00:00:00 2001 +From: Fiona Ebner <f.ebner@proxmox.com> +Date: Wed, 6 Sep 2023 15:09:21 +0200 +Subject: [PATCH] hw/ide: reset: cancel async DMA operation before resetting + state +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If there is a pending DMA operation during ide_bus_reset(), the fact +that the IDEState is already reset before the operation is canceled +can be problematic. In particular, ide_dma_cb() might be called and +then use the reset IDEState which contains the signature after the +reset. When used to construct the IO operation this leads to +ide_get_sector() returning 0 and nsector being 1. This is particularly +bad, because a write command will thus destroy the first sector which +often contains a partition table or similar. + +Traces showing the unsolicited write happening with IDEState +0x5595af6949d0 being used after reset: + +> ahci_port_write ahci(0x5595af6923f0)[0]: port write [reg:PxSCTL] @ 0x2c: 0x00000300 +> ahci_reset_port ahci(0x5595af6923f0)[0]: reset port +> ide_reset IDEstate 0x5595af6949d0 +> ide_reset IDEstate 0x5595af694da8 +> ide_bus_reset_aio aio_cancel +> dma_aio_cancel dbs=0x7f64600089a0 +> dma_blk_cb dbs=0x7f64600089a0 ret=0 +> dma_complete dbs=0x7f64600089a0 ret=0 cb=0x5595acd40b30 +> ahci_populate_sglist ahci(0x5595af6923f0)[0] +> ahci_dma_prepare_buf ahci(0x5595af6923f0)[0]: prepare buf limit=512 prepared=512 +> ide_dma_cb IDEState 0x5595af6949d0; sector_num=0 n=1 cmd=DMA WRITE +> dma_blk_io dbs=0x7f6420802010 bs=0x5595ae2c6c30 offset=0 to_dev=1 +> dma_blk_cb dbs=0x7f6420802010 ret=0 + +> (gdb) p *qiov +> $11 = {iov = 0x7f647c76d840, niov = 1, {{nalloc = 1, local_iov = {iov_base = 0x0, +> iov_len = 512}}, {__pad = "\001\000\000\000\000\000\000\000\000\000\000", +> size = 512}}} +> (gdb) bt +> #0 blk_aio_pwritev (blk=0x5595ae2c6c30, offset=0, qiov=0x7f6420802070, flags=0, +> cb=0x5595ace6f0b0 <dma_blk_cb>, opaque=0x7f6420802010) +> at ../block/block-backend.c:1682 +> #1 0x00005595ace6f185 in dma_blk_cb (opaque=0x7f6420802010, ret=<optimized out>) +> at ../softmmu/dma-helpers.c:179 +> #2 0x00005595ace6f778 in dma_blk_io (ctx=0x5595ae0609f0, +> sg=sg@entry=0x5595af694d00, offset=offset@entry=0, align=align@entry=512, +> io_func=io_func@entry=0x5595ace6ee30 <dma_blk_write_io_func>, +> io_func_opaque=io_func_opaque@entry=0x5595ae2c6c30, +> cb=0x5595acd40b30 <ide_dma_cb>, opaque=0x5595af6949d0, +> dir=DMA_DIRECTION_TO_DEVICE) at ../softmmu/dma-helpers.c:244 +> #3 0x00005595ace6f90a in dma_blk_write (blk=0x5595ae2c6c30, +> sg=sg@entry=0x5595af694d00, offset=offset@entry=0, align=align@entry=512, +> cb=cb@entry=0x5595acd40b30 <ide_dma_cb>, opaque=opaque@entry=0x5595af6949d0) +> at ../softmmu/dma-helpers.c:280 +> #4 0x00005595acd40e18 in ide_dma_cb (opaque=0x5595af6949d0, ret=<optimized out>) +> at ../hw/ide/core.c:953 +> #5 0x00005595ace6f319 in dma_complete (ret=0, dbs=0x7f64600089a0) +> at ../softmmu/dma-helpers.c:107 +> #6 dma_blk_cb (opaque=0x7f64600089a0, ret=0) at ../softmmu/dma-helpers.c:127 +> #7 0x00005595ad12227d in blk_aio_complete (acb=0x7f6460005b10) +> at ../block/block-backend.c:1527 +> #8 blk_aio_complete (acb=0x7f6460005b10) at ../block/block-backend.c:1524 +> #9 blk_aio_write_entry (opaque=0x7f6460005b10) at ../block/block-backend.c:1594 +> #10 0x00005595ad258cfb in coroutine_trampoline (i0=<optimized out>, +> i1=<optimized out>) at ../util/coroutine-ucontext.c:177 + +Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> +Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> +Tested-by: simon.rowe@nutanix.com +Message-ID: <20230906130922.142845-1-f.ebner@proxmox.com> +Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> + +Upstream-Status: Backport [https://gitlab.com/qemu-project/qemu/-/commit/7d7512019fc40c577e2bdd61f114f31a9eb84a8e] +CVE: CVE-2023-5088 +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> +--- + hw/ide/core.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/hw/ide/core.c b/hw/ide/core.c +index b5e0dcd29b2..63ba665f3d2 100644 +--- a/hw/ide/core.c ++++ b/hw/ide/core.c +@@ -2515,19 +2515,19 @@ static void ide_dummy_transfer_stop(IDEState *s) + + void ide_bus_reset(IDEBus *bus) + { +- bus->unit = 0; +- bus->cmd = 0; +- ide_reset(&bus->ifs[0]); +- ide_reset(&bus->ifs[1]); +- ide_clear_hob(bus); +- +- /* pending async DMA */ ++ /* pending async DMA - needs the IDEState before it is reset */ + if (bus->dma->aiocb) { + trace_ide_bus_reset_aio(); + blk_aio_cancel(bus->dma->aiocb); + bus->dma->aiocb = NULL; + } + ++ bus->unit = 0; ++ bus->cmd = 0; ++ ide_reset(&bus->ifs[0]); ++ ide_reset(&bus->ifs[1]); ++ ide_clear_hob(bus); ++ + /* reset dma provider too */ + if (bus->dma->ops->reset) { + bus->dma->ops->reset(bus->dma); +-- +GitLab + diff --git a/meta/recipes-devtools/qemu/qemu/hw-block-nvme-handle-dma-errors.patch b/meta/recipes-devtools/qemu/qemu/hw-block-nvme-handle-dma-errors.patch new file mode 100644 index 0000000000..0fdae8351a --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/hw-block-nvme-handle-dma-errors.patch @@ -0,0 +1,146 @@ +From ea2a7c7676d8eb9d1458eaa4b717df46782dcb3a Mon Sep 17 00:00:00 2001 +From: Gaurav Gupta <gauragup@cisco.com> +Date: Wed, 29 Mar 2023 14:07:17 -0700 +Subject: [PATCH 2/2] hw/block/nvme: handle dma errors + +Handling DMA errors gracefully is required for the device to pass the +block/011 test ("disable PCI device while doing I/O") in the blktests +suite. + +With this patch the device sets the Controller Fatal Status bit in the +CSTS register when failing to read from a submission queue or writing to +a completion queue; expecting the host to reset the controller. + +If DMA errors occur at any other point in the execution of the command +(say, while mapping the PRPs), the command is aborted with a Data +Transfer Error status code. + +Signed-off-by: Klaus Jensen <k.jensen@samsung.com> +Signed-off-by: Gaurav Gupta <gauragup@cisco.com> +--- + hw/block/nvme.c | 41 +++++++++++++++++++++++++++++++---------- + hw/block/trace-events | 3 +++ + 2 files changed, 34 insertions(+), 10 deletions(-) + +diff --git a/hw/block/nvme.c b/hw/block/nvme.c +index e6f24a6..bda446d 100644 +--- a/hw/block/nvme.c ++++ b/hw/block/nvme.c +@@ -60,14 +60,14 @@ static bool nvme_addr_is_cmb(NvmeCtrl *n, hwaddr addr) + return addr >= low && addr < hi; + } + +-static void nvme_addr_read(NvmeCtrl *n, hwaddr addr, void *buf, int size) ++static int nvme_addr_read(NvmeCtrl *n, hwaddr addr, void *buf, int size) + { + if (n->cmbsz && nvme_addr_is_cmb(n, addr)) { + memcpy(buf, (void *)&n->cmbuf[addr - n->ctrl_mem.addr], size); +- return; ++ return 0; + } + +- pci_dma_read(&n->parent_obj, addr, buf, size); ++ return pci_dma_read(&n->parent_obj, addr, buf, size); + } + + static int nvme_check_sqid(NvmeCtrl *n, uint16_t sqid) +@@ -152,6 +152,7 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1, + hwaddr trans_len = n->page_size - (prp1 % n->page_size); + trans_len = MIN(len, trans_len); + int num_prps = (len >> n->page_bits) + 1; ++ int ret; + + if (unlikely(!prp1)) { + trace_nvme_err_invalid_prp(); +@@ -178,7 +179,11 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1, + + nents = (len + n->page_size - 1) >> n->page_bits; + prp_trans = MIN(n->max_prp_ents, nents) * sizeof(uint64_t); +- nvme_addr_read(n, prp2, (void *)prp_list, prp_trans); ++ ret = nvme_addr_read(n, prp2, (void *)prp_list, prp_trans); ++ if (ret) { ++ trace_pci_nvme_err_addr_read(prp2); ++ return NVME_DATA_TRAS_ERROR; ++ } + while (len != 0) { + uint64_t prp_ent = le64_to_cpu(prp_list[i]); + +@@ -191,8 +196,12 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1, + i = 0; + nents = (len + n->page_size - 1) >> n->page_bits; + prp_trans = MIN(n->max_prp_ents, nents) * sizeof(uint64_t); +- nvme_addr_read(n, prp_ent, (void *)prp_list, +- prp_trans); ++ ret = nvme_addr_read(n, prp_ent, (void *)prp_list, ++ prp_trans); ++ if (ret) { ++ trace_pci_nvme_err_addr_read(prp_ent); ++ return NVME_DATA_TRAS_ERROR; ++ } + prp_ent = le64_to_cpu(prp_list[i]); + } + +@@ -286,6 +295,7 @@ static void nvme_post_cqes(void *opaque) + NvmeCQueue *cq = opaque; + NvmeCtrl *n = cq->ctrl; + NvmeRequest *req, *next; ++ int ret; + + QTAILQ_FOREACH_SAFE(req, &cq->req_list, entry, next) { + NvmeSQueue *sq; +@@ -295,15 +305,21 @@ static void nvme_post_cqes(void *opaque) + break; + } + +- QTAILQ_REMOVE(&cq->req_list, req, entry); + sq = req->sq; + req->cqe.status = cpu_to_le16((req->status << 1) | cq->phase); + req->cqe.sq_id = cpu_to_le16(sq->sqid); + req->cqe.sq_head = cpu_to_le16(sq->head); + addr = cq->dma_addr + cq->tail * n->cqe_size; ++ ret = pci_dma_write(&n->parent_obj, addr, (void *)&req->cqe, ++ sizeof(req->cqe)); ++ if (ret) { ++ trace_pci_nvme_err_addr_write(addr); ++ trace_pci_nvme_err_cfs(); ++ n->bar.csts = NVME_CSTS_FAILED; ++ break; ++ } ++ QTAILQ_REMOVE(&cq->req_list, req, entry); + nvme_inc_cq_tail(cq); +- pci_dma_write(&n->parent_obj, addr, (void *)&req->cqe, +- sizeof(req->cqe)); + QTAILQ_INSERT_TAIL(&sq->req_list, req, entry); + } + if (cq->tail != cq->head) { +@@ -888,7 +904,12 @@ static void nvme_process_sq(void *opaque) + + while (!(nvme_sq_empty(sq) || QTAILQ_EMPTY(&sq->req_list))) { + addr = sq->dma_addr + sq->head * n->sqe_size; +- nvme_addr_read(n, addr, (void *)&cmd, sizeof(cmd)); ++ if (nvme_addr_read(n, addr, (void *)&cmd, sizeof(cmd))) { ++ trace_pci_nvme_err_addr_read(addr); ++ trace_pci_nvme_err_cfs(); ++ n->bar.csts = NVME_CSTS_FAILED; ++ break; ++ } + nvme_inc_sq_head(sq); + + req = QTAILQ_FIRST(&sq->req_list); +diff --git a/hw/block/trace-events b/hw/block/trace-events +index c03e80c..4e4ad4e 100644 +--- a/hw/block/trace-events ++++ b/hw/block/trace-events +@@ -60,6 +60,9 @@ nvme_mmio_shutdown_set(void) "shutdown bit set" + nvme_mmio_shutdown_cleared(void) "shutdown bit cleared" + + # nvme traces for error conditions ++pci_nvme_err_addr_read(uint64_t addr) "addr 0x%"PRIx64"" ++pci_nvme_err_addr_write(uint64_t addr) "addr 0x%"PRIx64"" ++pci_nvme_err_cfs(void) "controller fatal status" + nvme_err_invalid_dma(void) "PRP/SGL is too small for transfer size" + nvme_err_invalid_prplist_ent(uint64_t prplist) "PRP list entry is null or not page aligned: 0x%"PRIx64"" + nvme_err_invalid_prp2_align(uint64_t prp2) "PRP2 is not page aligned: 0x%"PRIx64"" +-- +1.8.3.1 + diff --git a/meta/recipes-devtools/qemu/qemu/hw-block-nvme-refactor-nvme_addr_read.patch b/meta/recipes-devtools/qemu/qemu/hw-block-nvme-refactor-nvme_addr_read.patch new file mode 100644 index 0000000000..66ada52efb --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/hw-block-nvme-refactor-nvme_addr_read.patch @@ -0,0 +1,55 @@ +From 55428706d5b0b8889b8e009eac77137bb556a4f0 Mon Sep 17 00:00:00 2001 +From: Klaus Jensen <k.jensen@samsung.com> +Date: Tue, 9 Jun 2020 21:03:17 +0200 +Subject: [PATCH 1/2] hw/block/nvme: refactor nvme_addr_read +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Pull the controller memory buffer check to its own function. The check +will be used on its own in later patches. + +Signed-off-by: Klaus Jensen <k.jensen@samsung.com> +Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> +Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com> +Reviewed-by: Keith Busch <kbusch@kernel.org> +Message-Id: <20200609190333.59390-7-its@irrelevant.dk> +Signed-off-by: Kevin Wolf <kwolf@redhat.com> +--- + hw/block/nvme.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/hw/block/nvme.c b/hw/block/nvme.c +index 12d8254..e6f24a6 100644 +--- a/hw/block/nvme.c ++++ b/hw/block/nvme.c +@@ -52,14 +52,22 @@ + + static void nvme_process_sq(void *opaque); + ++static bool nvme_addr_is_cmb(NvmeCtrl *n, hwaddr addr) ++{ ++ hwaddr low = n->ctrl_mem.addr; ++ hwaddr hi = n->ctrl_mem.addr + int128_get64(n->ctrl_mem.size); ++ ++ return addr >= low && addr < hi; ++} ++ + static void nvme_addr_read(NvmeCtrl *n, hwaddr addr, void *buf, int size) + { +- if (n->cmbsz && addr >= n->ctrl_mem.addr && +- addr < (n->ctrl_mem.addr + int128_get64(n->ctrl_mem.size))) { ++ if (n->cmbsz && nvme_addr_is_cmb(n, addr)) { + memcpy(buf, (void *)&n->cmbuf[addr - n->ctrl_mem.addr], size); +- } else { +- pci_dma_read(&n->parent_obj, addr, buf, size); ++ return; + } ++ ++ pci_dma_read(&n->parent_obj, addr, buf, size); + } + + static int nvme_check_sqid(NvmeCtrl *n, uint16_t sqid) +-- +1.8.3.1 + diff --git a/meta/recipes-devtools/qemu/qemu/hw-display-qxl-Pass-requested-buffer-size-to-qxl_phy.patch b/meta/recipes-devtools/qemu/qemu/hw-display-qxl-Pass-requested-buffer-size-to-qxl_phy.patch new file mode 100644 index 0000000000..f380be486c --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/hw-display-qxl-Pass-requested-buffer-size-to-qxl_phy.patch @@ -0,0 +1,236 @@ +From 5a44a01c9eca6507be45d107c27377a3e8d0ee8c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= <philmd@linaro.org> +Date: Mon, 28 Nov 2022 21:27:39 +0100 +Subject: [PATCH] hw/display/qxl: Pass requested buffer size to qxl_phys2virt() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Currently qxl_phys2virt() doesn't check for buffer overrun. +In order to do so in the next commit, pass the buffer size +as argument. + +For QXLCursor in qxl_render_cursor() -> qxl_cursor() we +verify the size of the chunked data ahead, checking we can +access 'sizeof(QXLCursor) + chunk->data_size' bytes. +Since in the SPICE_CURSOR_TYPE_MONO case the cursor is +assumed to fit in one chunk, no change are required. +In SPICE_CURSOR_TYPE_ALPHA the ahead read is handled in +qxl_unpack_chunks(). + +Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> +Acked-by: Gerd Hoffmann <kraxel@redhat.com> +Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> +Message-Id: <20221128202741.4945-4-philmd@linaro.org> + +Backport and rebase patch to fix compile error which imported by CVE-2022-4144.patch: + +/qxl.c: In function 'qxl_phys2virt': +| /home/hitendra/work/yocto-work/cgx-data/dunfell-3.1/x86-generic-64-5.4-3.1-cgx/project/tmp/work/i586-montavistamllib32-linux/lib32-qemu/4.2.0-r0.8/qemu-4.2.0/hw/display/qxl.c:1508:67: error: 'size' undeclared (first use in this function); did you mean 'gsize'? +| 1508 | if (!qxl_get_check_slot_offset(qxl, pqxl, &slot, &offset, size)) { +| | ^~~~ +| | gsize + +Upstream-Status: Backport [https://github.com/qemu/qemu/commit/61c34fc && https://gitlab.com/qemu-project/qemu/-/commit/8efec0ef8bbc1e75a7ebf6e325a35806ece9b39f] + +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> +--- + hw/display/qxl-logger.c | 22 +++++++++++++++++++--- + hw/display/qxl-render.c | 20 ++++++++++++++++---- + hw/display/qxl.c | 17 +++++++++++------ + hw/display/qxl.h | 3 ++- + 4 files changed, 48 insertions(+), 14 deletions(-) + +diff --git a/hw/display/qxl-logger.c b/hw/display/qxl-logger.c +index 2ec6d8fa..031ddfec 100644 +--- a/hw/display/qxl-logger.c ++++ b/hw/display/qxl-logger.c +@@ -106,7 +106,7 @@ static int qxl_log_image(PCIQXLDevice *qxl, QXLPHYSICAL addr, int group_id) + QXLImage *image; + QXLImageDescriptor *desc; + +- image = qxl_phys2virt(qxl, addr, group_id); ++ image = qxl_phys2virt(qxl, addr, group_id, sizeof(QXLImage)); + if (!image) { + return 1; + } +@@ -216,7 +216,8 @@ int qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id) + cmd->u.set.position.y, + cmd->u.set.visible ? "yes" : "no", + cmd->u.set.shape); +- cursor = qxl_phys2virt(qxl, cmd->u.set.shape, group_id); ++ cursor = qxl_phys2virt(qxl, cmd->u.set.shape, group_id, ++ sizeof(QXLCursor)); + if (!cursor) { + return 1; + } +@@ -238,6 +239,7 @@ int qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext) + { + bool compat = ext->flags & QXL_COMMAND_FLAG_COMPAT; + void *data; ++ size_t datasz; + int ret; + + if (!qxl->cmdlog) { +@@ -249,7 +251,20 @@ int qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext) + qxl_name(qxl_type, ext->cmd.type), + compat ? "(compat)" : ""); + +- data = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); ++ switch (ext->cmd.type) { ++ case QXL_CMD_DRAW: ++ datasz = compat ? sizeof(QXLCompatDrawable) : sizeof(QXLDrawable); ++ break; ++ case QXL_CMD_SURFACE: ++ datasz = sizeof(QXLSurfaceCmd); ++ break; ++ case QXL_CMD_CURSOR: ++ datasz = sizeof(QXLCursorCmd); ++ break; ++ default: ++ goto out; ++ } ++ data = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id, datasz); + if (!data) { + return 1; + } +@@ -271,6 +286,7 @@ int qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext) + qxl_log_cmd_cursor(qxl, data, ext->group_id); + break; + } ++out: + fprintf(stderr, "\n"); + return 0; + } +diff --git a/hw/display/qxl-render.c b/hw/display/qxl-render.c +index d532e157..a65a6d64 100644 +--- a/hw/display/qxl-render.c ++++ b/hw/display/qxl-render.c +@@ -107,7 +107,9 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) + qxl->guest_primary.resized = 0; + qxl->guest_primary.data = qxl_phys2virt(qxl, + qxl->guest_primary.surface.mem, +- MEMSLOT_GROUP_GUEST); ++ MEMSLOT_GROUP_GUEST, ++ qxl->guest_primary.abs_stride ++ * height); + if (!qxl->guest_primary.data) { + return; + } +@@ -222,7 +224,8 @@ static void qxl_unpack_chunks(void *dest, size_t size, PCIQXLDevice *qxl, + if (offset == size) { + return; + } +- chunk = qxl_phys2virt(qxl, chunk->next_chunk, group_id); ++ chunk = qxl_phys2virt(qxl, chunk->next_chunk, group_id, ++ sizeof(QXLDataChunk) + chunk->data_size); + if (!chunk) { + return; + } +@@ -289,7 +292,8 @@ fail: + /* called from spice server thread context only */ + int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext) + { +- QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); ++ QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id, ++ sizeof(QXLCursorCmd)); + QXLCursor *cursor; + QEMUCursor *c; + +@@ -308,7 +312,15 @@ int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext) + } + switch (cmd->type) { + case QXL_CURSOR_SET: +- cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id); ++ /* First read the QXLCursor to get QXLDataChunk::data_size ... */ ++ cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id, ++ sizeof(QXLCursor)); ++ if (!cursor) { ++ return 1; ++ } ++ /* Then read including the chunked data following QXLCursor. */ ++ cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id, ++ sizeof(QXLCursor) + cursor->chunk.data_size); + if (!cursor) { + return 1; + } +diff --git a/hw/display/qxl.c b/hw/display/qxl.c +index 6bc8385b..858d3e93 100644 +--- a/hw/display/qxl.c ++++ b/hw/display/qxl.c +@@ -275,7 +275,8 @@ static void qxl_spice_monitors_config_async(PCIQXLDevice *qxl, int replay) + QXL_IO_MONITORS_CONFIG_ASYNC)); + } + +- cfg = qxl_phys2virt(qxl, qxl->guest_monitors_config, MEMSLOT_GROUP_GUEST); ++ cfg = qxl_phys2virt(qxl, qxl->guest_monitors_config, MEMSLOT_GROUP_GUEST, ++ sizeof(QXLMonitorsConfig)); + if (cfg != NULL && cfg->count == 1) { + qxl->guest_primary.resized = 1; + qxl->guest_head0_width = cfg->heads[0].width; +@@ -460,7 +461,8 @@ static int qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext) + switch (le32_to_cpu(ext->cmd.type)) { + case QXL_CMD_SURFACE: + { +- QXLSurfaceCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); ++ QXLSurfaceCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id, ++ sizeof(QXLSurfaceCmd)); + + if (!cmd) { + return 1; +@@ -494,7 +496,8 @@ static int qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext) + } + case QXL_CMD_CURSOR: + { +- QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); ++ QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id, ++ sizeof(QXLCursorCmd)); + + if (!cmd) { + return 1; +@@ -674,7 +677,8 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) + * + * https://cgit.freedesktop.org/spice/win32/qxl-wddm-dod/commit/?id=f6e099db39e7d0787f294d5fd0dce328b5210faa + */ +- void *msg = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); ++ void *msg = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id, ++ sizeof(QXLCommandRing)); + if (msg != NULL && ( + msg < (void *)qxl->vga.vram_ptr || + msg > ((void *)qxl->vga.vram_ptr + qxl->vga.vram_size))) { +@@ -1494,7 +1498,8 @@ static bool qxl_get_check_slot_offset(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, + } + + /* can be also called from spice server thread context */ +-void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id) ++void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id, ++ size_t size) + { + uint64_t offset; + uint32_t slot; +@@ -1994,7 +1999,7 @@ static void qxl_dirty_surfaces(PCIQXLDevice *qxl) + } + + cmd = qxl_phys2virt(qxl, qxl->guest_surfaces.cmds[i], +- MEMSLOT_GROUP_GUEST); ++ MEMSLOT_GROUP_GUEST, sizeof(QXLSurfaceCmd)); + assert(cmd); + assert(cmd->type == QXL_SURFACE_CMD_CREATE); + qxl_dirty_one_surface(qxl, cmd->u.surface_create.data, +diff --git a/hw/display/qxl.h b/hw/display/qxl.h +index 80eb0d26..fcfd133a 100644 +--- a/hw/display/qxl.h ++++ b/hw/display/qxl.h +@@ -147,7 +147,8 @@ typedef struct PCIQXLDevice { + #define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V12 + + /* qxl.c */ +-void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id); ++void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id, ++ size_t size); + void qxl_set_guest_bug(PCIQXLDevice *qxl, const char *msg, ...) + GCC_FMT_ATTR(2, 3); + +-- +2.25.1 + diff --git a/meta/recipes-devtools/qemu/qemu_4.2.0.bb b/meta/recipes-devtools/qemu/qemu_4.2.0.bb index 9c76144749..05449afe4e 100644 --- a/meta/recipes-devtools/qemu/qemu_4.2.0.bb +++ b/meta/recipes-devtools/qemu/qemu_4.2.0.bb @@ -24,7 +24,8 @@ do_install_append_class-nativesdk() { } PACKAGECONFIG ??= " \ - fdt sdl kvm \ + fdt sdl kvm slirp \ ${@bb.utils.filter('DISTRO_FEATURES', 'alsa xen', d)} \ + ${@bb.utils.filter('DISTRO_FEATURES', 'seccomp', d)} \ " -PACKAGECONFIG_class-nativesdk ??= "fdt sdl kvm" +PACKAGECONFIG:class-nativesdk ??= "fdt sdl kvm slirp" diff --git a/meta/recipes-devtools/quilt/quilt.inc b/meta/recipes-devtools/quilt/quilt.inc index d7ecda7aaa..ad23b8d922 100644 --- a/meta/recipes-devtools/quilt/quilt.inc +++ b/meta/recipes-devtools/quilt/quilt.inc @@ -12,6 +12,7 @@ SRC_URI = "${SAVANNAH_GNU_MIRROR}/quilt/quilt-${PV}.tar.gz \ file://Makefile \ file://test.sh \ file://0001-tests-Allow-different-output-from-mv.patch \ + file://faildiff-order.patch \ " SRC_URI_append_class-target = " file://gnu_patch_test_fix_target.patch" diff --git a/meta/recipes-devtools/quilt/quilt/faildiff-order.patch b/meta/recipes-devtools/quilt/quilt/faildiff-order.patch new file mode 100644 index 0000000000..f22065a250 --- /dev/null +++ b/meta/recipes-devtools/quilt/quilt/faildiff-order.patch @@ -0,0 +1,41 @@ +Upstream-Status: Backport +Signed-off-by: Ross Burton <ross.burton@arm.com> + +From 4dfe7f9e702c85243a71e4de267a13e434b6d6c2 Mon Sep 17 00:00:00 2001 +From: Jean Delvare <jdelvare@suse.de> +Date: Fri, 20 Jan 2023 12:56:08 +0100 +Subject: [PATCH] test: Fix a race condition + +The test suite does not differentiate between stdout and stderr. When +messages are printed to both, the order in which they will reach us +is apparently not guaranteed. Ideally this would be deterministic, but +until then, explicitly test stdout and stderr separately in the test +case itself. Otherwise the test suite fails randomly, which is a pain +for distribution package maintainers. + +This fixes bug #63651 reported by Ross Burton: +https://savannah.nongnu.org/bugs/index.php?63651 + +Signed-off-by: Jean Delvare <jdelvare@suse.de> +--- + test/faildiff.test | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/test/faildiff.test b/test/faildiff.test +index 5afb8e3..0444c15 100644 +--- a/test/faildiff.test ++++ b/test/faildiff.test +@@ -27,8 +27,9 @@ What happens on binary files? + > File test.bin added to patch %{P}test.diff + + $ printf "\\003\\000\\001" > test.bin +- $ quilt diff -pab --no-index ++ $ quilt diff -pab --no-index 2>/dev/null + >~ (Files|Binary files) a/test\.bin and b/test\.bin differ ++ $ quilt diff -pab --no-index >/dev/null + > Diff failed on file 'test.bin', aborting + $ echo %{?} + > 1 +-- +2.34.1 + diff --git a/meta/recipes-devtools/rpm/files/0001-rpm-rpmio.c-restrict-virtual-memory-usage-if-limit-s.patch b/meta/recipes-devtools/rpm/files/0001-rpm-rpmio.c-restrict-virtual-memory-usage-if-limit-s.patch index 6454785254..dc3f74fecd 100644 --- a/meta/recipes-devtools/rpm/files/0001-rpm-rpmio.c-restrict-virtual-memory-usage-if-limit-s.patch +++ b/meta/recipes-devtools/rpm/files/0001-rpm-rpmio.c-restrict-virtual-memory-usage-if-limit-s.patch @@ -11,36 +11,39 @@ CPU thread. Upstream-Status: Pending [merge of multithreading patches to upstream] Signed-off-by: Peter Bergin <peter@berginkonsult.se> +Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> --- - rpmio/rpmio.c | 34 ++++++++++++++++++++++++++++++++++ - 1 file changed, 34 insertions(+) + rpmio/rpmio.c | 36 ++++++++++++++++++++++++++++++++++++ + 1 file changed, 36 insertions(+) diff --git a/rpmio/rpmio.c b/rpmio/rpmio.c index e051c98..b3c56b6 100644 --- a/rpmio/rpmio.c +++ b/rpmio/rpmio.c -@@ -845,6 +845,40 @@ static LZFILE *lzopen_internal(const char *mode, int fd, int xz) +@@ -845,6 +845,42 @@ static LZFILE *lzopen_internal(const char *mode, int fd, int xz) } #endif -+ struct rlimit virtual_memory; -+ getrlimit(RLIMIT_AS, &virtual_memory); -+ if (virtual_memory.rlim_cur != RLIM_INFINITY) { ++ struct rlimit virtual_memory = {RLIM_INFINITY , RLIM_INFINITY}; ++ int status = getrlimit(RLIMIT_AS, &virtual_memory); ++ if ((status != -1) && (virtual_memory.rlim_cur != RLIM_INFINITY)) { + const uint64_t virtual_memlimit = virtual_memory.rlim_cur; ++ uint32_t threads_max = lzma_cputhreads(); + const uint64_t virtual_memlimit_per_cpu_thread = -+ virtual_memlimit / lzma_cputhreads(); -+ uint64_t memory_usage_virt; ++ virtual_memlimit / ((threads_max == 0) ? 1 : threads_max); + rpmlog(RPMLOG_NOTICE, "XZ: virtual memory restricted to %lu and " + "per CPU thread %lu\n", virtual_memlimit, virtual_memlimit_per_cpu_thread); ++ uint64_t memory_usage_virt; + /* keep reducing the number of compression threads until memory + usage falls below the limit per CPU thread*/ + while ((memory_usage_virt = lzma_stream_encoder_mt_memusage(&mt_options)) > + virtual_memlimit_per_cpu_thread) { -+ /* If number of threads goes down to zero lzma_stream_encoder will -+ * will return UINT64_MAX. We must check here to avoid an infinite loop. ++ /* If number of threads goes down to zero or in case of any other error ++ * lzma_stream_encoder_mt_memusage will return UINT64_MAX. We must check ++ * for both the cases here to avoid an infinite loop. + * If we get into situation that one thread requires more virtual memory + * than available we set one thread, print error message and try anyway. */ -+ if (--mt_options.threads == 0) { ++ if ((--mt_options.threads == 0) || (memory_usage_virt == UINT64_MAX)) { + mt_options.threads = 1; + rpmlog(RPMLOG_WARNING, + "XZ: Could not adjust number of threads to get below " diff --git a/meta/recipes-devtools/rpm/files/0001-rpmio-Fix-lzopen_internal-mode-parsing-when-Tn-is-us.patch b/meta/recipes-devtools/rpm/files/0001-rpmio-Fix-lzopen_internal-mode-parsing-when-Tn-is-us.patch new file mode 100644 index 0000000000..9a5ebb9115 --- /dev/null +++ b/meta/recipes-devtools/rpm/files/0001-rpmio-Fix-lzopen_internal-mode-parsing-when-Tn-is-us.patch @@ -0,0 +1,34 @@ +From 405fc8998181353bd510864ca251dc233afec276 Mon Sep 17 00:00:00 2001 +From: Vitaly Chikunov <vt@altlinux.org> +Date: Wed, 6 Jan 2021 23:43:41 +0300 +Subject: [PATCH] rpmio: Fix lzopen_internal mode parsing when 'Tn' is used + +When there is number after "T" (suggested number of threads or "0" for +getncpus), lzopen_internal() mode parser would skip one byte, and when +it's at the end of the string it would then parse undesired garbage from +the memory, making intermittent compression failures. + +Fixes: 7740d1098 ("Add support for multithreaded xz compression") +Signed-off-by: Vitaly Chikunov <vt@altlinux.org> + +Upstream-Status: Backport [https://github.com/rpm-software-management/rpm/commit/405fc8998181353bd510864ca251dc233afec276] + +--- + rpmio/rpmio.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/rpmio/rpmio.c b/rpmio/rpmio.c +index ed1e25140..9d32ec6d9 100644 +--- a/rpmio/rpmio.c ++++ b/rpmio/rpmio.c +@@ -798,6 +798,7 @@ static LZFILE *lzopen_internal(const char *mode, int fd, int xz) + * should've processed + * */ + while (isdigit(*++mode)); ++ --mode; + } + #ifdef HAVE_LZMA_MT + else +-- +2.25.1 + diff --git a/meta/recipes-devtools/rpm/files/CVE-2021-20266.patch b/meta/recipes-devtools/rpm/files/CVE-2021-20266.patch new file mode 100644 index 0000000000..f2fc47e321 --- /dev/null +++ b/meta/recipes-devtools/rpm/files/CVE-2021-20266.patch @@ -0,0 +1,109 @@ +From ebbf0f0133c498d229e94ecf2ed0b41d6e6a142a Mon Sep 17 00:00:00 2001 +From: Demi Marie Obenour <athena@invisiblethingslab.com> +Date: Mon, 8 Feb 2021 16:05:01 -0500 +Subject: [PATCH] hdrblobInit() needs bounds checks too + +Users can pass untrusted data to hdrblobInit() and it must be robust +against this. + +Backported from commit 8f4b3c3cab8922a2022b9e47c71f1ecf906077ef + +Upstream-Status: Backport [https://github.com/rpm-software-management/rpm/pull/1587/commits/9646711891df851dfbf7ef54cc171574a0914b15] +CVE: CVE-2021-20266 +Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> + +--- + lib/header.c | 48 +++++++++++++++++++++++++++++++----------------- + 1 file changed, 31 insertions(+), 17 deletions(-) + +diff --git a/lib/header.c b/lib/header.c +index 5b09f8352..ad5b6dc57 100644 +--- a/lib/header.c ++++ b/lib/header.c +@@ -11,6 +11,7 @@ + #include "system.h" + #include <netdb.h> + #include <errno.h> ++#include <inttypes.h> + #include <rpm/rpmtypes.h> + #include <rpm/rpmstring.h> + #include "lib/header_internal.h" +@@ -1890,6 +1891,25 @@ hdrblob hdrblobFree(hdrblob blob) + return NULL; + } + ++static rpmRC hdrblobVerifyLengths(rpmTagVal regionTag, uint32_t il, uint32_t dl, ++ char **emsg) { ++ uint32_t il_max = HEADER_TAGS_MAX; ++ uint32_t dl_max = HEADER_DATA_MAX; ++ if (regionTag == RPMTAG_HEADERSIGNATURES) { ++ il_max = 32; ++ dl_max = 8192; ++ } ++ if (hdrchkRange(il_max, il)) { ++ rasprintf(emsg, _("hdr tags: BAD, no. of tags(%" PRIu32 ") out of range"), il); ++ return RPMRC_FAIL; ++ } ++ if (hdrchkRange(dl_max, dl)) { ++ rasprintf(emsg, _("hdr data: BAD, no. of bytes(%" PRIu32 ") out of range"), dl); ++ return RPMRC_FAIL; ++ } ++ return RPMRC_OK; ++} ++ + rpmRC hdrblobRead(FD_t fd, int magic, int exact_size, rpmTagVal regionTag, hdrblob blob, char **emsg) + { + int32_t block[4]; +@@ -1902,13 +1922,6 @@ rpmRC hdrblobRead(FD_t fd, int magic, int exact_size, rpmTagVal regionTag, hdrbl + size_t nb; + rpmRC rc = RPMRC_FAIL; /* assume failure */ + int xx; +- int32_t il_max = HEADER_TAGS_MAX; +- int32_t dl_max = HEADER_DATA_MAX; +- +- if (regionTag == RPMTAG_HEADERSIGNATURES) { +- il_max = 32; +- dl_max = 8192; +- } + + memset(block, 0, sizeof(block)); + if ((xx = Freadall(fd, bs, blen)) != blen) { +@@ -1921,15 +1934,9 @@ rpmRC hdrblobRead(FD_t fd, int magic, int exact_size, rpmTagVal regionTag, hdrbl + goto exit; + } + il = ntohl(block[2]); +- if (hdrchkRange(il_max, il)) { +- rasprintf(emsg, _("hdr tags: BAD, no. of tags(%d) out of range"), il); +- goto exit; +- } + dl = ntohl(block[3]); +- if (hdrchkRange(dl_max, dl)) { +- rasprintf(emsg, _("hdr data: BAD, no. of bytes(%d) out of range"), dl); ++ if (hdrblobVerifyLengths(regionTag, il, dl, emsg)) + goto exit; +- } + + nb = (il * sizeof(struct entryInfo_s)) + dl; + uc = sizeof(il) + sizeof(dl) + nb; +@@ -1973,11 +1980,18 @@ rpmRC hdrblobInit(const void *uh, size_t uc, + struct hdrblob_s *blob, char **emsg) + { + rpmRC rc = RPMRC_FAIL; +- + memset(blob, 0, sizeof(*blob)); ++ if (uc && uc < 8) { ++ rasprintf(emsg, _("hdr length: BAD")); ++ goto exit; ++ } ++ + blob->ei = (int32_t *) uh; /* discards const */ +- blob->il = ntohl(blob->ei[0]); +- blob->dl = ntohl(blob->ei[1]); ++ blob->il = ntohl((uint32_t)(blob->ei[0])); ++ blob->dl = ntohl((uint32_t)(blob->ei[1])); ++ if (hdrblobVerifyLengths(regionTag, blob->il, blob->dl, emsg) != RPMRC_OK) ++ goto exit; ++ + blob->pe = (entryInfo) &(blob->ei[2]); + blob->pvlen = sizeof(blob->il) + sizeof(blob->dl) + + (blob->il * sizeof(*blob->pe)) + blob->dl; diff --git a/meta/recipes-devtools/rpm/files/CVE-2021-3521-01.patch b/meta/recipes-devtools/rpm/files/CVE-2021-3521-01.patch new file mode 100644 index 0000000000..0882d6f310 --- /dev/null +++ b/meta/recipes-devtools/rpm/files/CVE-2021-3521-01.patch @@ -0,0 +1,60 @@ +From b5e8bc74b2b05aa557f663fe227b94d2bc64fbd8 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen <pmatilai@redhat.com> +Date: Thu, 30 Sep 2021 09:51:10 +0300 +Subject: [PATCH] Process MPI's from all kinds of signatures + +No immediate effect but needed by the following commits. + +Dependent patch: +CVE: CVE-2021-3521 +Upstream-Status: Backport [https://github.com/rpm-software-management/rpm/commit/b5e8bc74b2b05aa557f663fe227b94d2bc64fbd8] +Signed-off-by: Riyaz Khan <Riyaz.Khan@kpit.com> + +--- + rpmio/rpmpgp.c | 12 +++++------- + 1 file changed, 5 insertions(+), 7 deletions(-) + +diff --git a/rpmio/rpmpgp.c b/rpmio/rpmpgp.c +index ee5c81e246..340de5fc9a 100644 +--- a/rpmio/rpmpgp.c ++++ b/rpmio/rpmpgp.c +@@ -511,7 +511,7 @@ pgpDigAlg pgpDigAlgFree(pgpDigAlg alg) + return NULL; + } + +-static int pgpPrtSigParams(pgpTag tag, uint8_t pubkey_algo, uint8_t sigtype, ++static int pgpPrtSigParams(pgpTag tag, uint8_t pubkey_algo, + const uint8_t *p, const uint8_t *h, size_t hlen, + pgpDigParams sigp) + { +@@ -524,10 +524,8 @@ static int pgpPrtSigParams(pgpTag tag, uint8_t pubkey_algo, uint8_t sigtype, + int mpil = pgpMpiLen(p); + if (p + mpil > pend) + break; +- if (sigtype == PGPSIGTYPE_BINARY || sigtype == PGPSIGTYPE_TEXT) { +- if (sigalg->setmpi(sigalg, i, p)) +- break; +- } ++ if (sigalg->setmpi(sigalg, i, p)) ++ break; + p += mpil; + } + +@@ -600,7 +598,7 @@ static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen, + } + + p = ((uint8_t *)v) + sizeof(*v); +- rc = pgpPrtSigParams(tag, v->pubkey_algo, v->sigtype, p, h, hlen, _digp); ++ rc = pgpPrtSigParams(tag, v->pubkey_algo, p, h, hlen, _digp); + } break; + case 4: + { pgpPktSigV4 v = (pgpPktSigV4)h; +@@ -658,7 +656,7 @@ static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen, + if (p > (h + hlen)) + return 1; + +- rc = pgpPrtSigParams(tag, v->pubkey_algo, v->sigtype, p, h, hlen, _digp); ++ rc = pgpPrtSigParams(tag, v->pubkey_algo, p, h, hlen, _digp); + } break; + default: + rpmlog(RPMLOG_WARNING, _("Unsupported version of key: V%d\n"), version); diff --git a/meta/recipes-devtools/rpm/files/CVE-2021-3521-02.patch b/meta/recipes-devtools/rpm/files/CVE-2021-3521-02.patch new file mode 100644 index 0000000000..c5f88a8c72 --- /dev/null +++ b/meta/recipes-devtools/rpm/files/CVE-2021-3521-02.patch @@ -0,0 +1,55 @@ +From 9f03f42e2614a68f589f9db8fe76287146522c0c Mon Sep 17 00:00:00 2001 +From: Panu Matilainen <pmatilai@redhat.com> +Date: Thu, 30 Sep 2021 09:56:20 +0300 +Subject: [PATCH] Refactor pgpDigParams construction to helper function + +No functional changes, just to reduce code duplication and needed by +the following commits. + +Dependent patch: +CVE: CVE-2021-3521 +Upstream-Status: Backport [https://github.com/rpm-software-management/rpm/commit/9f03f42e2614a68f589f9db8fe76287146522c0c] +Signed-off-by: Riyaz Khan <Riyaz.Khan@kpit.com> + +--- + rpmio/rpmpgp.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/rpmio/rpmpgp.c b/rpmio/rpmpgp.c +index 340de5fc9a..aad7c275c9 100644 +--- a/rpmio/rpmpgp.c ++++ b/rpmio/rpmpgp.c +@@ -1055,6 +1055,13 @@ unsigned int pgpDigParamsAlgo(pgpDigParams digp, unsigned int algotype) + return algo; + } + ++static pgpDigParams pgpDigParamsNew(uint8_t tag) ++{ ++ pgpDigParams digp = xcalloc(1, sizeof(*digp)); ++ digp->tag = tag; ++ return digp; ++} ++ + int pgpPrtParams(const uint8_t * pkts, size_t pktlen, unsigned int pkttype, + pgpDigParams * ret) + { +@@ -1072,8 +1079,7 @@ int pgpPrtParams(const uint8_t * pkts, size_t pktlen, unsigned int pkttype, + if (pkttype && pkt.tag != pkttype) { + break; + } else { +- digp = xcalloc(1, sizeof(*digp)); +- digp->tag = pkt.tag; ++ digp = pgpDigParamsNew(pkt.tag); + } + } + +@@ -1121,8 +1127,7 @@ int pgpPrtParamsSubkeys(const uint8_t *pkts, size_t pktlen, + digps = xrealloc(digps, alloced * sizeof(*digps)); + } + +- digps[count] = xcalloc(1, sizeof(**digps)); +- digps[count]->tag = PGPTAG_PUBLIC_SUBKEY; ++ digps[count] = pgpDigParamsNew(PGPTAG_PUBLIC_SUBKEY); + /* Copy UID from main key to subkey */ + digps[count]->userid = xstrdup(mainkey->userid); + diff --git a/meta/recipes-devtools/rpm/files/CVE-2021-3521-03.patch b/meta/recipes-devtools/rpm/files/CVE-2021-3521-03.patch new file mode 100644 index 0000000000..fd31f11beb --- /dev/null +++ b/meta/recipes-devtools/rpm/files/CVE-2021-3521-03.patch @@ -0,0 +1,34 @@ +From 5ff86764b17f31535cb247543a90dd739076ec38 Mon Sep 17 00:00:00 2001 +From: Demi Marie Obenour <demi@invisiblethingslab.com> +Date: Thu, 6 May 2021 18:34:45 -0400 +Subject: [PATCH] Do not allow extra packets to follow a signature +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +According to RFC 4880 § 11.4, a detached signature is “simply a +Signature packet”. Therefore, extra packets following a detached +signature are not allowed. + +Dependent patch: +CVE: CVE-2021-3521 +Upstream-Status: Backport [https://github.com/rpm-software-management/rpm/commit/5ff86764b17f31535cb247543a90dd739076ec38] +Signed-off-by: Riyaz Khan <Riyaz.Khan@kpit.com> + +--- + rpmio/rpmpgp.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/rpmio/rpmpgp.c b/rpmio/rpmpgp.c +index f1a99e7169..5b346a8253 100644 +--- a/rpmio/rpmpgp.c ++++ b/rpmio/rpmpgp.c +@@ -1068,6 +1068,8 @@ int pgpPrtParams(const uint8_t * pkts, size_t pktlen, unsigned int pkttype, + break; + + p += (pkt.body - pkt.head) + pkt.blen; ++ if (pkttype == PGPTAG_SIGNATURE) ++ break; + } + + rc = (digp && (p == pend)) ? 0 : -1; diff --git a/meta/recipes-devtools/rpm/files/CVE-2021-3521.patch b/meta/recipes-devtools/rpm/files/CVE-2021-3521.patch new file mode 100644 index 0000000000..cb9e9842fe --- /dev/null +++ b/meta/recipes-devtools/rpm/files/CVE-2021-3521.patch @@ -0,0 +1,330 @@ +From bd36c5dc9fb6d90c46fbfed8c2d67516fc571ec8 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen <pmatilai@redhat.com> +Date: Thu, 30 Sep 2021 09:59:30 +0300 +Subject: [PATCH] Validate and require subkey binding signatures on PGP public + keys + +All subkeys must be followed by a binding signature by the primary key +as per the OpenPGP RFC, enforce the presence and validity in the parser. + +The implementation is as kludgey as they come to work around our +simple-minded parser structure without touching API, to maximise +backportability. Store all the raw packets internally as we decode them +to be able to access previous elements at will, needed to validate ordering +and access the actual data. Add testcases for manipulated keys whose +import previously would succeed. + +Depends on the two previous commits: +7b399fcb8f52566e6f3b4327197a85facd08db91 and +236b802a4aa48711823a191d1b7f753c82a89ec5 + +CVE: CVE-2021-3521 +Upstream-Status: Backport [https://github.com/rpm-software-management/rpm/commit/bd36c5dc9fb6d90c46fbfed8c2d67516fc571ec8] +Comment: Hunk refreshed +Signed-off-by: Riyaz Khan <Riyaz.Khan@kpit.com> + +Fixes CVE-2021-3521. +--- + rpmio/rpmpgp.c | 98 +++++++++++++++++-- + tests/Makefile.am | 3 + + tests/data/keys/CVE-2021-3521-badbind.asc | 25 +++++ + .../data/keys/CVE-2021-3521-nosubsig-last.asc | 25 +++++ + tests/data/keys/CVE-2021-3521-nosubsig.asc | 37 +++++++ + tests/rpmsigdig.at | 28 ++++++ + 6 files changed, 209 insertions(+), 7 deletions(-) + create mode 100644 tests/data/keys/CVE-2021-3521-badbind.asc + create mode 100644 tests/data/keys/CVE-2021-3521-nosubsig-last.asc + create mode 100644 tests/data/keys/CVE-2021-3521-nosubsig.asc + +diff --git a/rpmio/rpmpgp.c b/rpmio/rpmpgp.c +index aad7c275c9..d70802ae86 100644 +--- a/rpmio/rpmpgp.c ++++ b/rpmio/rpmpgp.c +@@ -1004,37 +1004,121 @@ static pgpDigParams pgpDigParamsNew(uint8_t tag) + return digp; + } + ++static int hashKey(DIGEST_CTX hash, const struct pgpPkt *pkt, int exptag) ++{ ++ int rc = -1; ++ if (pkt->tag == exptag) { ++ uint8_t head[] = { ++ 0x99, ++ (pkt->blen >> 8), ++ (pkt->blen ), ++ }; ++ ++ rpmDigestUpdate(hash, head, 3); ++ rpmDigestUpdate(hash, pkt->body, pkt->blen); ++ rc = 0; ++ } ++ return rc; ++} ++ ++static int pgpVerifySelf(pgpDigParams key, pgpDigParams selfsig, ++ const struct pgpPkt *all, int i) ++{ ++ int rc = -1; ++ DIGEST_CTX hash = NULL; ++ ++ switch (selfsig->sigtype) { ++ case PGPSIGTYPE_SUBKEY_BINDING: ++ hash = rpmDigestInit(selfsig->hash_algo, 0); ++ if (hash) { ++ rc = hashKey(hash, &all[0], PGPTAG_PUBLIC_KEY); ++ if (!rc) ++ rc = hashKey(hash, &all[i-1], PGPTAG_PUBLIC_SUBKEY); ++ } ++ break; ++ default: ++ /* ignore types we can't handle */ ++ rc = 0; ++ break; ++ } ++ ++ if (hash && rc == 0) ++ rc = pgpVerifySignature(key, selfsig, hash); ++ ++ rpmDigestFinal(hash, NULL, NULL, 0); ++ ++ return rc; ++} ++ + int pgpPrtParams(const uint8_t * pkts, size_t pktlen, unsigned int pkttype, + pgpDigParams * ret) + { + const uint8_t *p = pkts; + const uint8_t *pend = pkts + pktlen; + pgpDigParams digp = NULL; +- struct pgpPkt pkt; ++ pgpDigParams selfsig = NULL; ++ int i = 0; ++ int alloced = 16; /* plenty for normal cases */ ++ struct pgpPkt *all = xmalloc(alloced * sizeof(*all)); + int rc = -1; /* assume failure */ ++ int expect = 0; ++ int prevtag = 0; + + while (p < pend) { +- if (decodePkt(p, (pend - p), &pkt)) ++ struct pgpPkt *pkt = &all[i]; ++ if (decodePkt(p, (pend - p), pkt)) + break; + + if (digp == NULL) { +- if (pkttype && pkt.tag != pkttype) { ++ if (pkttype && pkt->tag != pkttype) { + break; + } else { +- digp = pgpDigParamsNew(pkt.tag); ++ digp = pgpDigParamsNew(pkt->tag); + } + } + +- if (pgpPrtPkt(&pkt, digp)) ++ if (expect) { ++ if (pkt->tag != expect) ++ break; ++ selfsig = pgpDigParamsNew(pkt->tag); ++ } ++ ++ if (pgpPrtPkt(pkt, selfsig ? selfsig : digp)) + break; + +- p += (pkt.body - pkt.head) + pkt.blen; ++ if (selfsig) { ++ /* subkeys must be followed by binding signature */ ++ if (prevtag == PGPTAG_PUBLIC_SUBKEY) { ++ if (selfsig->sigtype != PGPSIGTYPE_SUBKEY_BINDING) ++ break; ++ } ++ ++ int xx = pgpVerifySelf(digp, selfsig, all, i); ++ ++ selfsig = pgpDigParamsFree(selfsig); ++ if (xx) ++ break; ++ expect = 0; ++ } ++ ++ if (pkt->tag == PGPTAG_PUBLIC_SUBKEY) ++ expect = PGPTAG_SIGNATURE; ++ prevtag = pkt->tag; ++ ++ i++; ++ p += (pkt->body - pkt->head) + pkt->blen; + if (pkttype == PGPTAG_SIGNATURE) + break; ++ ++ if (alloced <= i) { ++ alloced *= 2; ++ all = xrealloc(all, alloced * sizeof(*all)); ++ } + } + +- rc = (digp && (p == pend)) ? 0 : -1; ++ rc = (digp && (p == pend) && expect == 0) ? 0 : -1; + ++ free(all); + if (ret && rc == 0) { + *ret = digp; + } else { +diff --git a/tests/Makefile.am b/tests/Makefile.am +index b4a2e2e1ce..bc535d2833 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -87,6 +87,9 @@ EXTRA_DIST += data/SPECS/hello-config-buildid.spec + EXTRA_DIST += data/SPECS/hello-cd.spec + EXTRA_DIST += data/keys/rpm.org-rsa-2048-test.pub + EXTRA_DIST += data/keys/rpm.org-rsa-2048-test.secret ++EXTRA_DIST += data/keys/CVE-2021-3521-badbind.asc ++EXTRA_DIST += data/keys/CVE-2021-3521-nosubsig.asc ++EXTRA_DIST += data/keys/CVE-2021-3521-nosubsig-last.asc + EXTRA_DIST += data/macros.testfile + + # testsuite voodoo +diff --git a/tests/data/keys/CVE-2021-3521-badbind.asc b/tests/data/keys/CVE-2021-3521-badbind.asc +new file mode 100644 +index 0000000000..aea00f9d7a +--- /dev/null ++++ b/tests/data/keys/CVE-2021-3521-badbind.asc +@@ -0,0 +1,25 @@ ++-----BEGIN PGP PUBLIC KEY BLOCK----- ++Version: rpm-4.17.90 (NSS-3) ++ ++mQENBFjmORgBCAC7TMEk6wnjSs8Dr4yqSScWdU2pjcqrkTxuzdWvowcIUPZI0w/g ++HkRqGd4apjvY2V15kjL10gk3QhFP3pZ/9p7zh8o8NHX7aGdSGDK7NOq1eFaErPRY ++91LW9RiZ0lbOjXEzIL0KHxUiTQEmdXJT43DJMFPyW9fkCWg0OltiX618FUdWWfI8 ++eySdLur1utnqBvdEbCUvWK2RX3vQZQdvEBODnNk2pxqTyV0w6VPQ96W++lF/5Aas ++7rUv3HIyIXxIggc8FRrnH+y9XvvHDonhTIlGnYZN4ubm9i4y3gOkrZlGTrEw7elQ ++1QeMyG2QQEbze8YjpTm4iLABCBrRfPRaQpwrABEBAAG0IXJwbS5vcmcgUlNBIHRl ++c3RrZXkgPHJzYUBycG0ub3JnPokBNwQTAQgAIQUCWOY5GAIbAwULCQgHAgYVCAkK ++CwIEFgIDAQIeAQIXgAAKCRBDRFkeGWTF/MxxCACnjqFL+MmPh9W9JQKT2DcLbBzf ++Cqo6wcEBoCOcwgRSk8dSikhARoteoa55JRJhuMyeKhhEAogE9HRmCPFdjezFTwgB ++BDVBpO2dZ023mLXDVCYX3S8pShOgCP6Tn4wqCnYeAdLcGg106N4xcmgtcssJE+Pr ++XzTZksbZsrTVEmL/Ym+R5w5jBfFnGk7Yw7ndwfQsfNXQb5AZynClFxnX546lcyZX ++fEx3/e6ezw57WNOUK6WT+8b+EGovPkbetK/rGxNXuWaP6X4A/QUm8O98nCuHYFQq +++mvNdsCBqGf7mhaRGtpHk/JgCn5rFvArMDqLVrR9hX0LdCSsH7EGE+bR3r7wuQEN ++BFjmORgBCACk+vDZrIXQuFXEYToZVwb2attzbbJJCqD71vmZTLsW0QxuPKRgbcYY ++zp4K4lVBnHhFrF8MOUOxJ7kQWIJZMZFt+BDcptCYurbD2H4W2xvnWViiC+LzCMzz ++iMJT6165uefL4JHTDPxC2fFiM9yrc72LmylJNkM/vepT128J5Qv0gRUaQbHiQuS6 ++Dm/+WRnUfx3i89SV4mnBxb/Ta93GVqoOciWwzWSnwEnWYAvOb95JL4U7c5J5f/+c ++KnQDHsW7sIiIdscsWzvgf6qs2Ra1Zrt7Fdk4+ZS2f/adagLhDO1C24sXf5XfMk5m ++L0OGwZSr9m5s17VXxfspgU5ugc8kBJfzABEBAAE= ++=WCfs ++-----END PGP PUBLIC KEY BLOCK----- ++ +diff --git a/tests/data/keys/CVE-2021-3521-nosubsig-last.asc b/tests/data/keys/CVE-2021-3521-nosubsig-last.asc +new file mode 100644 +index 0000000000..aea00f9d7a +--- /dev/null ++++ b/tests/data/keys/CVE-2021-3521-nosubsig-last.asc +@@ -0,0 +1,25 @@ ++-----BEGIN PGP PUBLIC KEY BLOCK----- ++Version: rpm-4.17.90 (NSS-3) ++ ++mQENBFjmORgBCAC7TMEk6wnjSs8Dr4yqSScWdU2pjcqrkTxuzdWvowcIUPZI0w/g ++HkRqGd4apjvY2V15kjL10gk3QhFP3pZ/9p7zh8o8NHX7aGdSGDK7NOq1eFaErPRY ++91LW9RiZ0lbOjXEzIL0KHxUiTQEmdXJT43DJMFPyW9fkCWg0OltiX618FUdWWfI8 ++eySdLur1utnqBvdEbCUvWK2RX3vQZQdvEBODnNk2pxqTyV0w6VPQ96W++lF/5Aas ++7rUv3HIyIXxIggc8FRrnH+y9XvvHDonhTIlGnYZN4ubm9i4y3gOkrZlGTrEw7elQ ++1QeMyG2QQEbze8YjpTm4iLABCBrRfPRaQpwrABEBAAG0IXJwbS5vcmcgUlNBIHRl ++c3RrZXkgPHJzYUBycG0ub3JnPokBNwQTAQgAIQUCWOY5GAIbAwULCQgHAgYVCAkK ++CwIEFgIDAQIeAQIXgAAKCRBDRFkeGWTF/MxxCACnjqFL+MmPh9W9JQKT2DcLbBzf ++Cqo6wcEBoCOcwgRSk8dSikhARoteoa55JRJhuMyeKhhEAogE9HRmCPFdjezFTwgB ++BDVBpO2dZ023mLXDVCYX3S8pShOgCP6Tn4wqCnYeAdLcGg106N4xcmgtcssJE+Pr ++XzTZksbZsrTVEmL/Ym+R5w5jBfFnGk7Yw7ndwfQsfNXQb5AZynClFxnX546lcyZX ++fEx3/e6ezw57WNOUK6WT+8b+EGovPkbetK/rGxNXuWaP6X4A/QUm8O98nCuHYFQq +++mvNdsCBqGf7mhaRGtpHk/JgCn5rFvArMDqLVrR9hX0LdCSsH7EGE+bR3r7wuQEN ++BFjmORgBCACk+vDZrIXQuFXEYToZVwb2attzbbJJCqD71vmZTLsW0QxuPKRgbcYY ++zp4K4lVBnHhFrF8MOUOxJ7kQWIJZMZFt+BDcptCYurbD2H4W2xvnWViiC+LzCMzz ++iMJT6165uefL4JHTDPxC2fFiM9yrc72LmylJNkM/vepT128J5Qv0gRUaQbHiQuS6 ++Dm/+WRnUfx3i89SV4mnBxb/Ta93GVqoOciWwzWSnwEnWYAvOb95JL4U7c5J5f/+c ++KnQDHsW7sIiIdscsWzvgf6qs2Ra1Zrt7Fdk4+ZS2f/adagLhDO1C24sXf5XfMk5m ++L0OGwZSr9m5s17VXxfspgU5ugc8kBJfzABEBAAE= ++=WCfs ++-----END PGP PUBLIC KEY BLOCK----- ++ +diff --git a/tests/data/keys/CVE-2021-3521-nosubsig.asc b/tests/data/keys/CVE-2021-3521-nosubsig.asc +new file mode 100644 +index 0000000000..3a2e7417f8 +--- /dev/null ++++ b/tests/data/keys/CVE-2021-3521-nosubsig.asc +@@ -0,0 +1,37 @@ ++-----BEGIN PGP PUBLIC KEY BLOCK----- ++Version: rpm-4.17.90 (NSS-3) ++ ++mQENBFjmORgBCAC7TMEk6wnjSs8Dr4yqSScWdU2pjcqrkTxuzdWvowcIUPZI0w/g ++HkRqGd4apjvY2V15kjL10gk3QhFP3pZ/9p7zh8o8NHX7aGdSGDK7NOq1eFaErPRY ++91LW9RiZ0lbOjXEzIL0KHxUiTQEmdXJT43DJMFPyW9fkCWg0OltiX618FUdWWfI8 ++eySdLur1utnqBvdEbCUvWK2RX3vQZQdvEBODnNk2pxqTyV0w6VPQ96W++lF/5Aas ++7rUv3HIyIXxIggc8FRrnH+y9XvvHDonhTIlGnYZN4ubm9i4y3gOkrZlGTrEw7elQ ++1QeMyG2QQEbze8YjpTm4iLABCBrRfPRaQpwrABEBAAG0IXJwbS5vcmcgUlNBIHRl ++c3RrZXkgPHJzYUBycG0ub3JnPokBNwQTAQgAIQUCWOY5GAIbAwULCQgHAgYVCAkK ++CwIEFgIDAQIeAQIXgAAKCRBDRFkeGWTF/MxxCACnjqFL+MmPh9W9JQKT2DcLbBzf ++Cqo6wcEBoCOcwgRSk8dSikhARoteoa55JRJhuMyeKhhEAogE9HRmCPFdjezFTwgB ++BDVBpO2dZ023mLXDVCYX3S8pShOgCP6Tn4wqCnYeAdLcGg106N4xcmgtcssJE+Pr ++XzTZksbZsrTVEmL/Ym+R5w5jBfFnGk7Yw7ndwfQsfNXQb5AZynClFxnX546lcyZX ++fEx3/e6ezw57WNOUK6WT+8b+EGovPkbetK/rGxNXuWaP6X4A/QUm8O98nCuHYFQq +++mvNdsCBqGf7mhaRGtpHk/JgCn5rFvArMDqLVrR9hX0LdCSsH7EGE+bR3r7wuQEN ++BFjmORgBCACk+vDZrIXQuFXEYToZVwb2attzbbJJCqD71vmZTLsW0QxuPKRgbcYY ++zp4K4lVBnHhFrF8MOUOxJ7kQWIJZMZFt+BDcptCYurbD2H4W2xvnWViiC+LzCMzz ++iMJT6165uefL4JHTDPxC2fFiM9yrc72LmylJNkM/vepT128J5Qv0gRUaQbHiQuS6 ++Dm/+WRnUfx3i89SV4mnBxb/Ta93GVqoOciWwzWSnwEnWYAvOb95JL4U7c5J5f/+c ++KnQDHsW7sIiIdscsWzvgf6qs2Ra1Zrt7Fdk4+ZS2f/adagLhDO1C24sXf5XfMk5m ++L0OGwZSr9m5s17VXxfspgU5ugc8kBJfzABEBAAG5AQ0EWOY5GAEIAKT68NmshdC4 ++VcRhOhlXBvZq23NtskkKoPvW+ZlMuxbRDG48pGBtxhjOngriVUGceEWsXww5Q7En ++uRBYglkxkW34ENym0Ji6tsPYfhbbG+dZWKIL4vMIzPOIwlPrXrm558vgkdMM/ELZ ++8WIz3KtzvYubKUk2Qz+96lPXbwnlC/SBFRpBseJC5LoOb/5ZGdR/HeLz1JXiacHF ++v9Nr3cZWqg5yJbDNZKfASdZgC85v3kkvhTtzknl//5wqdAMexbuwiIh2xyxbO+B/ ++qqzZFrVmu3sV2Tj5lLZ/9p1qAuEM7ULbixd/ld8yTmYvQ4bBlKv2bmzXtVfF+ymB ++Tm6BzyQEl/MAEQEAAYkBHwQYAQgACQUCWOY5GAIbDAAKCRBDRFkeGWTF/PANB/9j ++mifmj6z/EPe0PJFhrpISt9PjiUQCt0IPtiL5zKAkWjHePIzyi+0kCTBF6DDLFxos ++3vN4bWnVKT1kBhZAQlPqpJTg+m74JUYeDGCdNx9SK7oRllATqyu+5rncgxjWVPnQ ++zu/HRPlWJwcVFYEVXYL8xzfantwQTqefjmcRmBRdA2XJITK+hGWwAmrqAWx+q5xX ++Pa8wkNMxVzNS2rUKO9SoVuJ/wlUvfoShkJ/VJ5HDp3qzUqncADfdGN35TDzscngQ ++gHvnMwVBfYfSCABV1hNByoZcc/kxkrWMmsd/EnIyLd1Q1baKqc3cEDuC6E6/o4yJ ++E4XX4jtDmdZPreZALsiB ++=rRop ++-----END PGP PUBLIC KEY BLOCK----- ++ +diff --git a/tests/rpmsigdig.at b/tests/rpmsigdig.at +index 0f8f2b4884..c8b9f139e1 100644 +--- a/tests/rpmsigdig.at ++++ b/tests/rpmsigdig.at +@@ -240,6 +240,34 @@ gpg(185e6146f00650f8) = 4:185e6146f00650f8-58e63918 + []) + AT_CLEANUP + ++AT_SETUP([rpmkeys --import invalid keys]) ++AT_KEYWORDS([rpmkeys import]) ++RPMDB_INIT ++ ++AT_CHECK([ ++runroot rpmkeys --import /data/keys/CVE-2021-3521-badbind.asc ++], ++[1], ++[], ++[error: /data/keys/CVE-2021-3521-badbind.asc: key 1 import failed.] ++) ++AT_CHECK([ ++runroot rpmkeys --import /data/keys/CVE-2021-3521-nosubsig.asc ++], ++[1], ++[], ++[error: /data/keys/CVE-2021-3521-nosubsig.asc: key 1 import failed.] ++) ++ ++AT_CHECK([ ++runroot rpmkeys --import /data/keys/CVE-2021-3521-nosubsig-last.asc ++], ++[1], ++[], ++[error: /data/keys/CVE-2021-3521-nosubsig-last.asc: key 1 import failed.] ++) ++AT_CLEANUP ++ + # ------------------------------ + # Test pre-built package verification + AT_SETUP([rpmkeys -K <signed> 1]) + diff --git a/meta/recipes-devtools/rpm/rpm_4.14.2.1.bb b/meta/recipes-devtools/rpm/rpm_4.14.2.1.bb index 018b2f8700..4d605c8501 100644 --- a/meta/recipes-devtools/rpm/rpm_4.14.2.1.bb +++ b/meta/recipes-devtools/rpm/rpm_4.14.2.1.bb @@ -24,7 +24,7 @@ HOMEPAGE = "http://www.rpm.org" LICENSE = "GPL-2.0" LIC_FILES_CHKSUM = "file://COPYING;md5=c0bf017c0fd1920e6158a333acabfd4a" -SRC_URI = "git://github.com/rpm-software-management/rpm;branch=rpm-4.14.x \ +SRC_URI = "git://github.com/rpm-software-management/rpm;branch=rpm-4.14.x;protocol=https \ file://0001-Do-not-add-an-unsatisfiable-dependency-when-building.patch \ file://0001-Do-not-read-config-files-from-HOME.patch \ file://0001-When-cross-installing-execute-package-scriptlets-wit.patch \ @@ -44,7 +44,13 @@ SRC_URI = "git://github.com/rpm-software-management/rpm;branch=rpm-4.14.x \ file://0001-mono-find-provides-requires-do-not-use-monodis-from-.patch \ file://0001-Rip-out-partial-support-for-unused-MD2-and-RIPEMD160.patch \ file://0001-rpmplugins.c-call-dlerror-prior-to-dlsym.patch \ + file://0001-rpmio-Fix-lzopen_internal-mode-parsing-when-Tn-is-us.patch \ file://CVE-2021-3421.patch \ + file://CVE-2021-20266.patch \ + file://CVE-2021-3521-01.patch \ + file://CVE-2021-3521-02.patch \ + file://CVE-2021-3521-03.patch \ + file://CVE-2021-3521.patch \ " PE = "1" @@ -61,7 +67,8 @@ export PYTHON_ABI # OE-core patches autoreconf to additionally run gnu-configize, which fails with this recipe EXTRA_AUTORECONF_append = " --exclude=gnu-configize" -EXTRA_OECONF_append = " --without-lua --enable-python --with-crypto=openssl" +# Vendor is detected differently on x86 and aarch64 hosts and can feed into target packages +EXTRA_OECONF_append = " --without-lua --enable-python --with-crypto=openssl --with-vendor=pc" EXTRA_OECONF_append_libc-musl = " --disable-nls" # --sysconfdir prevents rpm from attempting to access machine-specific configuration in sysroot/etc; we need to have it in rootfs diff --git a/meta/recipes-devtools/rsync/files/0001-Fix-relative-when-copying-an-absolute-path.patch b/meta/recipes-devtools/rsync/files/0001-Fix-relative-when-copying-an-absolute-path.patch new file mode 100644 index 0000000000..b2e02dba97 --- /dev/null +++ b/meta/recipes-devtools/rsync/files/0001-Fix-relative-when-copying-an-absolute-path.patch @@ -0,0 +1,31 @@ +From fabef23bea6e9963c06e218586fda1a823e3c6bf Mon Sep 17 00:00:00 2001 +From: Wayne Davison <wayne@opencoder.net> +Date: Mon, 8 Aug 2022 21:30:21 -0700 +Subject: [PATCH] Fix --relative when copying an absolute path. + +CVE: CVE-2022-29154 +Upstream-Status: Backport [https://github.com/WayneD/rsync/commit/fabef23bea6e9963c06e218586fda1a823e3c6bf] +Signed-off-by: Matthias Schmitz <matthias.schmitz@port4949.net> +--- + exclude.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/exclude.c b/exclude.c +index 2394023f..ba5ca5a3 100644 +--- a/exclude.c ++++ b/exclude.c +@@ -434,8 +434,10 @@ void add_implied_include(const char *arg) + *p++ = *cp++; + break; + case '/': +- if (p[-1] == '/') /* This is safe because of the initial slash. */ ++ if (p[-1] == '/') { /* This is safe because of the initial slash. */ ++ cp++; + break; ++ } + if (relative_paths) { + filter_rule const *ent; + int found = 0; +-- +2.39.2 + diff --git a/meta/recipes-devtools/rsync/files/CVE-2022-29154.patch b/meta/recipes-devtools/rsync/files/CVE-2022-29154.patch new file mode 100644 index 0000000000..61e4e03254 --- /dev/null +++ b/meta/recipes-devtools/rsync/files/CVE-2022-29154.patch @@ -0,0 +1,334 @@ +From b7231c7d02cfb65d291af74ff66e7d8c507ee871 Mon Sep 17 00:00:00 2001 +From: Wayne Davison <wayne@opencoder.net> +Date: Sun, 31 Jul 2022 16:55:34 -0700 +Subject: [PATCH] Some extra file-list safety checks. + +CVE-2022-29154 rsync: remote arbitrary files write inside the + +Upstream-Status: Backport from [https://git.samba.org/?p=rsync.git;a=patch;h=b7231c7d02cfb65d291af74ff66e7d8c507ee871] +CVE:CVE-2022-29154 +Signed-off-by: Vivek Kumbhar <vkumbhar@mvista.com> +--- + exclude.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++++- + flist.c | 17 ++++++- + io.c | 4 ++ + main.c | 7 ++- + receiver.c | 11 +++-- + 5 files changed, 158 insertions(+), 8 deletions(-) + +diff --git a/exclude.c b/exclude.c +index 7989fb3..e146e96 100644 +--- a/exclude.c ++++ b/exclude.c +@@ -26,16 +26,21 @@ extern int am_server; + extern int am_sender; + extern int eol_nulls; + extern int io_error; ++extern int xfer_dirs; ++extern int recurse; + extern int local_server; + extern int prune_empty_dirs; + extern int ignore_perishable; ++extern int relative_paths; + extern int delete_mode; + extern int delete_excluded; + extern int cvs_exclude; + extern int sanitize_paths; + extern int protocol_version; ++extern int list_only; + extern int module_id; + ++extern char *filesfrom_host; + extern char curr_dir[MAXPATHLEN]; + extern unsigned int curr_dir_len; + extern unsigned int module_dirlen; +@@ -43,8 +48,10 @@ extern unsigned int module_dirlen; + filter_rule_list filter_list = { .debug_type = "" }; + filter_rule_list cvs_filter_list = { .debug_type = " [global CVS]" }; + filter_rule_list daemon_filter_list = { .debug_type = " [daemon]" }; ++filter_rule_list implied_filter_list = { .debug_type = " [implied]" }; + + int saw_xattr_filter = 0; ++int trust_sender_filter = 0; + + /* Need room enough for ":MODS " prefix plus some room to grow. */ + #define MAX_RULE_PREFIX (16) +@@ -293,6 +300,123 @@ static void add_rule(filter_rule_list *listp, const char *pat, unsigned int pat_ + } + } + ++/* Each arg the client sends to the remote sender turns into an implied include ++ * that the receiver uses to validate the file list from the sender. */ ++void add_implied_include(const char *arg) ++{ ++ filter_rule *rule; ++ int arg_len, saw_wild = 0, backslash_cnt = 0; ++ int slash_cnt = 1; /* We know we're adding a leading slash. */ ++ const char *cp; ++ char *p; ++ if (relative_paths) { ++ cp = strstr(arg, "/./"); ++ if (cp) ++ arg = cp+3; ++ } else { ++ if ((cp = strrchr(arg, '/')) != NULL) ++ arg = cp + 1; ++ } ++ arg_len = strlen(arg); ++ if (arg_len) { ++ if (strpbrk(arg, "*[?")) { ++ /* We need to add room to escape backslashes if wildcard chars are present. */ ++ cp = arg; ++ while ((cp = strchr(cp, '\\')) != NULL) { ++ arg_len++; ++ cp++; ++ } ++ saw_wild = 1; ++ } ++ arg_len++; /* Leave room for the prefixed slash */ ++ rule = new0(filter_rule); ++ if (!implied_filter_list.head) ++ implied_filter_list.head = implied_filter_list.tail = rule; ++ else { ++ rule->next = implied_filter_list.head; ++ implied_filter_list.head = rule; ++ } ++ rule->rflags = FILTRULE_INCLUDE + (saw_wild ? FILTRULE_WILD : 0); ++ p = rule->pattern = new_array(char, arg_len + 1); ++ *p++ = '/'; ++ cp = arg; ++ while (*cp) { ++ switch (*cp) { ++ case '\\': ++ backslash_cnt++; ++ if (saw_wild) ++ *p++ = '\\'; ++ *p++ = *cp++; ++ break; ++ case '/': ++ if (p[-1] == '/') /* This is safe because of the initial slash. */ ++ break; ++ if (relative_paths) { ++ filter_rule const *ent; ++ int found = 0; ++ *p = '\0'; ++ for (ent = implied_filter_list.head; ent; ent = ent->next) { ++ if (ent != rule && strcmp(ent->pattern, rule->pattern) == 0) ++ found = 1; ++ } ++ if (!found) { ++ filter_rule *R_rule = new0(filter_rule); ++ R_rule->rflags = FILTRULE_INCLUDE + (saw_wild ? FILTRULE_WILD : 0); ++ R_rule->pattern = strdup(rule->pattern); ++ R_rule->u.slash_cnt = slash_cnt; ++ R_rule->next = implied_filter_list.head; ++ implied_filter_list.head = R_rule; ++ } ++ } ++ slash_cnt++; ++ *p++ = *cp++; ++ break; ++ default: ++ *p++ = *cp++; ++ break; ++ } ++ } ++ *p = '\0'; ++ rule->u.slash_cnt = slash_cnt; ++ arg = (const char *)rule->pattern; ++ } ++ ++ if (recurse || xfer_dirs) { ++ /* Now create a rule with an added "/" & "**" or "*" at the end */ ++ rule = new0(filter_rule); ++ if (recurse) ++ rule->rflags = FILTRULE_INCLUDE | FILTRULE_WILD | FILTRULE_WILD2; ++ else ++ rule->rflags = FILTRULE_INCLUDE | FILTRULE_WILD; ++ /* A +4 in the len leaves enough room for / * * \0 or / * \0 \0 */ ++ if (!saw_wild && backslash_cnt) { ++ /* We are appending a wildcard, so now the backslashes need to be escaped. */ ++ p = rule->pattern = new_array(char, arg_len + backslash_cnt + 3 + 1); ++ cp = arg; ++ while (*cp) { ++ if (*cp == '\\') ++ *p++ = '\\'; ++ *p++ = *cp++; ++ } ++ } else { ++ p = rule->pattern = new_array(char, arg_len + 3 + 1); ++ if (arg_len) { ++ memcpy(p, arg, arg_len); ++ p += arg_len; ++ } ++ } ++ if (p[-1] != '/') ++ *p++ = '/'; ++ *p++ = '*'; ++ if (recurse) ++ *p++ = '*'; ++ *p = '\0'; ++ rule->u.slash_cnt = slash_cnt + 1; ++ rule->next = implied_filter_list.head; ++ implied_filter_list.head = rule; ++ } ++} ++ + /* This frees any non-inherited items, leaving just inherited items on the list. */ + static void pop_filter_list(filter_rule_list *listp) + { +@@ -721,7 +845,7 @@ static void report_filter_result(enum logcode code, char const *name, + : name_flags & NAME_IS_DIR ? "directory" + : "file"; + rprintf(code, "[%s] %sing %s %s because of pattern %s%s%s\n", +- w, actions[*w!='s'][!(ent->rflags & FILTRULE_INCLUDE)], ++ w, actions[*w=='g'][!(ent->rflags & FILTRULE_INCLUDE)], + t, name, ent->pattern, + ent->rflags & FILTRULE_DIRECTORY ? "/" : "", type); + } +@@ -894,6 +1018,7 @@ static filter_rule *parse_rule_tok(const char **rulestr_ptr, + } + switch (ch) { + case ':': ++ trust_sender_filter = 1; + rule->rflags |= FILTRULE_PERDIR_MERGE + | FILTRULE_FINISH_SETUP; + /* FALL THROUGH */ +diff --git a/flist.c b/flist.c +index 499440c..630d685 100644 +--- a/flist.c ++++ b/flist.c +@@ -70,6 +70,7 @@ extern int need_unsorted_flist; + extern int sender_symlink_iconv; + extern int output_needs_newline; + extern int sender_keeps_checksum; ++extern int trust_sender_filter; + extern int unsort_ndx; + extern uid_t our_uid; + extern struct stats stats; +@@ -80,8 +81,7 @@ extern char curr_dir[MAXPATHLEN]; + + extern struct chmod_mode_struct *chmod_modes; + +-extern filter_rule_list filter_list; +-extern filter_rule_list daemon_filter_list; ++extern filter_rule_list filter_list, implied_filter_list, daemon_filter_list; + + #ifdef ICONV_OPTION + extern int filesfrom_convert; +@@ -904,6 +904,19 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x + exit_cleanup(RERR_UNSUPPORTED); + } + ++ if (*thisname != '.' || thisname[1] != '\0') { ++ int filt_flags = S_ISDIR(mode) ? NAME_IS_DIR : NAME_IS_FILE; ++ if (!trust_sender_filter /* a per-dir filter rule means we must trust the sender's filtering */ ++ && filter_list.head && check_filter(&filter_list, FINFO, thisname, filt_flags) < 0) { ++ rprintf(FERROR, "ERROR: rejecting excluded file-list name: %s\n", thisname); ++ exit_cleanup(RERR_PROTOCOL); ++ } ++ if (implied_filter_list.head && check_filter(&implied_filter_list, FINFO, thisname, filt_flags) <= 0) { ++ rprintf(FERROR, "ERROR: rejecting unrequested file-list name: %s\n", thisname); ++ exit_cleanup(RERR_PROTOCOL); ++ } ++ } ++ + if (inc_recurse && S_ISDIR(mode)) { + if (one_file_system) { + /* Room to save the dir's device for -x */ +diff --git a/io.c b/io.c +index c04dbd5..698a7da 100644 +--- a/io.c ++++ b/io.c +@@ -415,6 +415,7 @@ static void forward_filesfrom_data(void) + while (s != eob) { + if (*s++ == '\0') { + ff_xb.len = s - sob - 1; ++ add_implied_include(sob); + if (iconvbufs(ic_send, &ff_xb, &iobuf.out, flags) < 0) + exit_cleanup(RERR_PROTOCOL); /* impossible? */ + write_buf(iobuf.out_fd, s-1, 1); /* Send the '\0'. */ +@@ -446,9 +447,12 @@ static void forward_filesfrom_data(void) + char *f = ff_xb.buf + ff_xb.pos; + char *t = ff_xb.buf; + char *eob = f + len; ++ char *cur = t; + /* Eliminate any multi-'\0' runs. */ + while (f != eob) { + if (!(*t++ = *f++)) { ++ add_implied_include(cur); ++ cur = t; + while (f != eob && *f == '\0') + f++; + } +diff --git a/main.c b/main.c +index ee9630f..6ec56e7 100644 +--- a/main.c ++++ b/main.c +@@ -78,6 +78,7 @@ extern BOOL flist_receiving_enabled; + extern BOOL shutting_down; + extern int backup_dir_len; + extern int basis_dir_cnt; ++extern int trust_sender_filter; + extern struct stats stats; + extern char *stdout_format; + extern char *logfile_format; +@@ -93,7 +94,7 @@ extern char curr_dir[MAXPATHLEN]; + extern char backup_dir_buf[MAXPATHLEN]; + extern char *basis_dir[MAX_BASIS_DIRS+1]; + extern struct file_list *first_flist; +-extern filter_rule_list daemon_filter_list; ++extern filter_rule_list daemon_filter_list, implied_filter_list; + + uid_t our_uid; + gid_t our_gid; +@@ -534,6 +535,7 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, in + #ifdef ICONV_CONST + setup_iconv(); + #endif ++ trust_sender_filter = 1; + } else if (local_server) { + /* If the user didn't request --[no-]whole-file, force + * it on, but only if we're not batch processing. */ +@@ -1358,6 +1360,8 @@ static int start_client(int argc, char *argv[]) + char *dummy_host; + int dummy_port = rsync_port; + int i; ++ if (filesfrom_fd < 0) ++ add_implied_include(remote_argv[0]); + /* For remote source, any extra source args must have either + * the same hostname or an empty hostname. */ + for (i = 1; i < remote_argc; i++) { +@@ -1381,6 +1385,7 @@ static int start_client(int argc, char *argv[]) + if (!rsync_port && !*arg) /* Turn an empty arg into a dot dir. */ + arg = "."; + remote_argv[i] = arg; ++ add_implied_include(arg); + } + } + +diff --git a/receiver.c b/receiver.c +index d6a48f1..c0aa893 100644 +--- a/receiver.c ++++ b/receiver.c +@@ -577,10 +577,13 @@ int recv_files(int f_in, int f_out, char *local_name) + if (DEBUG_GTE(RECV, 1)) + rprintf(FINFO, "recv_files(%s)\n", fname); + +- if (daemon_filter_list.head && (*fname != '.' || fname[1] != '\0') +- && check_filter(&daemon_filter_list, FLOG, fname, 0) < 0) { +- rprintf(FERROR, "attempt to hack rsync failed.\n"); +- exit_cleanup(RERR_PROTOCOL); ++ if (daemon_filter_list.head && (*fname != '.' || fname[1] != '\0')) { ++ int filt_flags = S_ISDIR(file->mode) ? NAME_IS_DIR : NAME_IS_FILE; ++ if (check_filter(&daemon_filter_list, FLOG, fname, filt_flags) < 0) { ++ rprintf(FERROR, "ERROR: rejecting file transfer request for daemon excluded file: %s\n", ++ fname); ++ exit_cleanup(RERR_PROTOCOL); ++ } + } + + #ifdef SUPPORT_XATTRS +-- +2.30.2 + diff --git a/meta/recipes-devtools/rsync/rsync_3.1.3.bb b/meta/recipes-devtools/rsync/rsync_3.1.3.bb index c743e3f75b..c744503227 100644 --- a/meta/recipes-devtools/rsync/rsync_3.1.3.bb +++ b/meta/recipes-devtools/rsync/rsync_3.1.3.bb @@ -16,6 +16,8 @@ SRC_URI = "https://download.samba.org/pub/${BPN}/src/${BP}.tar.gz \ file://CVE-2016-9841.patch \ file://CVE-2016-9842.patch \ file://CVE-2016-9843.patch \ + file://CVE-2022-29154.patch \ + file://0001-Fix-relative-when-copying-an-absolute-path.patch \ " SRC_URI[md5sum] = "1581a588fde9d89f6bc6201e8129afaf" diff --git a/meta/recipes-devtools/ruby/ruby.inc b/meta/recipes-devtools/ruby/ruby.inc index 7b6d4edc61..a9f4240932 100644 --- a/meta/recipes-devtools/ruby/ruby.inc +++ b/meta/recipes-devtools/ruby/ruby.inc @@ -14,8 +14,8 @@ LIC_FILES_CHKSUM = "\ file://LEGAL;md5=2b6d62dc0d608f34d510ca3f428110ec \ " -DEPENDS = "ruby-native zlib openssl libyaml gdbm readline libffi" -DEPENDS_class-native = "openssl-native libyaml-native readline-native zlib-native" +DEPENDS = "zlib openssl libyaml gdbm readline libffi" +DEPENDS_append_class-target = " ruby-native" SHRT_VER = "${@oe.utils.trim_version("${PV}", 2)}" SRC_URI = "http://cache.ruby-lang.org/pub/ruby/${SHRT_VER}/ruby-${PV}.tar.gz \ diff --git a/meta/recipes-devtools/ruby/ruby/CVE-2021-33621.patch b/meta/recipes-devtools/ruby/ruby/CVE-2021-33621.patch new file mode 100644 index 0000000000..cc2f9853db --- /dev/null +++ b/meta/recipes-devtools/ruby/ruby/CVE-2021-33621.patch @@ -0,0 +1,139 @@ +From 64c5045c0a6b84fdb938a8465a0890e5f7162708 Mon Sep 17 00:00:00 2001 +From: Yusuke Endoh <mame@ruby-lang.org> +Date: Tue, 22 Nov 2022 10:49:27 +0900 +Subject: [PATCH] Prevent CRLF injection + +Throw a RuntimeError if the HTTP response header contains CR or LF to +prevent HTTP response splitting. + +https://hackerone.com/reports/1204695 + +Upstream-Status: Backport [https://github.com/ruby/cgi/commit/64c5045c0a6b84fdb938a8465a0890e5f7162708] +CVE: CVE-2021-33621 +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> +--- + lib/cgi/core.rb | 45 +++++++++++++++++++++++-------------- + test/cgi/test_cgi_header.rb | 8 +++++++ + 2 files changed, 36 insertions(+), 17 deletions(-) + +diff --git a/lib/cgi/core.rb b/lib/cgi/core.rb +index bec76e0..62e6068 100644 +--- a/lib/cgi/core.rb ++++ b/lib/cgi/core.rb +@@ -188,17 +188,28 @@ class CGI + # Using #header with the HTML5 tag maker will create a <header> element. + alias :header :http_header + ++ def _no_crlf_check(str) ++ if str ++ str = str.to_s ++ raise "A HTTP status or header field must not include CR and LF" if str =~ /[\r\n]/ ++ str ++ else ++ nil ++ end ++ end ++ private :_no_crlf_check ++ + def _header_for_string(content_type) #:nodoc: + buf = ''.dup + if nph?() +- buf << "#{$CGI_ENV['SERVER_PROTOCOL'] || 'HTTP/1.0'} 200 OK#{EOL}" ++ buf << "#{_no_crlf_check($CGI_ENV['SERVER_PROTOCOL']) || 'HTTP/1.0'} 200 OK#{EOL}" + buf << "Date: #{CGI.rfc1123_date(Time.now)}#{EOL}" +- buf << "Server: #{$CGI_ENV['SERVER_SOFTWARE']}#{EOL}" ++ buf << "Server: #{_no_crlf_check($CGI_ENV['SERVER_SOFTWARE'])}#{EOL}" + buf << "Connection: close#{EOL}" + end +- buf << "Content-Type: #{content_type}#{EOL}" ++ buf << "Content-Type: #{_no_crlf_check(content_type)}#{EOL}" + if @output_cookies +- @output_cookies.each {|cookie| buf << "Set-Cookie: #{cookie}#{EOL}" } ++ @output_cookies.each {|cookie| buf << "Set-Cookie: #{_no_crlf_check(cookie)}#{EOL}" } + end + return buf + end # _header_for_string +@@ -213,9 +224,9 @@ class CGI + ## NPH + options.delete('nph') if defined?(MOD_RUBY) + if options.delete('nph') || nph?() +- protocol = $CGI_ENV['SERVER_PROTOCOL'] || 'HTTP/1.0' ++ protocol = _no_crlf_check($CGI_ENV['SERVER_PROTOCOL']) || 'HTTP/1.0' + status = options.delete('status') +- status = HTTP_STATUS[status] || status || '200 OK' ++ status = HTTP_STATUS[status] || _no_crlf_check(status) || '200 OK' + buf << "#{protocol} #{status}#{EOL}" + buf << "Date: #{CGI.rfc1123_date(Time.now)}#{EOL}" + options['server'] ||= $CGI_ENV['SERVER_SOFTWARE'] || '' +@@ -223,38 +234,38 @@ class CGI + end + ## common headers + status = options.delete('status') +- buf << "Status: #{HTTP_STATUS[status] || status}#{EOL}" if status ++ buf << "Status: #{HTTP_STATUS[status] || _no_crlf_check(status)}#{EOL}" if status + server = options.delete('server') +- buf << "Server: #{server}#{EOL}" if server ++ buf << "Server: #{_no_crlf_check(server)}#{EOL}" if server + connection = options.delete('connection') +- buf << "Connection: #{connection}#{EOL}" if connection ++ buf << "Connection: #{_no_crlf_check(connection)}#{EOL}" if connection + type = options.delete('type') +- buf << "Content-Type: #{type}#{EOL}" #if type ++ buf << "Content-Type: #{_no_crlf_check(type)}#{EOL}" #if type + length = options.delete('length') +- buf << "Content-Length: #{length}#{EOL}" if length ++ buf << "Content-Length: #{_no_crlf_check(length)}#{EOL}" if length + language = options.delete('language') +- buf << "Content-Language: #{language}#{EOL}" if language ++ buf << "Content-Language: #{_no_crlf_check(language)}#{EOL}" if language + expires = options.delete('expires') + buf << "Expires: #{CGI.rfc1123_date(expires)}#{EOL}" if expires + ## cookie + if cookie = options.delete('cookie') + case cookie + when String, Cookie +- buf << "Set-Cookie: #{cookie}#{EOL}" ++ buf << "Set-Cookie: #{_no_crlf_check(cookie)}#{EOL}" + when Array + arr = cookie +- arr.each {|c| buf << "Set-Cookie: #{c}#{EOL}" } ++ arr.each {|c| buf << "Set-Cookie: #{_no_crlf_check(c)}#{EOL}" } + when Hash + hash = cookie +- hash.each_value {|c| buf << "Set-Cookie: #{c}#{EOL}" } ++ hash.each_value {|c| buf << "Set-Cookie: #{_no_crlf_check(c)}#{EOL}" } + end + end + if @output_cookies +- @output_cookies.each {|c| buf << "Set-Cookie: #{c}#{EOL}" } ++ @output_cookies.each {|c| buf << "Set-Cookie: #{_no_crlf_check(c)}#{EOL}" } + end + ## other headers + options.each do |key, value| +- buf << "#{key}: #{value}#{EOL}" ++ buf << "#{_no_crlf_check(key)}: #{_no_crlf_check(value)}#{EOL}" + end + return buf + end # _header_for_hash +diff --git a/test/cgi/test_cgi_header.rb b/test/cgi/test_cgi_header.rb +index bab2d03..ec2f4de 100644 +--- a/test/cgi/test_cgi_header.rb ++++ b/test/cgi/test_cgi_header.rb +@@ -176,6 +176,14 @@ class CGIHeaderTest < Test::Unit::TestCase + end + + ++ def test_cgi_http_header_crlf_injection ++ cgi = CGI.new ++ assert_raise(RuntimeError) { cgi.http_header("text/xhtml\r\nBOO") } ++ assert_raise(RuntimeError) { cgi.http_header("type" => "text/xhtml\r\nBOO") } ++ assert_raise(RuntimeError) { cgi.http_header("status" => "200 OK\r\nBOO") } ++ assert_raise(RuntimeError) { cgi.http_header("location" => "text/xhtml\r\nBOO") } ++ end ++ + + instance_methods.each do |method| + private method if method =~ /^test_(.*)/ && $1 != ENV['TEST'] +-- +2.25.1 + diff --git a/meta/recipes-devtools/ruby/ruby/CVE-2023-28756.patch b/meta/recipes-devtools/ruby/ruby/CVE-2023-28756.patch new file mode 100644 index 0000000000..c25a147d36 --- /dev/null +++ b/meta/recipes-devtools/ruby/ruby/CVE-2023-28756.patch @@ -0,0 +1,61 @@ +From 957bb7cb81995f26c671afce0ee50a5c660e540e Mon Sep 17 00:00:00 2001 +From: Hiroshi SHIBATA <hsbt@ruby-lang.org> +Date: Wed, 29 Mar 2023 13:28:25 +0900 +Subject: [PATCH] CVE-2023-28756 + +CVE: CVE-2023-28756 +Upstream-Status: Backport [https://github.com/ruby/ruby/commit/957bb7cb81995f26c671afce0ee50a5c660e540e] + +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> +--- + lib/time.rb | 6 +++--- + test/test_time.rb | 9 +++++++++ + 2 files changed, 12 insertions(+), 3 deletions(-) + +diff --git a/lib/time.rb b/lib/time.rb +index f27bacd..4a86e8e 100644 +--- a/lib/time.rb ++++ b/lib/time.rb +@@ -501,8 +501,8 @@ class Time + (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+ + (\d{2,})\s+ + (\d{2})\s* +- :\s*(\d{2})\s* +- (?::\s*(\d{2}))?\s+ ++ :\s*(\d{2}) ++ (?:\s*:\s*(\d\d))?\s+ + ([+-]\d{4}| + UT|GMT|EST|EDT|CST|CDT|MST|MDT|PST|PDT|[A-IK-Z])/ix =~ date + # Since RFC 2822 permit comments, the regexp has no right anchor. +@@ -717,7 +717,7 @@ class Time + # + # If self is a UTC time, Z is used as TZD. [+-]hh:mm is used otherwise. + # +- # +fractional_digits+ specifies a number of digits to use for fractional ++ # +fraction_digits+ specifies a number of digits to use for fractional + # seconds. Its default value is 0. + # + # require 'time' +diff --git a/test/test_time.rb b/test/test_time.rb +index ca20788..4f11048 100644 +--- a/test/test_time.rb ++++ b/test/test_time.rb +@@ -62,6 +62,15 @@ class TestTimeExtension < Test::Unit::TestCase # :nodoc: + assert_equal(true, t.utc?) + end + ++ def test_rfc2822_nonlinear ++ pre = ->(n) {"0 Feb 00 00 :00" + " " * n} ++ assert_linear_performance([100, 500, 5000, 50_000], pre: pre) do |s| ++ assert_raise(ArgumentError) do ++ Time.rfc2822(s) ++ end ++ end ++ end ++ + def test_encode_rfc2822 + t = Time.utc(1) + assert_equal("Mon, 01 Jan 0001 00:00:00 -0000", t.rfc2822) +-- +2.25.1 + diff --git a/meta/recipes-devtools/ruby/ruby_2.7.3.bb b/meta/recipes-devtools/ruby/ruby_2.7.6.bb index 318b9acdae..7e6373bd24 100644 --- a/meta/recipes-devtools/ruby/ruby_2.7.3.bb +++ b/meta/recipes-devtools/ruby/ruby_2.7.6.bb @@ -7,10 +7,16 @@ SRC_URI += " \ file://run-ptest \ file://0001-Modify-shebang-of-libexec-y2racc-and-libexec-racc2y.patch \ file://0001-template-Makefile.in-do-not-write-host-cross-cc-item.patch \ + file://CVE-2023-28756.patch \ + file://CVE-2021-33621.patch \ " -SRC_URI[md5sum] = "72ef97685008981de3ddb748d0dab31f" -SRC_URI[sha256sum] = "8925a95e31d8f2c81749025a52a544ea1d05dad18794e6828709268b92e55338" +SRC_URI[md5sum] = "f972fb0cce662966bec10d5c5f32d042" +SRC_URI[sha256sum] = "e7203b0cc09442ed2c08936d483f8ac140ec1c72e37bb5c401646b7866cb5d10" + +# CVE-2021-28966 is Windows specific and not affects Linux OS +# https://security-tracker.debian.org/tracker/CVE-2021-28966 +CVE_CHECK_WHITELIST += "CVE-2021-28966" PACKAGECONFIG ??= "" PACKAGECONFIG += "${@bb.utils.filter('DISTRO_FEATURES', 'ipv6', d)}" diff --git a/meta/recipes-devtools/run-postinsts/run-postinsts/run-postinsts.service b/meta/recipes-devtools/run-postinsts/run-postinsts/run-postinsts.service index 7f72f3388a..b6b81d5c1a 100644 --- a/meta/recipes-devtools/run-postinsts/run-postinsts/run-postinsts.service +++ b/meta/recipes-devtools/run-postinsts/run-postinsts/run-postinsts.service @@ -1,7 +1,7 @@ [Unit] Description=Run pending postinsts DefaultDependencies=no -After=systemd-remount-fs.service systemd-tmpfiles-setup.service tmp.mount +After=systemd-remount-fs.service systemd-tmpfiles-setup.service tmp.mount ldconfig.service Before=sysinit.target [Service] diff --git a/meta/recipes-devtools/squashfs-tools/files/CVE-2021-40153.patch b/meta/recipes-devtools/squashfs-tools/files/CVE-2021-40153.patch new file mode 100644 index 0000000000..95e2534ee4 --- /dev/null +++ b/meta/recipes-devtools/squashfs-tools/files/CVE-2021-40153.patch @@ -0,0 +1,253 @@ +Backport patch to fix CVE-2021-40153, and remove version update in unsquashfs.c +for compatible. + +Upstream-Status: Backport [https://github.com/plougher/squashfs-tools/commit/79b5a55] +CVE: CVE-2021-40153 + +Signed-off-by: Kai Kang <kai.kang@windriver.com> + +From 79b5a555058eef4e1e7ff220c344d39f8cd09646 Mon Sep 17 00:00:00 2001 +From: Phillip Lougher <phillip@squashfs.org.uk> +Date: Sat, 16 Jan 2021 20:08:55 +0000 +Subject: [PATCH] Unsquashfs: fix write outside destination directory exploit + +An issue on Github (https://github.com/plougher/squashfs-tools/issues/72) +shows how some specially crafted Squashfs filesystems containing +invalid file names (with '/' and ..) can cause Unsquashfs to write +files outside of the destination directory. + +This commit fixes this exploit by checking all names for +validity. + +In doing so I have also added checks for '.' and for names that +are shorter than they should be (names in the file system should +not have '\0' terminators). + +Signed-off-by: Phillip Lougher <phillip@squashfs.org.uk> +--- + squashfs-tools/Makefile | 5 ++- + squashfs-tools/unsquash-1.c | 9 +++++- + squashfs-tools/unsquash-1234.c | 58 ++++++++++++++++++++++++++++++++++ + squashfs-tools/unsquash-2.c | 9 +++++- + squashfs-tools/unsquash-3.c | 9 +++++- + squashfs-tools/unsquash-4.c | 9 +++++- + squashfs-tools/unsquashfs.h | 5 ++- + 7 files changed, 98 insertions(+), 6 deletions(-) + create mode 100644 squashfs-tools/unsquash-1234.c + +diff --git a/squashfs-tools/Makefile b/squashfs-tools/Makefile +index aee4b960..20feaca2 100644 +--- a/squashfs-tools/Makefile ++++ b/squashfs-tools/Makefile +@@ -156,7 +156,8 @@ MKSQUASHFS_OBJS = mksquashfs.o read_fs.o action.o swap.o pseudo.o compressor.o \ + caches-queues-lists.o + + UNSQUASHFS_OBJS = unsquashfs.o unsquash-1.o unsquash-2.o unsquash-3.o \ +- unsquash-4.o unsquash-123.o unsquash-34.o swap.o compressor.o unsquashfs_info.o ++ unsquash-4.o unsquash-123.o unsquash-34.o unsquash-1234.o swap.o \ ++ compressor.o unsquashfs_info.o + + CFLAGS ?= -O2 + CFLAGS += $(EXTRA_CFLAGS) $(INCLUDEDIR) -D_FILE_OFFSET_BITS=64 \ +@@ -350,6 +351,8 @@ unsquash-123.o: unsquashfs.h unsquash-123.c squashfs_fs.h squashfs_compat.h + + unsquash-34.o: unsquashfs.h unsquash-34.c + ++unsquash-1234.o: unsquash-1234.c ++ + unsquashfs_xattr.o: unsquashfs_xattr.c unsquashfs.h squashfs_fs.h xattr.h + + unsquashfs_info.o: unsquashfs.h squashfs_fs.h +diff --git a/squashfs-tools/unsquash-1.c b/squashfs-tools/unsquash-1.c +index 34eced36..28326cb1 100644 +--- a/squashfs-tools/unsquash-1.c ++++ b/squashfs-tools/unsquash-1.c +@@ -2,7 +2,7 @@ + * Unsquash a squashfs filesystem. This is a highly compressed read only + * filesystem. + * +- * Copyright (c) 2009, 2010, 2011, 2012, 2019 ++ * Copyright (c) 2009, 2010, 2011, 2012, 2019, 2021 + * Phillip Lougher <phillip@squashfs.org.uk> + * + * This program is free software; you can redistribute it and/or +@@ -285,6 +285,13 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse + memcpy(dire->name, directory_table + bytes, + dire->size + 1); + dire->name[dire->size + 1] = '\0'; ++ ++ /* check name for invalid characters (i.e /, ., ..) */ ++ if(check_name(dire->name, dire->size + 1) == FALSE) { ++ ERROR("File system corrupted: invalid characters in name\n"); ++ goto corrupted; ++ } ++ + TRACE("squashfs_opendir: directory entry %s, inode " + "%d:%d, type %d\n", dire->name, + dirh.start_block, dire->offset, dire->type); +diff --git a/squashfs-tools/unsquash-1234.c b/squashfs-tools/unsquash-1234.c +new file mode 100644 +index 00000000..c2d4f42b +--- /dev/null ++++ b/squashfs-tools/unsquash-1234.c +@@ -0,0 +1,58 @@ ++/* ++ * Unsquash a squashfs filesystem. This is a highly compressed read only ++ * filesystem. ++ * ++ * Copyright (c) 2021 ++ * Phillip Lougher <phillip@squashfs.org.uk> ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2, ++ * or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * unsquash-1234.c ++ * ++ * Helper functions used by unsquash-1, unsquash-2, unsquash-3 and ++ * unsquash-4. ++ */ ++ ++#define TRUE 1 ++#define FALSE 0 ++/* ++ * Check name for validity, name should not ++ * - be ".", "./", or ++ * - be "..", "../" or ++ * - have a "/" anywhere in the name, or ++ * - be shorter than the expected size ++ */ ++int check_name(char *name, int size) ++{ ++ char *start = name; ++ ++ if(name[0] == '.') { ++ if(name[1] == '.') ++ name++; ++ if(name[1] == '/' || name[1] == '\0') ++ return FALSE; ++ } ++ ++ while(name[0] != '/' && name[0] != '\0') ++ name ++; ++ ++ if(name[0] == '/') ++ return FALSE; ++ ++ if((name - start) != size) ++ return FALSE; ++ ++ return TRUE; ++} +diff --git a/squashfs-tools/unsquash-2.c b/squashfs-tools/unsquash-2.c +index 4b3d767e..474064e1 100644 +--- a/squashfs-tools/unsquash-2.c ++++ b/squashfs-tools/unsquash-2.c +@@ -2,7 +2,7 @@ + * Unsquash a squashfs filesystem. This is a highly compressed read only + * filesystem. + * +- * Copyright (c) 2009, 2010, 2013, 2019 ++ * Copyright (c) 2009, 2010, 2013, 2019, 2021 + * Phillip Lougher <phillip@squashfs.org.uk> + * + * This program is free software; you can redistribute it and/or +@@ -386,6 +386,13 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse + memcpy(dire->name, directory_table + bytes, + dire->size + 1); + dire->name[dire->size + 1] = '\0'; ++ ++ /* check name for invalid characters (i.e /, ., ..) */ ++ if(check_name(dire->name, dire->size + 1) == FALSE) { ++ ERROR("File system corrupted: invalid characters in name\n"); ++ goto corrupted; ++ } ++ + TRACE("squashfs_opendir: directory entry %s, inode " + "%d:%d, type %d\n", dire->name, + dirh.start_block, dire->offset, dire->type); +diff --git a/squashfs-tools/unsquash-3.c b/squashfs-tools/unsquash-3.c +index 02c31fc5..65cfe4d9 100644 +--- a/squashfs-tools/unsquash-3.c ++++ b/squashfs-tools/unsquash-3.c +@@ -2,7 +2,7 @@ + * Unsquash a squashfs filesystem. This is a highly compressed read only + * filesystem. + * +- * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2019 ++ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2019, 2021 + * Phillip Lougher <phillip@squashfs.org.uk> + * + * This program is free software; you can redistribute it and/or +@@ -413,6 +413,13 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse + memcpy(dire->name, directory_table + bytes, + dire->size + 1); + dire->name[dire->size + 1] = '\0'; ++ ++ /* check name for invalid characters (i.e /, ., ..) */ ++ if(check_name(dire->name, dire->size + 1) == FALSE) { ++ ERROR("File system corrupted: invalid characters in name\n"); ++ goto corrupted; ++ } ++ + TRACE("squashfs_opendir: directory entry %s, inode " + "%d:%d, type %d\n", dire->name, + dirh.start_block, dire->offset, dire->type); +diff --git a/squashfs-tools/unsquash-4.c b/squashfs-tools/unsquash-4.c +index 8475835c..aa23a841 100644 +--- a/squashfs-tools/unsquash-4.c ++++ b/squashfs-tools/unsquash-4.c +@@ -2,7 +2,7 @@ + * Unsquash a squashfs filesystem. This is a highly compressed read only + * filesystem. + * +- * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2019 ++ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2019, 2021 + * Phillip Lougher <phillip@squashfs.org.uk> + * + * This program is free software; you can redistribute it and/or +@@ -349,6 +349,13 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse + memcpy(dire->name, directory_table + bytes, + dire->size + 1); + dire->name[dire->size + 1] = '\0'; ++ ++ /* check name for invalid characters (i.e /, ., ..) */ ++ if(check_name(dire->name, dire->size + 1) == FALSE) { ++ ERROR("File system corrupted: invalid characters in name\n"); ++ goto corrupted; ++ } ++ + TRACE("squashfs_opendir: directory entry %s, inode " + "%d:%d, type %d\n", dire->name, + dirh.start_block, dire->offset, dire->type); +diff --git a/squashfs-tools/unsquashfs.h b/squashfs-tools/unsquashfs.h +index 934618b2..db1da7a0 100644 +--- a/squashfs-tools/unsquashfs.h ++++ b/squashfs-tools/unsquashfs.h +@@ -4,7 +4,7 @@ + * Unsquash a squashfs filesystem. This is a highly compressed read only + * filesystem. + * +- * Copyright (c) 2009, 2010, 2013, 2014, 2019 ++ * Copyright (c) 2009, 2010, 2013, 2014, 2019, 2021 + * Phillip Lougher <phillip@squashfs.org.uk> + * + * This program is free software; you can redistribute it and/or +@@ -261,4 +261,7 @@ extern int read_ids(int, long long, long long, unsigned int **); + + /* unsquash-34.c */ + extern long long *alloc_index_table(int); ++ ++/* unsquash-1234.c */ ++extern int check_name(char *, int); + #endif diff --git a/meta/recipes-devtools/squashfs-tools/squashfs-tools_git.bb b/meta/recipes-devtools/squashfs-tools/squashfs-tools_git.bb index 2b1409d78d..5d754b20b3 100644 --- a/meta/recipes-devtools/squashfs-tools/squashfs-tools_git.bb +++ b/meta/recipes-devtools/squashfs-tools/squashfs-tools_git.bb @@ -9,8 +9,9 @@ LIC_FILES_CHKSUM = "file://../COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263" PV = "4.4" SRCREV = "52eb4c279cd283ed9802dd1ceb686560b22ffb67" -SRC_URI = "git://github.com/plougher/squashfs-tools.git;protocol=https \ +SRC_URI = "git://github.com/plougher/squashfs-tools.git;protocol=https;branch=master \ file://0001-squashfs-tools-fix-build-failure-against-gcc-10.patch;striplevel=2 \ + file://CVE-2021-40153.patch;striplevel=2 \ " S = "${WORKDIR}/git/squashfs-tools" diff --git a/meta/recipes-devtools/subversion/subversion/CVE-2021-28544.patch b/meta/recipes-devtools/subversion/subversion/CVE-2021-28544.patch new file mode 100644 index 0000000000..030ead6c66 --- /dev/null +++ b/meta/recipes-devtools/subversion/subversion/CVE-2021-28544.patch @@ -0,0 +1,146 @@ +From 61382fd8ea66000bd9ee8e203a6eab443220ee40 Mon Sep 17 00:00:00 2001 +From: Nathan Hartman <hartmannathan@apache.org> +Date: Sun, 27 Mar 2022 05:59:18 +0000 +Subject: [PATCH] On the 1.14.x-r1899227 branch: Merge r1899227 from trunk + w/testlist variation + +git-svn-id: https://svn.apache.org/repos/asf/subversion/branches/1.14.x-r1899227@1899229 13f79535-47bb-0310-9956-ffa450edef68 + +CVE: CVE-2021-28544 [https://github.com/apache/subversion/commit/61382fd8ea66000bd9ee8e203a6eab443220ee40] +Upstream-Status: Backport +Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> +--- + subversion/libsvn_repos/log.c | 26 +++++------- + subversion/tests/cmdline/authz_tests.py | 55 +++++++++++++++++++++++++ + 2 files changed, 65 insertions(+), 16 deletions(-) + +diff --git a/subversion/libsvn_repos/log.c b/subversion/libsvn_repos/log.c +index d9a1fb1085e16..41ca8aed27174 100644 +--- a/subversion/libsvn_repos/log.c ++++ b/subversion/libsvn_repos/log.c +@@ -337,42 +337,36 @@ detect_changed(svn_repos_revision_access_level_t *access_level, + if ( (change->change_kind == svn_fs_path_change_add) + || (change->change_kind == svn_fs_path_change_replace)) + { +- const char *copyfrom_path = change->copyfrom_path; +- svn_revnum_t copyfrom_rev = change->copyfrom_rev; +- + /* the following is a potentially expensive operation since on FSFS + we will follow the DAG from ROOT to PATH and that requires + actually reading the directories along the way. */ + if (!change->copyfrom_known) + { +- SVN_ERR(svn_fs_copied_from(©from_rev, ©from_path, ++ SVN_ERR(svn_fs_copied_from(&change->copyfrom_rev, &change->copyfrom_path, + root, path, iterpool)); + change->copyfrom_known = TRUE; + } + +- if (copyfrom_path && SVN_IS_VALID_REVNUM(copyfrom_rev)) ++ if (change->copyfrom_path && SVN_IS_VALID_REVNUM(change->copyfrom_rev)) + { +- svn_boolean_t readable = TRUE; +- + if (callbacks->authz_read_func) + { + svn_fs_root_t *copyfrom_root; ++ svn_boolean_t readable; + + SVN_ERR(svn_fs_revision_root(©from_root, fs, +- copyfrom_rev, iterpool)); ++ change->copyfrom_rev, iterpool)); + SVN_ERR(callbacks->authz_read_func(&readable, + copyfrom_root, +- copyfrom_path, ++ change->copyfrom_path, + callbacks->authz_read_baton, + iterpool)); + if (! readable) +- found_unreadable = TRUE; +- } +- +- if (readable) +- { +- change->copyfrom_path = copyfrom_path; +- change->copyfrom_rev = copyfrom_rev; ++ { ++ found_unreadable = TRUE; ++ change->copyfrom_path = NULL; ++ change->copyfrom_rev = SVN_INVALID_REVNUM; ++ } + } + } + } +diff --git a/subversion/tests/cmdline/authz_tests.py b/subversion/tests/cmdline/authz_tests.py +index 760cb3663d02f..92e8a5e1935c9 100755 +--- a/subversion/tests/cmdline/authz_tests.py ++++ b/subversion/tests/cmdline/authz_tests.py +@@ -1731,6 +1731,60 @@ def empty_group(sbox): + '--username', svntest.main.wc_author, + sbox.repo_url) + ++@Skip(svntest.main.is_ra_type_file) ++def log_inaccessible_copyfrom(sbox): ++ "log doesn't leak inaccessible copyfrom paths" ++ ++ sbox.build(empty=True) ++ sbox.simple_add_text('secret', 'private') ++ sbox.simple_commit(message='log message for r1') ++ sbox.simple_copy('private', 'public') ++ sbox.simple_commit(message='log message for r2') ++ ++ svntest.actions.enable_revprop_changes(sbox.repo_dir) ++ # Remove svn:date and svn:author for predictable output. ++ svntest.actions.run_and_verify_svn(None, [], 'propdel', '--revprop', ++ '-r2', 'svn:date', sbox.repo_url) ++ svntest.actions.run_and_verify_svn(None, [], 'propdel', '--revprop', ++ '-r2', 'svn:author', sbox.repo_url) ++ ++ write_restrictive_svnserve_conf(sbox.repo_dir) ++ ++ # First test with blanket access. ++ write_authz_file(sbox, ++ {"/" : "* = rw"}) ++ expected_output = svntest.verify.ExpectedOutput([ ++ "------------------------------------------------------------------------\n", ++ "r2 | (no author) | (no date) | 1 line\n", ++ "Changed paths:\n", ++ " A /public (from /private:1)\n", ++ "\n", ++ "log message for r2\n", ++ "------------------------------------------------------------------------\n", ++ ]) ++ svntest.actions.run_and_verify_svn(expected_output, [], ++ 'log', '-r2', '-v', ++ sbox.repo_url) ++ ++ # Now test with an inaccessible copy source (/private). ++ write_authz_file(sbox, ++ {"/" : "* = rw"}, ++ {"/private" : "* ="}) ++ expected_output = svntest.verify.ExpectedOutput([ ++ "------------------------------------------------------------------------\n", ++ "r2 | (no author) | (no date) | 1 line\n", ++ "Changed paths:\n", ++ # The copy is shown as a plain add with no copyfrom info. ++ " A /public\n", ++ "\n", ++ # No log message, as the revision is only partially visible. ++ "\n", ++ "------------------------------------------------------------------------\n", ++ ]) ++ svntest.actions.run_and_verify_svn(expected_output, [], ++ 'log', '-r2', '-v', ++ sbox.repo_url) ++ + + ######################################################################## + # Run the tests +@@ -1771,6 +1825,7 @@ def empty_group(sbox): + inverted_group_membership, + group_member_empty_string, + empty_group, ++ log_inaccessible_copyfrom, + ] + serial_only = True + diff --git a/meta/recipes-devtools/subversion/subversion_1.13.0.bb b/meta/recipes-devtools/subversion/subversion_1.13.0.bb index 34c0dbe5b8..5643191569 100644 --- a/meta/recipes-devtools/subversion/subversion_1.13.0.bb +++ b/meta/recipes-devtools/subversion/subversion_1.13.0.bb @@ -13,6 +13,7 @@ SRC_URI = "${APACHE_MIRROR}/${BPN}/${BPN}-${PV}.tar.bz2 \ file://0001-Fix-libtool-name-in-configure.ac.patch \ file://serfmacro.patch \ file://CVE-2020-17525.patch \ + file://CVE-2021-28544.patch \ " SRC_URI[md5sum] = "3004b4dae18bf45a0b6ea4ef8820064d" diff --git a/meta/recipes-devtools/systemd-bootchart/systemd-bootchart_233.bb b/meta/recipes-devtools/systemd-bootchart/systemd-bootchart_233.bb index aafe7c72a0..e1233ffde0 100644 --- a/meta/recipes-devtools/systemd-bootchart/systemd-bootchart_233.bb +++ b/meta/recipes-devtools/systemd-bootchart/systemd-bootchart_233.bb @@ -8,7 +8,7 @@ LICENSE = "LGPLv2.1 & GPLv2" LIC_FILES_CHKSUM = "file://LICENSE.LGPL2.1;md5=4fbd65380cdd255951079008b364516c \ file://LICENSE.GPL2;md5=751419260aa954499f7abaabaa882bbe" -SRC_URI = "git://github.com/systemd/systemd-bootchart.git;protocol=https \ +SRC_URI = "git://github.com/systemd/systemd-bootchart.git;protocol=https;branch=master \ file://0001-architecture-Recognise-RISCV-32-RISCV-64.patch \ file://mips64.patch \ " diff --git a/meta/recipes-devtools/tcf-agent/tcf-agent_git.bb b/meta/recipes-devtools/tcf-agent/tcf-agent_git.bb index 44a0d227ec..b671956cc8 100644 --- a/meta/recipes-devtools/tcf-agent/tcf-agent_git.bb +++ b/meta/recipes-devtools/tcf-agent/tcf-agent_git.bb @@ -10,7 +10,7 @@ SRCREV = "a022ef2f1acfd9209a1bf792dda14ae4b0d1b60f" PV = "1.7.0+git${SRCPV}" UPSTREAM_CHECK_GITTAGREGEX = "(?P<pver>(\d+(\.\d+)+))" -SRC_URI = "git://git.eclipse.org/gitroot/tcf/org.eclipse.tcf.agent \ +SRC_URI = "git://git.eclipse.org/r/tcf/org.eclipse.tcf.agent.git;protocol=https;branch=master \ file://fix_ranlib.patch \ file://ldflags.patch \ file://tcf-agent.init \ diff --git a/meta/recipes-devtools/unfs3/unfs3_git.bb b/meta/recipes-devtools/unfs3/unfs3_git.bb index b1882defa2..d1b3fb8f57 100644 --- a/meta/recipes-devtools/unfs3/unfs3_git.bb +++ b/meta/recipes-devtools/unfs3/unfs3_git.bb @@ -14,7 +14,7 @@ DEPENDS_append_class-nativesdk = " flex-nativesdk" ASNEEDED = "" S = "${WORKDIR}/git" -SRC_URI = "git://github.com/unfs3/unfs3.git;protocol=https \ +SRC_URI = "git://github.com/unfs3/unfs3.git;protocol=https;branch=master \ file://unfs3_parallel_build.patch \ file://alternate_rpc_ports.patch \ file://fix_pid_race_parent_writes_child_pid.patch \ diff --git a/meta/recipes-devtools/valgrind/valgrind/remove-for-aarch64 b/meta/recipes-devtools/valgrind/valgrind/remove-for-aarch64 index 93bfd45a4e..afa6a94825 100644 --- a/meta/recipes-devtools/valgrind/valgrind/remove-for-aarch64 +++ b/meta/recipes-devtools/valgrind/valgrind/remove-for-aarch64 @@ -120,6 +120,7 @@ drd/tests/tc19_shadowmem drd/tests/tc21_pthonce drd/tests/tc22_exit_w_lock drd/tests/tc23_bogus_condwait +gdbserver_tests/hginfo helgrind/tests/annotate_rwlock helgrind/tests/annotate_smart_pointer helgrind/tests/bar_bad diff --git a/meta/recipes-devtools/valgrind/valgrind/remove-for-all b/meta/recipes-devtools/valgrind/valgrind/remove-for-all index d6a85c4735..88a11ca332 100644 --- a/meta/recipes-devtools/valgrind/valgrind/remove-for-all +++ b/meta/recipes-devtools/valgrind/valgrind/remove-for-all @@ -1,2 +1,4 @@ drd/tests/bar_bad drd/tests/bar_bad_xml +gdbserver_tests/hginfo +memcheck/tests/linux/timerfd-syscall |