[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1005340: bullseye-pu: package golang-1.15/1.15.15-1~deb11u3



Package: release.debian.org
Severity: normal
Tags: bullseye
User: release.debian.org@packages.debian.org
Usertags: pu
X-Debbugs-Cc: zhsj@debian.org, team@security.debian.org

[ Reason ]
Backport patches for CVE-2022-23806 CVE-2022-23772 CVE-2022-23773

[ Impact ]

+ CVE-2022-23806: crypto/elliptic: fix IsOnCurve for big.Int values
  that are not valid coordinates
+ CVE-2022-23772: math/big: prevent large memory consumption in
  Rat.SetString
+ CVE-2022-23773: cmd/go: prevent branches from materializing into versions

All are minor security issues, so I'd like to go with stable-pu.

[ Tests ]

For CVE-2022-23806 and CVE-2022-23772, regression tests are backported as well.

For CVE-2022-23773 the tests in upstream patch are hard to backport, so I test
it manully. The test is similar with upstream patch[1]

[1] https://github.com/golang/go/commit/fa4d9b8e2bc2612960c80474fca83a4c85a974eb#diff-6d41824e441b8846a74c31ab4968dc114a1e650c05172e1f89826ea9e55d4c5aR421

For example, running

  GOPROXY=direct /usr/lib/go-1.15/bin/go get vcs-test.golang.org/git/semver-branch.git@v1.0.0

Will get same result and error in [1].

[ Risks ]

Patch for CVE-2022-23806 and CVE-2022-23772 are trivial and easy to review.
Patch for CVE-2022-23773 is larger, and is backported by 3way merge.

[ 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 (old)stable
  [ ] the issue is verified as fixed in unstable
      golang-1.15 has been removed from unstable.

[ Changes ]

See attachment.

[ Other info ]

CVE-2022-23806 and CVE-2022-23772 are for Go std library, which is statically
linked in all Go programs. But these issues look like too minor to rebuild all
Go programs.
diff -Nru golang-1.15-1.15.15/debian/changelog golang-1.15-1.15.15/debian/changelog
--- golang-1.15-1.15.15/debian/changelog	2021-12-04 17:37:57.000000000 +0800
+++ golang-1.15-1.15.15/debian/changelog	2022-02-11 23:45:44.000000000 +0800
@@ -1,3 +1,14 @@
+golang-1.15 (1.15.15-1~deb11u3) bullseye; urgency=medium
+
+  * Backport patches for CVE-2022-23806 CVE-2022-23772 CVE-2022-23773
+    + CVE-2022-23806: crypto/elliptic: fix IsOnCurve for big.Int values
+      that are not valid coordinates
+    + CVE-2022-23772: math/big: prevent large memory consumption in
+      Rat.SetString
+    + CVE-2022-23773: cmd/go: prevent branches from materializing into versions
+
+ -- Shengjing Zhu <zhsj@debian.org>  Fri, 11 Feb 2022 23:45:44 +0800
+
 golang-1.15 (1.15.15-1~deb11u2) bullseye; urgency=medium
 
   * Backport patch for CVE-2021-38297
diff -Nru golang-1.15-1.15.15/debian/patches/0012-CVE-2022-23806.patch golang-1.15-1.15.15/debian/patches/0012-CVE-2022-23806.patch
--- golang-1.15-1.15.15/debian/patches/0012-CVE-2022-23806.patch	1970-01-01 08:00:00.000000000 +0800
+++ golang-1.15-1.15.15/debian/patches/0012-CVE-2022-23806.patch	2022-02-11 23:45:44.000000000 +0800
@@ -0,0 +1,132 @@
+From: Filippo Valsorda <filippo@golang.org>
+Date: Wed, 2 Feb 2022 09:15:44 -0800
+Subject: CVE-2022-23806
+
+Origin: backport, https://github.com/golang/go/commit/6b3e741a
+---
+ src/crypto/elliptic/elliptic.go      |  5 +++
+ src/crypto/elliptic/elliptic_test.go | 81 ++++++++++++++++++++++++++++++++++++
+ src/crypto/elliptic/p224.go          |  5 +++
+ 3 files changed, 91 insertions(+)
+
+diff --git a/src/crypto/elliptic/elliptic.go b/src/crypto/elliptic/elliptic.go
+index f93dc16..afedf18 100644
+--- a/src/crypto/elliptic/elliptic.go
++++ b/src/crypto/elliptic/elliptic.go
+@@ -71,6 +71,11 @@ func (curve *CurveParams) polynomial(x *big.Int) *big.Int {
+ }
+ 
+ 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 e80e773..bb16b0d 100644
+--- a/src/crypto/elliptic/elliptic_test.go
++++ b/src/crypto/elliptic/elliptic_test.go
+@@ -721,3 +721,84 @@ func testMarshalCompressed(t *testing.T, curve Curve, x, y *big.Int, want []byte
+ 		t.Errorf("point did not round-trip correctly: got (%v, %v), want (%v, %v)", X, Y, x, y)
+ 	}
+ }
++
++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..ff5c834 100644
+--- a/src/crypto/elliptic/p224.go
++++ b/src/crypto/elliptic/p224.go
+@@ -48,6 +48,11 @@ 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 -Nru golang-1.15-1.15.15/debian/patches/0013-CVE-2022-23772.patch golang-1.15-1.15.15/debian/patches/0013-CVE-2022-23772.patch
--- golang-1.15-1.15.15/debian/patches/0013-CVE-2022-23772.patch	1970-01-01 08:00:00.000000000 +0800
+++ golang-1.15-1.15.15/debian/patches/0013-CVE-2022-23772.patch	2022-02-11 23:45:44.000000000 +0800
@@ -0,0 +1,38 @@
+From: Katie Hockman <katie@golang.org>
+Date: Wed, 19 Jan 2022 16:54:41 -0500
+Subject: CVE-2022-23772
+
+Origin: backport, https://github.com/golang/go/commit/07ee9e64
+---
+ 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 ac3c8bd..90053a9 100644
+--- a/src/math/big/ratconv.go
++++ b/src/math/big/ratconv.go
+@@ -169,6 +169,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
++			}
+ 		}
+ 		if n > 1e6 {
+ 			return nil, false // avoid excessively large exponents
+diff --git a/src/math/big/ratconv_test.go b/src/math/big/ratconv_test.go
+index 15d206c..e55e655 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},
diff -Nru golang-1.15-1.15.15/debian/patches/0014-CVE-2022-23773.patch golang-1.15-1.15.15/debian/patches/0014-CVE-2022-23773.patch
--- golang-1.15-1.15.15/debian/patches/0014-CVE-2022-23773.patch	1970-01-01 08:00:00.000000000 +0800
+++ golang-1.15-1.15.15/debian/patches/0014-CVE-2022-23773.patch	2022-02-11 23:45:44.000000000 +0800
@@ -0,0 +1,323 @@
+From: "Bryan C. Mills" <bcmills@google.com>
+Date: Thu, 13 Jan 2022 15:38:14 -0500
+Subject: CVE-2022-23773
+
+Origin: backport, https://github.com/golang/go/commit/de76489a
+
+Only change in coderep.go is backported. Changes in coderepo_test.go
+and mod_invalid_version.txt are used for testing, which can't be
+cherry-picked directly.
+---
+ src/cmd/go/internal/modfetch/coderepo.go | 215 +++++++++++++++----------------
+ 1 file changed, 106 insertions(+), 109 deletions(-)
+
+diff --git a/src/cmd/go/internal/modfetch/coderepo.go b/src/cmd/go/internal/modfetch/coderepo.go
+index d043903..3297af9 100644
+--- a/src/cmd/go/internal/modfetch/coderepo.go
++++ b/src/cmd/go/internal/modfetch/coderepo.go
+@@ -298,16 +298,13 @@ func (r *codeRepo) Latest() (*RevInfo, error) {
+ // If statVers is a valid module version, it is used for the Version field.
+ // Otherwise, the Version is derived from the passed-in info and recent tags.
+ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, error) {
+-	info2 := &RevInfo{
+-		Name:  info.Name,
+-		Short: info.Short,
+-		Time:  info.Time,
+-	}
+-
+ 	// If this is a plain tag (no dir/ prefix)
+ 	// and the module path is unversioned,
+ 	// and if the underlying file tree has no go.mod,
+ 	// then allow using the tag with a +incompatible suffix.
++	//
++	// (If the version is +incompatible, then the go.mod file must not exist:
++	// +incompatible is not an ongoing opt-out from semantic import versioning.)
+ 	var canUseIncompatible func() bool
+ 	canUseIncompatible = func() bool {
+ 		var ok bool
+@@ -321,19 +318,12 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e
+ 		return ok
+ 	}
+ 
+-	invalidf := func(format string, args ...interface{}) error {
+-		return &module.ModuleError{
+-			Path: r.modPath,
+-			Err: &module.InvalidVersionError{
+-				Version: info2.Version,
+-				Err:     fmt.Errorf(format, args...),
+-			},
+-		}
+-	}
+-
+-	// checkGoMod verifies that the go.mod file for the module exists or does not
+-	// exist as required by info2.Version and the module path represented by r.
+-	checkGoMod := func() (*RevInfo, error) {
++	// checkCanonical verifies that the canonical version v is compatible with the
++	// module path represented by r, adding a "+incompatible" suffix if needed.
++	//
++	// If statVers is also canonical, checkCanonical also verifies that v is
++	// either statVers or statVers with the added "+incompatible" suffix.
++	checkCanonical := func(v string) (*RevInfo, error) {
+ 		// If r.codeDir is non-empty, then the go.mod file must exist: the module
+ 		// author — not the module consumer, — gets to decide how to carve up the repo
+ 		// into modules.
+@@ -344,73 +334,91 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e
+ 		// r.findDir verifies both of these conditions. Execute it now so that
+ 		// r.Stat will correctly return a notExistError if the go.mod location or
+ 		// declared module path doesn't match.
+-		_, _, _, err := r.findDir(info2.Version)
++		_, _, _, err := r.findDir(v)
+ 		if err != nil {
+ 			// TODO: It would be nice to return an error like "not a module".
+ 			// Right now we return "missing go.mod", which is a little confusing.
+ 			return nil, &module.ModuleError{
+ 				Path: r.modPath,
+ 				Err: &module.InvalidVersionError{
+-					Version: info2.Version,
++					Version: v,
+ 					Err:     notExistError{err: err},
+ 				},
+ 			}
+ 		}
+ 
+-		// If the version is +incompatible, then the go.mod file must not exist:
+-		// +incompatible is not an ongoing opt-out from semantic import versioning.
+-		if strings.HasSuffix(info2.Version, "+incompatible") {
+-			if !canUseIncompatible() {
++		invalidf := func(format string, args ...interface{}) error {
++			return &module.ModuleError{
++				Path: r.modPath,
++				Err: &module.InvalidVersionError{
++					Version: v,
++					Err:     fmt.Errorf(format, args...),
++				},
++			}
++		}
++
++		// Add the +incompatible suffix if needed or requested explicitly, and
++		// verify that its presence or absence is appropriate for this version
++		// (which depends on whether it has an explicit go.mod file).
++
++		if v == strings.TrimSuffix(statVers, "+incompatible") {
++			v = statVers
++		}
++		base := strings.TrimSuffix(v, "+incompatible")
++		var errIncompatible error
++		if !module.MatchPathMajor(base, r.pathMajor) {
++			if canUseIncompatible() {
++				v = base + "+incompatible"
++			} else {
+ 				if r.pathMajor != "" {
+-					return nil, invalidf("+incompatible suffix not allowed: module path includes a major version suffix, so major version must match")
++					errIncompatible = invalidf("module path includes a major version suffix, so major version must match")
+ 				} else {
+-					return nil, invalidf("+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required")
++					errIncompatible = invalidf("module contains a go.mod file, so module path must match major version (%q)", path.Join(r.pathPrefix, semver.Major(v)))
+ 				}
+ 			}
+-
+-			if err := module.CheckPathMajor(strings.TrimSuffix(info2.Version, "+incompatible"), r.pathMajor); err == nil {
+-				return nil, invalidf("+incompatible suffix not allowed: major version %s is compatible", semver.Major(info2.Version))
++		} else if strings.HasSuffix(v, "+incompatible") {
++			errIncompatible = invalidf("+incompatible suffix not allowed: major version %s is compatible", semver.Major(v))
++		}
++
++		if statVers != "" && statVers == module.CanonicalVersion(statVers) {
++			// Since the caller-requested version is canonical, it would be very
++			// confusing to resolve it to anything but itself, possibly with a
++			// "+incompatible" suffix. Error out explicitly.
++			if statBase := strings.TrimSuffix(statVers, "+incompatible"); statBase != base {
++				return nil, &module.ModuleError{
++					Path: r.modPath,
++					Err: &module.InvalidVersionError{
++						Version: statVers,
++						Err:     fmt.Errorf("resolves to version %v (%s is not a tag)", v, statBase),
++					},
++				}
+ 			}
+ 		}
+ 
+-		return info2, nil
++		if errIncompatible != nil {
++			return nil, errIncompatible
++		}
++
++		return &RevInfo{
++			Name:    info.Name,
++			Short:   info.Short,
++			Time:    info.Time,
++			Version: v,
++		}, nil
+ 	}
+ 
+ 	// Determine version.
+-	//
+-	// If statVers is canonical, then the original call was repo.Stat(statVers).
+-	// Since the version is canonical, we must not resolve it to anything but
+-	// itself, possibly with a '+incompatible' annotation: we do not need to do
+-	// the work required to look for an arbitrary pseudo-version.
+-	if statVers != "" && statVers == module.CanonicalVersion(statVers) {
+-		info2.Version = statVers
+-
+-		if IsPseudoVersion(info2.Version) {
+-			if err := r.validatePseudoVersion(info, info2.Version); err != nil {
+-				return nil, err
+-			}
+-			return checkGoMod()
+-		}
+ 
+-		if err := module.CheckPathMajor(info2.Version, r.pathMajor); err != nil {
+-			if canUseIncompatible() {
+-				info2.Version += "+incompatible"
+-				return checkGoMod()
+-			} else {
+-				if vErr, ok := err.(*module.InvalidVersionError); ok {
+-					// We're going to describe why the version is invalid in more detail,
+-					// so strip out the existing “invalid version” wrapper.
+-					err = vErr.Err
+-				}
+-				return nil, invalidf("module contains a go.mod file, so major version must be compatible: %v", err)
+-			}
++	if IsPseudoVersion(statVers) {
++		if err := r.validatePseudoVersion(info, statVers); err != nil {
++			return nil, err
+ 		}
+-
+-		return checkGoMod()
++		return checkCanonical(statVers)
+ 	}
+ 
+-	// statVers is empty or non-canonical, so we need to resolve it to a canonical
+-	// version or pseudo-version.
++	// statVers is not a pseudo-version, so we need to either resolve it to a
++	// canonical version or verify that it is already a canonical tag
++	// (not a branch).
+ 
+ 	// Derive or verify a version from a code repo tag.
+ 	// Tag must have a prefix matching codeDir.
+@@ -439,65 +447,59 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e
+ 		if v == trimmed {
+ 			tagIsCanonical = true
+ 		}
+-
+-		if err := module.CheckPathMajor(v, r.pathMajor); err != nil {
+-			if canUseIncompatible() {
+-				return v + "+incompatible", tagIsCanonical
+-			}
+-			return "", false
+-		}
+-
+ 		return v, tagIsCanonical
+ 	}
+ 
+ 	// If the VCS gave us a valid version, use that.
+ 	if v, tagIsCanonical := tagToVersion(info.Version); tagIsCanonical {
+-		info2.Version = v
+-		return checkGoMod()
++		if info, err := checkCanonical(v); err == nil {
++			return info, err
++		}
+ 	}
+ 
+ 	// Look through the tags on the revision for either a usable canonical version
+ 	// or an appropriate base for a pseudo-version.
+-	var pseudoBase string
++	var (
++		highestCanonical string
++		pseudoBase       string
++	)
+ 	for _, pathTag := range info.Tags {
+ 		v, tagIsCanonical := tagToVersion(pathTag)
+-		if tagIsCanonical {
+-			if statVers != "" && semver.Compare(v, statVers) == 0 {
+-				// The user requested a non-canonical version, but the tag for the
+-				// canonical equivalent refers to the same revision. Use it.
+-				info2.Version = v
+-				return checkGoMod()
++		if statVers != "" && semver.Compare(v, statVers) == 0 {
++			// The tag is equivalent to the version requested by the user.
++			if tagIsCanonical {
++				// This tag is the canonical form of the requested version,
++				// not some other form with extra build metadata.
++				// Use this tag so that the resolved version will match exactly.
++				// (If it isn't actually allowed, we'll error out in checkCanonical.)
++				return checkCanonical(v)
+ 			} else {
+-				// Save the highest canonical tag for the revision. If we don't find a
+-				// better match, we'll use it as the canonical version.
++				// The user explicitly requested something equivalent to this tag. We
++				// can't use the version from the tag directly: since the tag is not
++				// canonical, it could be ambiguous. For example, tags v0.0.1+a and
++				// v0.0.1+b might both exist and refer to different revisions.
+ 				//
+-				// NOTE: Do not replace this with semver.Max. Despite the name,
+-				// semver.Max *also* canonicalizes its arguments, which uses
+-				// semver.Canonical instead of module.CanonicalVersion and thereby
+-				// strips our "+incompatible" suffix.
+-				if semver.Compare(info2.Version, v) < 0 {
+-					info2.Version = v
+-				}
++				// The tag is otherwise valid for the module, so we can at least use it as
++				// the base of an unambiguous pseudo-version.
++				//
++				// If multiple tags match, tagToVersion will canonicalize them to the same
++				// base version.
++				pseudoBase = v
++			}
++		}
++		// Save the highest non-retracted canonical tag for the revision.
++		// If we don't find a better match, we'll use it as the canonical version.
++		if tagIsCanonical && semver.Compare(highestCanonical, v) < 0 {
++			if module.MatchPathMajor(v, r.pathMajor) || canUseIncompatible() {
++				highestCanonical = v
+ 			}
+-		} else if v != "" && semver.Compare(v, statVers) == 0 {
+-			// The user explicitly requested something equivalent to this tag. We
+-			// can't use the version from the tag directly: since the tag is not
+-			// canonical, it could be ambiguous. For example, tags v0.0.1+a and
+-			// v0.0.1+b might both exist and refer to different revisions.
+-			//
+-			// The tag is otherwise valid for the module, so we can at least use it as
+-			// the base of an unambiguous pseudo-version.
+-			//
+-			// If multiple tags match, tagToVersion will canonicalize them to the same
+-			// base version.
+-			pseudoBase = v
+ 		}
+ 	}
+ 
+-	// If we found any canonical tag for the revision, return it.
++	// If we found a valid canonical tag for the revision, return it.
+ 	// Even if we found a good pseudo-version base, a canonical version is better.
+-	if info2.Version != "" {
+-		return checkGoMod()
++	if highestCanonical != "" {
++		return checkCanonical(highestCanonical)
+ 	}
+ 
+ 	if pseudoBase == "" {
+@@ -511,11 +513,10 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e
+ 				tag, _ = r.code.RecentTag(info.Name, tagPrefix, "v0")
+ 			}
+ 		}
+-		pseudoBase, _ = tagToVersion(tag) // empty if the tag is invalid
++		pseudoBase, _ = tagToVersion(tag)
+ 	}
+ 
+-	info2.Version = PseudoVersion(r.pseudoMajor, pseudoBase, info.Time, info.Short)
+-	return checkGoMod()
++	return checkCanonical(PseudoVersion(r.pseudoMajor, pseudoBase, info.Time, info.Short))
+ }
+ 
+ // validatePseudoVersion checks that version has a major version compatible with
+@@ -539,10 +540,6 @@ func (r *codeRepo) validatePseudoVersion(info *codehost.RevInfo, version string)
+ 		}
+ 	}()
+ 
+-	if err := module.CheckPathMajor(version, r.pathMajor); err != nil {
+-		return err
+-	}
+-
+ 	rev, err := PseudoVersionRev(version)
+ 	if err != nil {
+ 		return err
diff -Nru golang-1.15-1.15.15/debian/patches/series golang-1.15-1.15.15/debian/patches/series
--- golang-1.15-1.15.15/debian/patches/series	2021-12-04 17:37:57.000000000 +0800
+++ golang-1.15-1.15.15/debian/patches/series	2022-02-11 23:45:44.000000000 +0800
@@ -9,3 +9,6 @@
 0009-CVE-2021-41771.patch
 0010-CVE-2021-44716.patch
 0011-CVE-2021-44717.patch
+0012-CVE-2022-23806.patch
+0013-CVE-2022-23772.patch
+0014-CVE-2022-23773.patch

Reply to: