Package: release.debian.org Severity: normal User: release.debian....@packages.debian.org Usertags: unblock X-Debbugs-Cc: golang-1...@packages.debian.org, z...@debian.org Control: affects -1 + src:golang-1.19
Please unblock package golang-1.19 [ Reason ] Two upstream minor versions, fixing 5 CVEs + CVE-2023-24532: crypto/elliptic: incorrect P-256 ScalarMult and ScalarBaseMult results + CVE-2023-24537: go/parser: infinite loop in parsing + CVE-2023-24538: html/template: backticks not treated as string delimiters + CVE-2023-24534: net/http, net/textproto: denial of service from excessive memory allocation + CVE-2023-24536: net/http, net/textproto, mime/multipart: denial of service from excessive resource consumption [ Impact ] Several security issues in the Go standard libraries. [ Tests ] Besise the unittests upstream added in the new release, I have use the new version to build some Go packages. And the result is good. [ Risks ] Toolchain package and no autopkgtest. [ Checklist ] [x] all changes are documented in the d/changelog [x] I reviewed all changes and I approve them [x] attach debdiff against the package in testing I attached the debdiff with filterdiff --exclude '*_test.go' --exclude '*_windows*' --exclude '*/testdata/*' \ --exclude '*/go.mod' --exclude '*/go.sum' --exclude '*/modules.txt' [ Other info ] It may be the last golang-1.19 version to be uploaded during freeze. The next release is expected (if no urgent CVE happens) to be May, which is probably hard-freeze time. unblock golang-1.19/1.19.8-2
diff -Nru golang-1.19-1.19.6/debian/changelog golang-1.19-1.19.8/debian/changelog --- golang-1.19-1.19.6/debian/changelog 2023-02-17 17:56:44.000000000 +0800 +++ golang-1.19-1.19.8/debian/changelog 2023-04-05 02:15:56.000000000 +0800 @@ -1,3 +1,25 @@ +golang-1.19 (1.19.8-1) experimental; urgency=medium + + * Team upload + * New upstream version 1.19.8 + + CVE-2023-24537: go/parser: infinite loop in parsing + + CVE-2023-24538: html/template: backticks not treated as string delimiters + + CVE-2023-24534: net/http, net/textproto: denial of service from excessive + memory allocation + + CVE-2023-24536: net/http, net/textproto, mime/multipart: denial of + service from excessive resource consumption + + -- Shengjing Zhu <z...@debian.org> Wed, 05 Apr 2023 02:15:56 +0800 + +golang-1.19 (1.19.7-1) experimental; urgency=medium + + * Team upload + * New upstream version 1.19.7 + + CVE-2023-24532: crypto/elliptic: incorrect P-256 ScalarMult and + ScalarBaseMult results + + -- Shengjing Zhu <z...@debian.org> Wed, 08 Mar 2023 13:54:08 +0800 + golang-1.19 (1.19.6-2) unstable; urgency=medium * Team upload diff -Nru golang-1.19-1.19.6/src/cmd/go/internal/work/exec.go golang-1.19-1.19.8/src/cmd/go/internal/work/exec.go --- golang-1.19-1.19.6/src/cmd/go/internal/work/exec.go 2023-02-14 01:38:43.000000000 +0800 +++ golang-1.19-1.19.8/src/cmd/go/internal/work/exec.go 2023-03-30 05:15:17.000000000 +0800 @@ -2764,6 +2764,36 @@ } } + // Scrutinize CFLAGS and related for flags that might cause + // problems if we are using internal linking (for example, use of + // plugins, LTO, etc) by calling a helper routine that builds on + // the existing CGO flags allow-lists. If we see anything + // suspicious, emit a special token file "preferlinkext" (known to + // the linker) in the object file to signal the that it should not + // try to link internally and should revert to external linking. + // The token we pass is a suggestion, not a mandate; if a user is + // explicitly asking for a specific linkmode via the "-linkmode" + // flag, the token will be ignored. NB: in theory we could ditch + // the token approach and just pass a flag to the linker when we + // eventually invoke it, and the linker flag could then be + // documented (although coming up with a simple explanation of the + // flag might be challenging). For more context see issues #58619, + // #58620, and #58848. + flagSources := []string{"CGO_CFLAGS", "CGO_CXXFLAGS", "CGO_FFLAGS"} + flagLists := [][]string{cgoCFLAGS, cgoCXXFLAGS, cgoFFLAGS} + if flagsNotCompatibleWithInternalLinking(flagSources, flagLists) { + tokenFile := objdir + "preferlinkext" + if cfg.BuildN || cfg.BuildX { + b.Showcmd("", "echo > %s", tokenFile) + } + if !cfg.BuildN { + if err := os.WriteFile(tokenFile, nil, 0666); err != nil { + return nil, nil, err + } + } + outObj = append(outObj, tokenFile) + } + if cfg.BuildMSan { cgoCFLAGS = append([]string{"-fsanitize=memory"}, cgoCFLAGS...) cgoLDFLAGS = append([]string{"-fsanitize=memory"}, cgoLDFLAGS...) @@ -3012,6 +3042,24 @@ return outGo, outObj, nil } +// flagsNotCompatibleWithInternalLinking scans the list of cgo +// compiler flags (C/C++/Fortran) looking for flags that might cause +// problems if the build in question uses internal linking. The +// primary culprits are use of plugins or use of LTO, but we err on +// the side of caution, supporting only those flags that are on the +// allow-list for safe flags from security perspective. Return is TRUE +// if a sensitive flag is found, FALSE otherwise. +func flagsNotCompatibleWithInternalLinking(sourceList []string, flagListList [][]string) bool { + for i := range sourceList { + sn := sourceList[i] + fll := flagListList[i] + if err := checkCompilerFlagsForInternalLink(sn, sn, fll); err != nil { + return true + } + } + return false +} + // dynimport creates a Go source file named importGo containing // //go:cgo_import_dynamic directives for each symbol or library // dynamically imported by the object files outObj. diff -Nru golang-1.19-1.19.6/src/cmd/go/internal/work/security.go golang-1.19-1.19.8/src/cmd/go/internal/work/security.go --- golang-1.19-1.19.6/src/cmd/go/internal/work/security.go 2023-02-14 01:38:43.000000000 +0800 +++ golang-1.19-1.19.8/src/cmd/go/internal/work/security.go 2023-03-30 05:15:17.000000000 +0800 @@ -230,32 +230,55 @@ } func checkCompilerFlags(name, source string, list []string) error { - return checkFlags(name, source, list, validCompilerFlags, validCompilerFlagsWithNextArg) + checkOverrides := true + return checkFlags(name, source, list, validCompilerFlags, validCompilerFlagsWithNextArg, checkOverrides) } func checkLinkerFlags(name, source string, list []string) error { - return checkFlags(name, source, list, validLinkerFlags, validLinkerFlagsWithNextArg) + checkOverrides := true + return checkFlags(name, source, list, validLinkerFlags, validLinkerFlagsWithNextArg, checkOverrides) } -func checkFlags(name, source string, list []string, valid []*lazyregexp.Regexp, validNext []string) error { +// checkCompilerFlagsForInternalLink returns an error if 'list' +// contains a flag or flags that may not be fully supported by +// internal linking (meaning that we should punt the link to the +// external linker). +func checkCompilerFlagsForInternalLink(name, source string, list []string) error { + checkOverrides := false + if err := checkFlags(name, source, list, validCompilerFlags, validCompilerFlagsWithNextArg, checkOverrides); err != nil { + return err + } + // Currently the only flag on the allow list that causes problems + // for the linker is "-flto"; check for it manually here. + for _, fl := range list { + if strings.HasPrefix(fl, "-flto") { + return fmt.Errorf("flag %q triggers external linking", fl) + } + } + return nil +} + +func checkFlags(name, source string, list []string, valid []*lazyregexp.Regexp, validNext []string, checkOverrides bool) error { // Let users override rules with $CGO_CFLAGS_ALLOW, $CGO_CFLAGS_DISALLOW, etc. var ( allow *regexp.Regexp disallow *regexp.Regexp ) - if env := cfg.Getenv("CGO_" + name + "_ALLOW"); env != "" { - r, err := regexp.Compile(env) - if err != nil { - return fmt.Errorf("parsing $CGO_%s_ALLOW: %v", name, err) + if checkOverrides { + if env := cfg.Getenv("CGO_" + name + "_ALLOW"); env != "" { + r, err := regexp.Compile(env) + if err != nil { + return fmt.Errorf("parsing $CGO_%s_ALLOW: %v", name, err) + } + allow = r } - allow = r - } - if env := cfg.Getenv("CGO_" + name + "_DISALLOW"); env != "" { - r, err := regexp.Compile(env) - if err != nil { - return fmt.Errorf("parsing $CGO_%s_DISALLOW: %v", name, err) + if env := cfg.Getenv("CGO_" + name + "_DISALLOW"); env != "" { + r, err := regexp.Compile(env) + if err != nil { + return fmt.Errorf("parsing $CGO_%s_DISALLOW: %v", name, err) + } + disallow = r } - disallow = r } Args: diff -Nru golang-1.19-1.19.6/src/cmd/internal/obj/ppc64/asm9.go golang-1.19-1.19.8/src/cmd/internal/obj/ppc64/asm9.go --- golang-1.19-1.19.6/src/cmd/internal/obj/ppc64/asm9.go 2023-02-14 01:38:43.000000000 +0800 +++ golang-1.19-1.19.8/src/cmd/internal/obj/ppc64/asm9.go 2023-03-30 05:15:17.000000000 +0800 @@ -3136,8 +3136,13 @@ if r == 0 { r = c.getimpliedreg(&p.From, p) } - o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), uint32(r), uint32(high16adjusted(v))) - o2 = AOP_IRR(c.opload(p.As), uint32(p.To.Reg), uint32(p.To.Reg), uint32(v)) + if o.a6 == C_REG { + o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), uint32(r), uint32(high16adjusted(v))) + o2 = AOP_IRR(c.opload(p.As), uint32(p.To.Reg), uint32(p.To.Reg), uint32(v)) + } else { + o1 = AOP_IRR(OP_ADDIS, uint32(REGTMP), uint32(r), uint32(high16adjusted(v))) + o2 = AOP_IRR(c.opload(p.As), uint32(p.To.Reg), uint32(REGTMP), uint32(v)) + } // Sign extend MOVB if needed o3 = LOP_RRR(OP_EXTSB, uint32(p.To.Reg), uint32(p.To.Reg), 0) @@ -3516,8 +3521,8 @@ rel.Type = objabi.R_ADDRPOWER_TOCREL_DS } default: - reuseBaseReg := p.As != AFMOVD && p.As != AFMOVS - // Reuse To.Reg as base register if not FP move. + reuseBaseReg := o.a6 == C_REG + // Reuse To.Reg as base register if it is a GPR. o1, o2 = c.symbolAccess(p.From.Sym, v, p.To.Reg, inst, reuseBaseReg) } diff -Nru golang-1.19-1.19.6/src/cmd/link/internal/arm/asm.go golang-1.19-1.19.8/src/cmd/link/internal/arm/asm.go --- golang-1.19-1.19.6/src/cmd/link/internal/arm/asm.go 2023-02-14 01:38:43.000000000 +0800 +++ golang-1.19-1.19.8/src/cmd/link/internal/arm/asm.go 2023-03-30 05:15:17.000000000 +0800 @@ -396,11 +396,28 @@ // laid out. Conservatively use a trampoline. This should be rare, as we lay out packages // in dependency order. if ldr.SymValue(rs) != 0 { - // r.Add is the instruction - // low 24-bit encodes the target address - t = (ldr.SymValue(rs) + int64(signext24(r.Add()&0xffffff)*4) - (ldr.SymValue(s) + int64(r.Off()))) / 4 + // Workaround for issue #58425: it appears that the + // external linker doesn't always take into account the + // relocation addend when doing reachability checks. This + // means that if you have a call from function XYZ at + // offset 8 to runtime.duffzero with addend 800 (for + // example), where the distance between the start of XYZ + // and the start of runtime.duffzero is just over the + // limit (by 100 bytes, say), you can get "relocation + // doesn't fit" errors from the external linker. To deal + // with this, ignore the addend when performing the + // distance calculation (this assumes that we're only + // handling backward jumps; ideally we might want to check + // both with and without the addend). + if ctxt.IsExternal() { + t = (ldr.SymValue(rs) - (ldr.SymValue(s) + int64(r.Off()))) / 4 + } else { + // r.Add is the instruction + // low 24-bit encodes the target address + t = (ldr.SymValue(rs) + int64(signext24(r.Add()&0xffffff)*4) - (ldr.SymValue(s) + int64(r.Off()))) / 4 + } } - if t > 0x7fffff || t < -0x800000 || ldr.SymValue(rs) == 0 || (*ld.FlagDebugTramp > 1 && ldr.SymPkg(s) != ldr.SymPkg(rs)) { + if t > 0x7fffff || t <= -0x800000 || ldr.SymValue(rs) == 0 || (*ld.FlagDebugTramp > 1 && ldr.SymPkg(s) != ldr.SymPkg(rs)) { // direct call too far, need to insert trampoline. // look up existing trampolines first. if we found one within the range // of direct call, we can reuse it. otherwise create a new one. diff -Nru golang-1.19-1.19.6/src/cmd/link/internal/ld/config.go golang-1.19-1.19.8/src/cmd/link/internal/ld/config.go --- golang-1.19-1.19.6/src/cmd/link/internal/ld/config.go 2023-02-14 01:38:43.000000000 +0800 +++ golang-1.19-1.19.8/src/cmd/link/internal/ld/config.go 2023-03-30 05:15:17.000000000 +0800 @@ -280,7 +280,11 @@ ctxt.LinkMode = LinkExternal via = "via GO_EXTLINK_ENABLED " default: - if extNeeded || (iscgo && externalobj) { + preferExternal := len(preferlinkext) != 0 + if preferExternal && ctxt.Debugvlog > 0 { + ctxt.Logf("external linking prefer list is %v\n", preferlinkext) + } + if extNeeded || (iscgo && (externalobj || preferExternal)) { ctxt.LinkMode = LinkExternal } else { ctxt.LinkMode = LinkInternal diff -Nru golang-1.19-1.19.6/src/cmd/link/internal/ld/lib.go golang-1.19-1.19.8/src/cmd/link/internal/ld/lib.go --- golang-1.19-1.19.6/src/cmd/link/internal/ld/lib.go 2023-02-14 01:38:43.000000000 +0800 +++ golang-1.19-1.19.8/src/cmd/link/internal/ld/lib.go 2023-03-30 05:15:17.000000000 +0800 @@ -349,6 +349,12 @@ // any of these objects, we must link externally. Issue 52863. dynimportfail []string + // preferlinkext is a list of packages for which the Go command + // noticed use of peculiar C flags. If we see any of these, + // default to linking externally unless overridden by the + // user. See issues #58619, #58620, and #58848. + preferlinkext []string + // unknownObjFormat is set to true if we see an object whose // format we don't recognize. unknownObjFormat = false @@ -1043,6 +1049,13 @@ if arhdr.name == "dynimportfail" { dynimportfail = append(dynimportfail, lib.Pkg) } + if arhdr.name == "preferlinkext" { + // Ignore this directive if -linkmode has been + // set explicitly. + if ctxt.LinkMode == LinkAuto { + preferlinkext = append(preferlinkext, lib.Pkg) + } + } // Skip other special (non-object-file) sections that // build tools may have added. Such sections must have diff -Nru golang-1.19-1.19.6/src/crypto/internal/nistec/p256_asm.go golang-1.19-1.19.8/src/crypto/internal/nistec/p256_asm.go --- golang-1.19-1.19.6/src/crypto/internal/nistec/p256_asm.go 2023-02-14 01:38:45.000000000 +0800 +++ golang-1.19-1.19.8/src/crypto/internal/nistec/p256_asm.go 2023-03-30 05:15:20.000000000 +0800 @@ -365,6 +365,21 @@ // Montgomery domain (with R 2²⁵⁶) as four uint64 limbs in little-endian order. type p256OrdElement [4]uint64 +// p256OrdReduce ensures s is in the range [0, ord(G)-1]. +func p256OrdReduce(s *p256OrdElement) { + // Since 2 * ord(G) > 2²⁵⁶, we can just conditionally subtract ord(G), + // keeping the result if it doesn't underflow. + t0, b := bits.Sub64(s[0], 0xf3b9cac2fc632551, 0) + t1, b := bits.Sub64(s[1], 0xbce6faada7179e84, b) + t2, b := bits.Sub64(s[2], 0xffffffffffffffff, b) + t3, b := bits.Sub64(s[3], 0xffffffff00000000, b) + tMask := b - 1 // zero if subtraction underflowed + s[0] ^= (t0 ^ s[0]) & tMask + s[1] ^= (t1 ^ s[1]) & tMask + s[2] ^= (t2 ^ s[2]) & tMask + s[3] ^= (t3 ^ s[3]) & tMask +} + // Add sets q = p1 + p2, and returns q. The points may overlap. func (q *P256Point) Add(r1, r2 *P256Point) *P256Point { var sum, double P256Point @@ -394,6 +409,7 @@ } scalarReversed := new(p256OrdElement) p256OrdBigToLittle(scalarReversed, (*[32]byte)(scalar)) + p256OrdReduce(scalarReversed) r.p256BaseMult(scalarReversed) return r, nil @@ -408,6 +424,7 @@ } scalarReversed := new(p256OrdElement) p256OrdBigToLittle(scalarReversed, (*[32]byte)(scalar)) + p256OrdReduce(scalarReversed) r.Set(q).p256ScalarMult(scalarReversed) return r, nil diff -Nru golang-1.19-1.19.6/src/crypto/internal/nistec/p256_asm_ordinv.go golang-1.19-1.19.8/src/crypto/internal/nistec/p256_asm_ordinv.go --- golang-1.19-1.19.6/src/crypto/internal/nistec/p256_asm_ordinv.go 2023-02-14 01:38:45.000000000 +0800 +++ golang-1.19-1.19.8/src/crypto/internal/nistec/p256_asm_ordinv.go 2023-03-30 05:15:20.000000000 +0800 @@ -25,6 +25,7 @@ x := new(p256OrdElement) p256OrdBigToLittle(x, (*[32]byte)(k)) + p256OrdReduce(x) // Inversion is implemented as exponentiation by n - 2, per Fermat's little theorem. // diff -Nru golang-1.19-1.19.6/src/crypto/x509/root_darwin.go golang-1.19-1.19.8/src/crypto/x509/root_darwin.go --- golang-1.19-1.19.6/src/crypto/x509/root_darwin.go 2023-02-14 01:38:45.000000000 +0800 +++ golang-1.19-1.19.8/src/crypto/x509/root_darwin.go 2023-03-30 05:15:20.000000000 +0800 @@ -25,9 +25,10 @@ return nil, err } sc, err := macOS.SecCertificateCreateWithData(c.Raw) - if err == nil { - macOS.CFArrayAppendValue(certs, sc) + if err != nil { + return nil, err } + macOS.CFArrayAppendValue(certs, sc) } } diff -Nru golang-1.19-1.19.6/src/go/scanner/scanner.go golang-1.19-1.19.8/src/go/scanner/scanner.go --- golang-1.19-1.19.6/src/go/scanner/scanner.go 2023-02-14 01:38:46.000000000 +0800 +++ golang-1.19-1.19.8/src/go/scanner/scanner.go 2023-03-30 05:15:20.000000000 +0800 @@ -246,13 +246,16 @@ 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 } @@ -262,7 +265,7 @@ line = n } - if line == 0 { + if line == 0 || line > maxLineCol { s.error(offs+i, "invalid line number: "+string(text[i:])) return } diff -Nru golang-1.19-1.19.6/src/html/template/context.go golang-1.19-1.19.8/src/html/template/context.go --- golang-1.19-1.19.6/src/html/template/context.go 2023-02-14 01:38:46.000000000 +0800 +++ golang-1.19-1.19.8/src/html/template/context.go 2023-03-30 05:15:20.000000000 +0800 @@ -120,6 +120,8 @@ 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 -Nru golang-1.19-1.19.6/src/html/template/error.go golang-1.19-1.19.8/src/html/template/error.go --- golang-1.19-1.19.6/src/html/template/error.go 2023-02-14 01:38:46.000000000 +0800 +++ golang-1.19-1.19.8/src/html/template/error.go 2023-03-30 05:15:20.000000000 +0800 @@ -214,6 +214,19 @@ // 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 -Nru golang-1.19-1.19.6/src/html/template/escape.go golang-1.19-1.19.8/src/html/template/escape.go --- golang-1.19-1.19.6/src/html/template/escape.go 2023-02-14 01:38:46.000000000 +0800 +++ golang-1.19-1.19.8/src/html/template/escape.go 2023-03-30 05:15:20.000000000 +0800 @@ -8,6 +8,7 @@ "bytes" "fmt" "html" + "internal/godebug" "io" "text/template" "text/template/parse" @@ -223,6 +224,16 @@ 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 -Nru golang-1.19-1.19.6/src/html/template/jsctx_string.go golang-1.19-1.19.8/src/html/template/jsctx_string.go --- golang-1.19-1.19.6/src/html/template/jsctx_string.go 2023-02-14 01:38:46.000000000 +0800 +++ golang-1.19-1.19.8/src/html/template/jsctx_string.go 2023-03-30 05:15:21.000000000 +0800 @@ -4,6 +4,15 @@ 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 -Nru golang-1.19-1.19.6/src/html/template/js.go golang-1.19-1.19.8/src/html/template/js.go --- golang-1.19-1.19.6/src/html/template/js.go 2023-02-14 01:38:46.000000000 +0800 +++ golang-1.19-1.19.8/src/html/template/js.go 2023-03-30 05:15:21.000000000 +0800 @@ -308,6 +308,7 @@ // 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 @@ '"': `\u0022`, '&': `\u0026`, '\'': `\u0027`, + '`': `\u0060`, '+': `\u002b`, '/': `\/`, '<': `\u003c`, diff -Nru golang-1.19-1.19.6/src/html/template/state_string.go golang-1.19-1.19.8/src/html/template/state_string.go --- golang-1.19-1.19.6/src/html/template/state_string.go 2023-02-14 01:38:46.000000000 +0800 +++ golang-1.19-1.19.8/src/html/template/state_string.go 2023-03-30 05:15:21.000000000 +0800 @@ -4,9 +4,42 @@ 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] +} -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} +const _state_name = "stateTextstateTagstateAttrNamestateAfterNamestateBeforeValuestateHTMLCmtstateRCDATAstateAttrstateURLstateSrcsetstateJSstateJSDqStrstateJSSqStrstateJSBqStrstateJSRegexpstateJSBlockCmtstateJSLineCmtstateCSSstateCSSDqStrstateCSSSqStrstateCSSDqURLstateCSSSqURLstateCSSURLstateCSSBlockCmtstateCSSLineCmtstateErrorstateDead" + +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 -Nru golang-1.19-1.19.6/src/html/template/transition.go golang-1.19-1.19.8/src/html/template/transition.go --- golang-1.19-1.19.6/src/html/template/transition.go 2023-02-14 01:38:46.000000000 +0800 +++ golang-1.19-1.19.8/src/html/template/transition.go 2023-03-30 05:15:21.000000000 +0800 @@ -27,6 +27,7 @@ stateJS: tJS, stateJSDqStr: tJSDelimited, stateJSSqStr: tJSDelimited, + stateJSBqStr: tJSDelimited, stateJSRegexp: tJSDelimited, stateJSBlockCmt: tBlockCmt, stateJSLineCmt: tLineCmt, @@ -262,7 +263,7 @@ // 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 @@ 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 @@ switch c.state { case stateJSSqStr: specials = `\'` + case stateJSBqStr: + specials = "`\\" case stateJSRegexp: specials = `\/[]` } diff -Nru golang-1.19-1.19.6/src/internal/poll/fd_poll_runtime.go golang-1.19-1.19.8/src/internal/poll/fd_poll_runtime.go --- golang-1.19-1.19.6/src/internal/poll/fd_poll_runtime.go 2023-02-14 01:38:46.000000000 +0800 +++ golang-1.19-1.19.8/src/internal/poll/fd_poll_runtime.go 2023-03-30 05:15:21.000000000 +0800 @@ -23,7 +23,7 @@ func runtime_pollOpen(fd uintptr) (uintptr, int) func runtime_pollClose(ctx uintptr) func runtime_pollWait(ctx uintptr, mode int) int -func runtime_pollWaitCanceled(ctx uintptr, mode int) int +func runtime_pollWaitCanceled(ctx uintptr, mode int) func runtime_pollReset(ctx uintptr, mode int) int func runtime_pollSetDeadline(ctx uintptr, d int64, mode int) func runtime_pollUnblock(ctx uintptr) diff -Nru golang-1.19-1.19.6/src/mime/multipart/formdata.go golang-1.19-1.19.8/src/mime/multipart/formdata.go --- golang-1.19-1.19.6/src/mime/multipart/formdata.go 2023-02-14 01:38:47.000000000 +0800 +++ golang-1.19-1.19.8/src/mime/multipart/formdata.go 2023-03-30 05:15:21.000000000 +0800 @@ -12,6 +12,7 @@ "math" "net/textproto" "os" + "strconv" ) // ErrMessageTooLarge is returned by ReadForm if the message form @@ -41,6 +42,15 @@ 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 { @@ -84,14 +94,19 @@ maxMemoryBytes = math.MaxInt64 } } + 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 == "" { @@ -102,8 +117,9 @@ // 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. @@ -127,10 +143,16 @@ } // file, store in memory or on disk + const fileHeaderSize = 100 maxMemoryBytes -= mimeHeaderSize(p.Header) + maxMemoryBytes -= mapEntryOverhead + maxMemoryBytes -= fileHeaderSize if maxMemoryBytes < 0 { return nil, ErrMessageTooLarge } + for _, v := range p.Header { + maxHeaders -= int64(len(v)) + } fh := &FileHeader{ Filename: filename, Header: p.Header, @@ -147,14 +169,22 @@ } } 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 @@ -174,9 +204,10 @@ } 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 -Nru golang-1.19-1.19.6/src/mime/multipart/multipart.go golang-1.19-1.19.8/src/mime/multipart/multipart.go --- golang-1.19-1.19.6/src/mime/multipart/multipart.go 2023-02-14 01:38:47.000000000 +0800 +++ golang-1.19-1.19.8/src/mime/multipart/multipart.go 2023-03-30 05:15:21.000000000 +0800 @@ -16,11 +16,13 @@ "bufio" "bytes" "fmt" + "internal/godebug" "io" "mime" "mime/quotedprintable" "net/textproto" "path/filepath" + "strconv" "strings" ) @@ -128,12 +130,12 @@ 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} @@ -149,9 +151,9 @@ return bp, nil } -func (p *Part) populateHeaders(maxMIMEHeaderSize int64) error { +func (p *Part) populateHeaders(maxMIMEHeaderSize, maxMIMEHeaders int64) error { r := textproto.NewReader(p.mr.bufReader) - header, err := readMIMEHeader(r, maxMIMEHeaderSize) + header, err := readMIMEHeader(r, maxMIMEHeaderSize, maxMIMEHeaders) if err == nil { p.Header = header } @@ -330,6 +332,19 @@ // 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. // @@ -337,7 +352,7 @@ // 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. @@ -346,10 +361,10 @@ // 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() } @@ -374,7 +389,7 @@ 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 -Nru golang-1.19-1.19.6/src/mime/multipart/readmimeheader.go golang-1.19-1.19.8/src/mime/multipart/readmimeheader.go --- golang-1.19-1.19.6/src/mime/multipart/readmimeheader.go 2023-02-14 01:38:47.000000000 +0800 +++ golang-1.19-1.19.8/src/mime/multipart/readmimeheader.go 2023-03-30 05:15:21.000000000 +0800 @@ -11,4 +11,4 @@ // 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 -Nru golang-1.19-1.19.6/src/net/textproto/reader.go golang-1.19-1.19.8/src/net/textproto/reader.go --- golang-1.19-1.19.6/src/net/textproto/reader.go 2023-02-14 01:38:47.000000000 +0800 +++ golang-1.19-1.19.8/src/net/textproto/reader.go 2023-03-30 05:15:21.000000000 +0800 @@ -483,23 +483,32 @@ // "Long-Key": {"Even Longer Value"}, // } 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. 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) } 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. + maxMemory -= 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() @@ -529,16 +538,21 @@ continue } + maxHeaders-- + if maxHeaders < 0 { + return nil, errors.New("message too large") + } + // Skip initial spaces in value. value := string(bytes.TrimLeft(v, " \t")) vv := m[key] if vv == nil { - lim -= int64(len(key)) - lim -= 100 // map entry overhead + 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") @@ -577,9 +591,9 @@ var nl = []byte("\n") -// upcomingHeaderNewlines returns an approximation of the number of newlines +// 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() @@ -587,7 +601,20 @@ return } peek, _ := r.R.Peek(s) - return bytes.Count(peek, nl) + 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++ + } + return n } // CanonicalMIMEHeaderKey returns the canonical format of the diff -Nru golang-1.19-1.19.6/src/os/signal/internal/pty/pty.go golang-1.19-1.19.8/src/os/signal/internal/pty/pty.go --- golang-1.19-1.19.6/src/os/signal/internal/pty/pty.go 2023-02-14 01:38:47.000000000 +0800 +++ golang-1.19-1.19.8/src/os/signal/internal/pty/pty.go 2023-03-30 05:15:22.000000000 +0800 @@ -42,14 +42,14 @@ // Open returns a control pty and the name of the linked process tty. func Open() (pty *os.File, processTTY string, err error) { m, err := C.posix_openpt(C.O_RDWR) - if err != nil { + if m < 0 { return nil, "", ptyError("posix_openpt", err) } - if _, err := C.grantpt(m); err != nil { + if res, err := C.grantpt(m); res < 0 { C.close(m) return nil, "", ptyError("grantpt", err) } - if _, err := C.unlockpt(m); err != nil { + if res, err := C.unlockpt(m); res < 0 { C.close(m) return nil, "", ptyError("unlockpt", err) } diff -Nru golang-1.19-1.19.6/src/runtime/mgcsweep.go golang-1.19-1.19.8/src/runtime/mgcsweep.go --- golang-1.19-1.19.6/src/runtime/mgcsweep.go 2023-02-14 01:38:47.000000000 +0800 +++ golang-1.19-1.19.8/src/runtime/mgcsweep.go 2023-03-30 05:15:22.000000000 +0800 @@ -815,11 +815,30 @@ traceGCSweepStart() } + // Fix debt if necessary. retry: sweptBasis := mheap_.pagesSweptBasis.Load() - - // Fix debt if necessary. - newHeapLive := uintptr(atomic.Load64(&gcController.heapLive)-mheap_.sweepHeapLiveBasis) + spanBytes + live := atomic.Load64(&gcController.heapLive) + liveBasis := mheap_.sweepHeapLiveBasis + newHeapLive := spanBytes + if liveBasis < live { + // Only do this subtraction when we don't overflow. Otherwise, pagesTarget + // might be computed as something really huge, causing us to get stuck + // sweeping here until the next mark phase. + // + // Overflow can happen here if gcPaceSweeper is called concurrently with + // sweeping (i.e. not during a STW, like it usually is) because this code + // is intentionally racy. A concurrent call to gcPaceSweeper can happen + // if a GC tuning parameter is modified and we read an older value of + // heapLive than what was used to set the basis. + // + // This state should be transient, so it's fine to just let newHeapLive + // be a relatively small number. We'll probably just skip this attempt to + // sweep. + // + // See issue #57523. + newHeapLive += uintptr(live - liveBasis) + } pagesTarget := int64(mheap_.sweepPagesPerByte*float64(newHeapLive)) - int64(callerSweepPages) for pagesTarget > int64(mheap_.pagesSwept.Load()-sweptBasis) { if sweepone() == ^uintptr(0) { diff -Nru golang-1.19-1.19.6/src/sync/atomic/value.go golang-1.19-1.19.8/src/sync/atomic/value.go --- golang-1.19-1.19.6/src/sync/atomic/value.go 2023-02-14 01:38:48.000000000 +0800 +++ golang-1.19-1.19.8/src/sync/atomic/value.go 2023-03-30 05:15:23.000000000 +0800 @@ -190,5 +190,5 @@ } // Disable/enable preemption, implemented in runtime. -func runtime_procPin() +func runtime_procPin() int func runtime_procUnpin() diff -Nru golang-1.19-1.19.6/src/time/zoneinfo.go golang-1.19-1.19.8/src/time/zoneinfo.go --- golang-1.19-1.19.6/src/time/zoneinfo.go 2023-02-14 01:38:48.000000000 +0800 +++ golang-1.19-1.19.8/src/time/zoneinfo.go 2023-03-30 05:15:24.000000000 +0800 @@ -182,7 +182,7 @@ // If we're at the end of the known zone transitions, // try the extend string. if lo == len(tx)-1 && l.extend != "" { - if ename, eoffset, estart, eend, eisDST, ok := tzset(l.extend, end, sec); ok { + if ename, eoffset, estart, eend, eisDST, ok := tzset(l.extend, start, sec); ok { return ename, eoffset, estart, eend, eisDST } } @@ -243,12 +243,12 @@ } // tzset takes a timezone string like the one found in the TZ environment -// variable, the end of the last time zone transition expressed as seconds +// variable, the time of the last time zone transition expressed as seconds // since January 1, 1970 00:00:00 UTC, and a time expressed the same way. // We call this a tzset string since in C the function tzset reads TZ. // The return values are as for lookup, plus ok which reports whether the // parse succeeded. -func tzset(s string, initEnd, sec int64) (name string, offset int, start, end int64, isDST, ok bool) { +func tzset(s string, lastTxSec, sec int64) (name string, offset int, start, end int64, isDST, ok bool) { var ( stdName, dstName string stdOffset, dstOffset int @@ -269,7 +269,7 @@ if len(s) == 0 || s[0] == ',' { // No daylight savings time. - return stdName, stdOffset, initEnd, omega, false, true + return stdName, stdOffset, lastTxSec, omega, false, true } dstName, s, ok = tzsetName(s) diff -Nru golang-1.19-1.19.6/src/time/zoneinfo_read.go golang-1.19-1.19.8/src/time/zoneinfo_read.go --- golang-1.19-1.19.6/src/time/zoneinfo_read.go 2023-02-14 01:38:48.000000000 +0800 +++ golang-1.19-1.19.8/src/time/zoneinfo_read.go 2023-03-30 05:15:24.000000000 +0800 @@ -329,7 +329,7 @@ } else if l.extend != "" { // If we're at the end of the known zone transitions, // try the extend string. - if name, offset, estart, eend, isDST, ok := tzset(l.extend, l.cacheEnd, sec); ok { + if name, offset, estart, eend, isDST, ok := tzset(l.extend, l.cacheStart, sec); ok { l.cacheStart = estart l.cacheEnd = eend // Find the zone that is returned by tzset to avoid allocation if possible. diff -Nru golang-1.19-1.19.6/VERSION golang-1.19-1.19.8/VERSION --- golang-1.19-1.19.6/VERSION 2023-02-14 01:38:41.000000000 +0800 +++ golang-1.19-1.19.8/VERSION 2023-03-30 05:15:14.000000000 +0800 @@ -1 +1 @@ -go1.19.6 \ No newline at end of file +go1.19.8 \ No newline at end of file