diff --git a/SPECS/cf-cli/CVE-2026-56852.patch b/SPECS/cf-cli/CVE-2026-56852.patch new file mode 100644 index 00000000000..4dbfa12a4dd --- /dev/null +++ b/SPECS/cf-cli/CVE-2026-56852.patch @@ -0,0 +1,188 @@ +From 8504c729256c0d225c6c5e61b8c02cad7a093f9a Mon Sep 17 00:00:00 2001 +From: Damien Neil +Date: Tue, 14 Apr 2026 21:46:24 -0400 +Subject: [PATCH] unicode/norm: avoid infinite loop on invalid input + +Invalid characters are given a Properties with a size of 0. + +The nextComposed function can enter an infinite loop when +encountering an invalid character, since it advances +its input by the (possibly 0) character size. + +Rather than finding every place which might assume characters +have a non-zero size, change compInfo to return a size-1 +Properties for invalid characters and use the property flags +to record validity. + +Fixes golang/go#80142 + +Change-Id: Ie0791faefeddc1e8f671b0ed73f29e906a6a6964 +Reviewed-on: https://go-review.googlesource.com/c/text/+/794100 +LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com +Auto-Submit: Damien Neil +Reviewed-by: Neal Patel +Reviewed-by: Neal Patel +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: https://github.com/golang/text/commit/5ae8e578e495731553eddba11b2d0e86c91a00ce.patch +--- + .../x/text/unicode/norm/forminfo.go | 9 ++++++++- + vendor/golang.org/x/text/unicode/norm/iter.go | 8 ++------ + .../x/text/unicode/norm/normalize.go | 20 +++++++++---------- + 3 files changed, 20 insertions(+), 17 deletions(-) + +diff --git a/vendor/golang.org/x/text/unicode/norm/forminfo.go b/vendor/golang.org/x/text/unicode/norm/forminfo.go +index 487335d..6596a6b 100644 +--- a/vendor/golang.org/x/text/unicode/norm/forminfo.go ++++ b/vendor/golang.org/x/text/unicode/norm/forminfo.go +@@ -118,8 +118,12 @@ func (p Properties) BoundaryAfter() bool { + // + // When all 4 bits are zero, the character is inert, meaning it is never + // influenced by normalization. ++// ++// We set flags to 0x80 (high bit 7 unused in quick check data) to indicate an invalid rune. + type qcInfo uint8 + ++func (p Properties) isInvalid() bool { return p.flags == 0x80 } ++ + func (p Properties) isYesC() bool { return p.flags&0x10 == 0 } + func (p Properties) isYesD() bool { return p.flags&0x4 == 0 } + +@@ -241,6 +245,9 @@ func (f Form) PropertiesString(s string) Properties { + // to a Properties. See the comment at the top of the file + // for more information on the format. + func compInfo(v uint16, sz int) Properties { ++ if sz == 0 { ++ return Properties{flags: 0x80, size: 1} ++ } + if v == 0 { + return Properties{size: uint8(sz)} + } else if v >= 0x8000 { +@@ -248,7 +255,7 @@ func compInfo(v uint16, sz int) Properties { + size: uint8(sz), + ccc: uint8(v), + tccc: uint8(v), +- flags: qcInfo(v >> 8), ++ flags: qcInfo(v>>8) & 0x3f, + } + if p.ccc > 0 || p.combinesBackward() { + p.nLead = uint8(p.flags & 0x3) +diff --git a/vendor/golang.org/x/text/unicode/norm/iter.go b/vendor/golang.org/x/text/unicode/norm/iter.go +index 417c6b2..3cc0592 100644 +--- a/vendor/golang.org/x/text/unicode/norm/iter.go ++++ b/vendor/golang.org/x/text/unicode/norm/iter.go +@@ -376,16 +376,12 @@ func nextComposed(i *Iter) []byte { + goto doNorm + } + prevCC = i.info.tccc +- sz := int(i.info.size) +- if sz == 0 { +- sz = 1 // illegal rune: copy byte-by-byte +- } +- p := outp + sz ++ p := outp + int(i.info.size) + if p > len(i.buf) { + break + } + outp = p +- i.p += sz ++ i.p += int(i.info.size) + if i.p >= i.rb.nsrc { + i.setDone() + break +diff --git a/vendor/golang.org/x/text/unicode/norm/normalize.go b/vendor/golang.org/x/text/unicode/norm/normalize.go +index 4747ad0..60b1511 100644 +--- a/vendor/golang.org/x/text/unicode/norm/normalize.go ++++ b/vendor/golang.org/x/text/unicode/norm/normalize.go +@@ -148,7 +148,7 @@ func (f Form) IsNormalString(s string) bool { + // patched buffer and whether the decomposition is still in progress. + func patchTail(rb *reorderBuffer) bool { + info, p := lastRuneStart(&rb.f, rb.out) +- if p == -1 || info.size == 0 { ++ if p == -1 || info.isInvalid() { + return true + } + end := p + int(info.size) +@@ -225,7 +225,7 @@ func doAppend(rb *reorderBuffer, out []byte, p int) []byte { + } + fd := &rb.f + if doMerge { +- var info Properties ++ info := Properties{flags: 0x80, size: 1} // invalid rune + if p < n { + info = fd.info(src, p) + if !info.BoundaryBefore() || info.nLeadingNonStarters() > 0 { +@@ -235,7 +235,7 @@ func doAppend(rb *reorderBuffer, out []byte, p int) []byte { + p = decomposeSegment(rb, p, true) + } + } +- if info.size == 0 { ++ if info.isInvalid() { + rb.doFlush() + // Append incomplete UTF-8 encoding. + return src.appendSlice(rb.out, p, n) +@@ -314,7 +314,7 @@ func (f *formInfo) quickSpan(src input, i, end int, atEOF bool) (n int, ok bool) + continue + } + info := f.info(src, i) +- if info.size == 0 { ++ if info.isInvalid() { + if atEOF { + // include incomplete runes + return n, true +@@ -379,7 +379,7 @@ func (f Form) firstBoundary(src input, nsrc int) int { + // CGJ insertion points correctly. Luckily it doesn't have to. + for { + info := fd.info(src, i) +- if info.size == 0 { ++ if info.isInvalid() { + return -1 + } + if s := ss.next(info); s != ssSuccess { +@@ -424,7 +424,7 @@ func (f Form) nextBoundary(src input, nsrc int, atEOF bool) int { + } + fd := formTable[f] + info := fd.info(src, 0) +- if info.size == 0 { ++ if info.isInvalid() { + if atEOF { + return 1 + } +@@ -435,7 +435,7 @@ func (f Form) nextBoundary(src input, nsrc int, atEOF bool) int { + + for i := int(info.size); i < nsrc; i += int(info.size) { + info = fd.info(src, i) +- if info.size == 0 { ++ if info.isInvalid() { + if atEOF { + return i + } +@@ -465,7 +465,7 @@ func lastBoundary(fd *formInfo, b []byte) int { + if p == -1 { + return -1 + } +- if info.size == 0 { // ends with incomplete rune ++ if info.isInvalid() { // ends with incomplete rune + if p == 0 { // starts with incomplete rune + return -1 + } +@@ -504,7 +504,7 @@ func lastBoundary(fd *formInfo, b []byte) int { + func decomposeSegment(rb *reorderBuffer, sp int, atEOF bool) int { + // Force one character to be consumed. + info := rb.f.info(rb.src, sp) +- if info.size == 0 { ++ if info.isInvalid() { + return 0 + } + if s := rb.ss.next(info); s == ssStarter { +@@ -528,7 +528,7 @@ func decomposeSegment(rb *reorderBuffer, sp int, atEOF bool) int { + break + } + info = rb.f.info(rb.src, sp) +- if info.size == 0 { ++ if info.isInvalid() { + if !atEOF { + return int(iShortSrc) + } +-- +2.45.4 + diff --git a/SPECS/cf-cli/cf-cli.spec b/SPECS/cf-cli/cf-cli.spec index e1694422923..191b4ba13af 100644 --- a/SPECS/cf-cli/cf-cli.spec +++ b/SPECS/cf-cli/cf-cli.spec @@ -5,7 +5,7 @@ Summary: The official command line client for Cloud Foundry. Name: cf-cli # Note: Upgrading the package also warrants an upgrade in the CF_BUILD_SHA Version: 8.7.11 -Release: 7%{?dist} +Release: 8%{?dist} License: Apache-2.0 Vendor: Microsoft Corporation Distribution: Azure Linux @@ -51,6 +51,7 @@ Patch15: CVE-2026-39827.patch Patch16: CVE-2026-39828.patch Patch17: CVE-2026-39835.patch Patch18: CVE-2026-42502.patch +Patch19: CVE-2026-56852.patch BuildRequires: golang < 1.25 %global debug_package %{nil} @@ -82,6 +83,9 @@ install -p -m 755 -t %{buildroot}%{_bindir} ./out/cf %{_bindir}/cf %changelog +* Mon Jul 27 2026 Azure Linux Security Servicing Account - 8.7.11-8 +- Patch for CVE-2026-56852 + * Mon Jun 01 2026 Azure Linux Security Servicing Account - 8.7.11-7 - Patch for CVE-2026-42502, CVE-2026-39835, CVE-2026-39828, CVE-2026-39827, CVE-2026-25681, CVE-2026-25680