diff --git a/meta/recipes-devtools/go/go-1.17.13.inc b/meta/recipes-devtools/go/go-1.17.13.inc index b17853035b..2052f4adbc 100644 --- a/meta/recipes-devtools/go/go-1.17.13.inc +++ b/meta/recipes-devtools/go/go-1.17.13.inc @@ -4,67 +4,70 @@ FILESEXTRAPATHS:prepend := "${FILE_DIRNAME}/go-1.21:${FILE_DIRNAME}/go-1.20:${FI LIC_FILES_CHKSUM = "file://LICENSE;md5=5d4950ecb7b26d2c5e4e7b4e0dd74707" -SRC_URI += "\ - file://0001-allow-CC-and-CXX-to-have-multiple-words.patch \ - file://0002-cmd-go-make-content-based-hash-generation-less-pedan.patch \ - file://0003-allow-GOTOOLDIR-to-be-overridden-in-the-environment.patch \ - file://0004-ld-add-soname-to-shareable-objects.patch \ - file://0005-make.bash-override-CC-when-building-dist-and-go_boot.patch \ - 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://0009-Revert-cmd-go-make-sure-CC-and-CXX-are-absolute.patch \ - file://0001-exec.go-do-not-write-linker-flags-into-buildids.patch \ - file://0001-src-cmd-dist-buildgo.go-do-not-hardcode-host-compile.patch \ - file://0010-net-Fix-issue-with-DNS-not-being-updated.patch \ - file://CVE-2022-27664.patch \ - file://0001-net-http-httputil-avoid-query-parameter-smuggling.patch \ - file://CVE-2022-41715.patch \ - file://CVE-2022-41717.patch \ - file://CVE-2022-2879.patch \ - file://CVE-2022-41720.patch \ - file://CVE-2022-41723.patch \ - file://cve-2022-41724.patch \ - file://add_godebug.patch \ - file://cve-2022-41725.patch \ - file://CVE-2022-41722.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-24540.patch \ - file://CVE-2023-24539.patch \ - file://CVE-2023-29404.patch \ - file://CVE-2023-29405.patch \ - file://CVE-2023-29402.patch \ - file://CVE-2023-29400.patch \ - file://CVE-2023-29406-1.patch \ - file://CVE-2023-29406-2.patch \ - file://CVE-2023-24536_1.patch \ - file://CVE-2023-24536_2.patch \ - file://CVE-2023-24536_3.patch \ - file://CVE-2023-24531_1.patch \ - file://CVE-2023-24531_2.patch \ - file://CVE-2023-29409.patch \ - file://CVE-2023-39319.patch \ - file://CVE-2023-39318.patch \ - file://CVE-2023-39326.patch \ - file://CVE-2023-45285.patch \ - file://CVE-2023-45287.patch \ - file://CVE-2023-45289.patch \ - file://CVE-2023-45290.patch \ - file://CVE-2024-24784.patch \ - file://CVE-2024-24785.patch \ - file://CVE-2023-45288.patch \ - file://CVE-2024-24789.patch \ - file://CVE-2024-24791.patch \ - file://CVE-2024-34155.patch \ - file://CVE-2024-34156.patch \ - file://CVE-2024-34158.patch \ - file://CVE-2024-45336.patch \ - file://CVE-2025-22871.patch \ - file://CVE-2025-4673.patch \ -" +SRC_URI = "https://golang.org/dl/go${PV}.src.tar.gz;name=main \ + file://0001-allow-CC-and-CXX-to-have-multiple-words.patch \ + file://0002-cmd-go-make-content-based-hash-generation-less-pedan.patch \ + file://0003-allow-GOTOOLDIR-to-be-overridden-in-the-environment.patch \ + file://0004-ld-add-soname-to-shareable-objects.patch \ + file://0005-make.bash-override-CC-when-building-dist-and-go_boot.patch \ + 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://0009-Revert-cmd-go-make-sure-CC-and-CXX-are-absolute.patch \ + file://0001-exec.go-do-not-write-linker-flags-into-buildids.patch \ + file://0001-src-cmd-dist-buildgo.go-do-not-hardcode-host-compile.patch \ + file://0010-net-Fix-issue-with-DNS-not-being-updated.patch \ + file://CVE-2022-27664.patch \ + file://0001-net-http-httputil-avoid-query-parameter-smuggling.patch \ + file://CVE-2022-41715.patch \ + file://CVE-2022-41717.patch \ + file://CVE-2022-2879.patch \ + file://CVE-2022-41720.patch \ + file://CVE-2022-41723.patch \ + file://cve-2022-41724.patch \ + file://add_godebug.patch \ + file://cve-2022-41725.patch \ + file://CVE-2022-41722.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-24540.patch \ + file://CVE-2023-24539.patch \ + file://CVE-2023-29404.patch \ + file://CVE-2023-29405.patch \ + file://CVE-2023-29402.patch \ + file://CVE-2023-29400.patch \ + file://CVE-2023-29406-1.patch \ + file://CVE-2023-29406-2.patch \ + file://CVE-2023-24536_1.patch \ + file://CVE-2023-24536_2.patch \ + file://CVE-2023-24536_3.patch \ + file://CVE-2023-24531_1.patch \ + file://CVE-2023-24531_2.patch \ + file://CVE-2023-29409.patch \ + file://CVE-2023-39319.patch \ + file://CVE-2023-39318.patch \ + file://CVE-2023-39326.patch \ + file://CVE-2023-45285.patch \ + file://CVE-2023-45287.patch \ + file://CVE-2023-45289.patch \ + file://CVE-2023-45290.patch \ + file://CVE-2024-24784.patch \ + file://CVE-2024-24785.patch \ + file://CVE-2023-45288.patch \ + file://CVE-2024-24789.patch \ + file://CVE-2024-24791.patch \ + file://CVE-2024-34155.patch \ + file://CVE-2024-34156.patch \ + file://CVE-2024-34158.patch \ + file://CVE-2024-45336.patch \ + file://CVE-2025-22871.patch \ + file://CVE-2025-4673.patch \ + file://CVE-2025-47907-pre-0001.patch \ + file://CVE-2025-47907-pre-0002.patch \ + file://CVE-2025-47907.patch \ + " SRC_URI[main.sha256sum] = "a1a48b23afb206f95e7bbaa9b898d965f90826f6f1d1fc0c1d784ada0cd300fd" # Upstream don't believe it is a signifiant real world issue and will only diff --git a/meta/recipes-devtools/go/go-1.21/CVE-2025-47907-pre-0001.patch b/meta/recipes-devtools/go/go-1.21/CVE-2025-47907-pre-0001.patch new file mode 100644 index 0000000000..97e7539dc3 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.21/CVE-2025-47907-pre-0001.patch @@ -0,0 +1,354 @@ +From 298fe517a9333c05143a8a8e1f9d5499f0c6e59b Mon Sep 17 00:00:00 2001 +From: Brad Fitzpatrick +Date: Tue, 23 May 2023 15:12:47 -0700 +Subject: [PATCH] database/sql: make RawBytes safely usable with contexts + +sql.RawBytes was added the very first Go release, Go 1. Its docs +say: + +> RawBytes is a byte slice that holds a reference to memory owned by +> the database itself. After a Scan into a RawBytes, the slice is only +> valid until the next call to Next, Scan, or Close. + +That "only valid until the next call" bit was true at the time, +until contexts were added to database/sql in Go 1.8. + +In the past ~dozen releases it's been unsafe to use QueryContext with +a context that might become Done to get an *sql.Rows that's scanning +into a RawBytes. The Scan can succeed, but then while the caller's +reading the memory, a database/sql-managed goroutine can see the +context becoming done and call Close on the database/sql/driver and +make the caller's view of the RawBytes memory no longer valid, +introducing races, crashes, or database corruption. See #60304 +and #53970 for details. + +This change does the minimal surgery on database/sql to make it safe +again: Rows.Scan was already acquiring a mutex to check whether the +rows had been closed, so this change make Rows.Scan notice whether +*RawBytes was used and, if so, doesn't release the mutex on exit +before returning. That mean it's still locked while the user code +operates on the RawBytes memory and the concurrent context-watching +goroutine to close the database still runs, but if it fires, it then +gets blocked on the mutex until the next call to a Rows method (Next, +NextResultSet, Err, Close). + +Updates #60304 +Updates #53970 (earlier one I'd missed) + +Change-Id: Ie41c0c6f32c24887b2f53ec3686c2aab73a1bfff +Reviewed-on: https://go-review.googlesource.com/c/go/+/497675 +TryBot-Result: Gopher Robot +Reviewed-by: Ian Lance Taylor +Run-TryBot: Brad Fitzpatrick +Auto-Submit: Ian Lance Taylor +Reviewed-by: Russ Cox + +CVE: CVE-2025-47907 + +Upstream-Status: Backport [https://github.com/golang/go/commit/298fe517a9333c05143a8a8e1f9d5499f0c6e59b] + +Signed-off-by: Praveen Kumar +--- + src/database/sql/fakedb_test.go | 13 +++++- + src/database/sql/sql.go | 72 ++++++++++++++++++++++++++++++++- + src/database/sql/sql_test.go | 58 ++++++++++++++++++++++++++ + 3 files changed, 141 insertions(+), 2 deletions(-) + +diff --git a/src/database/sql/fakedb_test.go b/src/database/sql/fakedb_test.go +index 4b68f1c..33c57b9 100644 +--- a/src/database/sql/fakedb_test.go ++++ b/src/database/sql/fakedb_test.go +@@ -15,6 +15,7 @@ import ( + "strconv" + "strings" + "sync" ++ "sync/atomic" + "testing" + "time" + ) +@@ -90,6 +91,8 @@ func (cc *fakeDriverCtx) OpenConnector(name string) (driver.Connector, error) { + type fakeDB struct { + name string + ++ useRawBytes atomic.Bool ++ + mu sync.Mutex + tables map[string]*table + badConn bool +@@ -680,6 +683,8 @@ func (c *fakeConn) PrepareContext(ctx context.Context, query string) (driver.Stm + switch cmd { + case "WIPE": + // Nothing ++ case "USE_RAWBYTES": ++ c.db.useRawBytes.Store(true) + case "SELECT": + stmt, err = c.prepareSelect(stmt, parts) + case "CREATE": +@@ -783,6 +788,9 @@ func (s *fakeStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (d + case "WIPE": + db.wipe() + return driver.ResultNoRows, nil ++ case "USE_RAWBYTES": ++ s.c.db.useRawBytes.Store(true) ++ return driver.ResultNoRows, nil + case "CREATE": + if err := db.createTable(s.table, s.colName, s.colType); err != nil { + return nil, err +@@ -912,6 +920,7 @@ func (s *fakeStmt) QueryContext(ctx context.Context, args []driver.NamedValue) ( + txStatus = "transaction" + } + cursor := &rowsCursor{ ++ db: s.c.db, + parentMem: s.c, + posRow: -1, + rows: [][]*row{ +@@ -1008,6 +1017,7 @@ func (s *fakeStmt) QueryContext(ctx context.Context, args []driver.NamedValue) ( + } + + cursor := &rowsCursor{ ++ db: s.c.db, + parentMem: s.c, + posRow: -1, + rows: setMRows, +@@ -1050,6 +1060,7 @@ func (tx *fakeTx) Rollback() error { + } + + type rowsCursor struct { ++ db *fakeDB + parentMem memToucher + cols [][]string + colType [][]string +@@ -1121,7 +1132,7 @@ func (rc *rowsCursor) Next(dest []driver.Value) error { + // messing up conversions or doing them differently. + dest[i] = v + +- if bs, ok := v.([]byte); ok { ++ if bs, ok := v.([]byte); ok && !rc.db.useRawBytes.Load() { + if rc.bytesClone == nil { + rc.bytesClone = make(map[*byte][]byte) + } +diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go +index 68fb392..ef49e70 100644 +--- a/src/database/sql/sql.go ++++ b/src/database/sql/sql.go +@@ -2879,6 +2879,8 @@ type Rows struct { + cancel func() // called when Rows is closed, may be nil. + closeStmt *driverStmt // if non-nil, statement to Close on close + ++ contextDone atomic.Value // error that awaitDone saw; set before close attempt ++ + // closemu prevents Rows from closing while there + // is an active streaming result. It is held for read during non-close operations + // and exclusively during close. +@@ -2891,6 +2893,15 @@ type Rows struct { + // lastcols is only used in Scan, Next, and NextResultSet which are expected + // not to be called concurrently. + lastcols []driver.Value ++ ++ // closemuScanHold is whether the previous call to Scan kept closemu RLock'ed ++ // without unlocking it. It does that when the user passes a *RawBytes scan ++ // target. In that case, we need to prevent awaitDone from closing the Rows ++ // while the user's still using the memory. See go.dev/issue/60304. ++ // ++ // It is only used by Scan, Next, and NextResultSet which are expected ++ // not to be called concurrently. ++ closemuScanHold bool + } + + // lasterrOrErrLocked returns either lasterr or the provided err. +@@ -2928,7 +2939,11 @@ func (rs *Rows) awaitDone(ctx, txctx context.Context) { + } + select { + case <-ctx.Done(): ++ err := ctx.Err() ++ rs.contextDone.Store(&err) + case <-txctxDone: ++ err := txctx.Err() ++ rs.contextDone.Store(&err) + } + rs.close(ctx.Err()) + } +@@ -2940,6 +2955,15 @@ func (rs *Rows) awaitDone(ctx, txctx context.Context) { + // + // Every call to Scan, even the first one, must be preceded by a call to Next. + func (rs *Rows) Next() bool { ++ // If the user's calling Next, they're done with their previous row's Scan ++ // results (any RawBytes memory), so we can release the read lock that would ++ // be preventing awaitDone from calling close. ++ rs.closemuRUnlockIfHeldByScan() ++ ++ if rs.contextDone.Load() != nil { ++ return false ++ } ++ + var doClose, ok bool + withLock(rs.closemu.RLocker(), func() { + doClose, ok = rs.nextLocked() +@@ -2994,6 +3018,11 @@ func (rs *Rows) nextLocked() (doClose, ok bool) { + // scanning. If there are further result sets they may not have rows in the result + // set. + func (rs *Rows) NextResultSet() bool { ++ // If the user's calling NextResultSet, they're done with their previous ++ // row's Scan results (any RawBytes memory), so we can release the read lock ++ // that would be preventing awaitDone from calling close. ++ rs.closemuRUnlockIfHeldByScan() ++ + var doClose bool + defer func() { + if doClose { +@@ -3030,6 +3059,10 @@ func (rs *Rows) NextResultSet() bool { + // Err returns the error, if any, that was encountered during iteration. + // Err may be called after an explicit or implicit Close. + func (rs *Rows) Err() error { ++ if errp := rs.contextDone.Load(); errp != nil { ++ return *(errp.(*error)) ++ } ++ + rs.closemu.RLock() + defer rs.closemu.RUnlock() + return rs.lasterrOrErrLocked(nil) +@@ -3223,6 +3256,11 @@ func rowsColumnInfoSetupConnLocked(rowsi driver.Rows) []*ColumnType { + // If any of the first arguments implementing Scanner returns an error, + // that error will be wrapped in the returned error + func (rs *Rows) Scan(dest ...interface{}) error { ++ if rs.closemuScanHold { ++ // This should only be possible if the user calls Scan twice in a row ++ // without calling Next. ++ return fmt.Errorf("sql: Scan called without calling Next (closemuScanHold)") ++ } + rs.closemu.RLock() + + if rs.lasterr != nil && rs.lasterr != io.EOF { +@@ -3234,23 +3272,50 @@ func (rs *Rows) Scan(dest ...interface{}) error { + rs.closemu.RUnlock() + return err + } +- rs.closemu.RUnlock() ++ ++ if scanArgsContainRawBytes(dest) { ++ rs.closemuScanHold = true ++ } else { ++ rs.closemu.RUnlock() ++ } + + if rs.lastcols == nil { ++ rs.closemuRUnlockIfHeldByScan() + return errors.New("sql: Scan called without calling Next") + } + if len(dest) != len(rs.lastcols) { ++ rs.closemuRUnlockIfHeldByScan() + return fmt.Errorf("sql: expected %d destination arguments in Scan, not %d", len(rs.lastcols), len(dest)) + } ++ + for i, sv := range rs.lastcols { + err := convertAssignRows(dest[i], sv, rs) + if err != nil { ++ rs.closemuRUnlockIfHeldByScan() + return fmt.Errorf(`sql: Scan error on column index %d, name %q: %w`, i, rs.rowsi.Columns()[i], err) + } + } + return nil + } + ++// closemuRUnlockIfHeldByScan releases any closemu.RLock held open by a previous ++// call to Scan with *RawBytes. ++func (rs *Rows) closemuRUnlockIfHeldByScan() { ++ if rs.closemuScanHold { ++ rs.closemuScanHold = false ++ rs.closemu.RUnlock() ++ } ++} ++ ++func scanArgsContainRawBytes(args []interface{}) bool { ++ for _, a := range args { ++ if _, ok := a.(*RawBytes); ok { ++ return true ++ } ++ } ++ return false ++} ++ + // rowsCloseHook returns a function so tests may install the + // hook through a test only mutex. + var rowsCloseHook = func() func(*Rows, *error) { return nil } +@@ -3260,6 +3325,11 @@ var rowsCloseHook = func() func(*Rows, *error) { return nil } + // the Rows are closed automatically and it will suffice to check the + // result of Err. Close is idempotent and does not affect the result of Err. + func (rs *Rows) Close() error { ++ // If the user's calling Close, they're done with their previous row's Scan ++ // results (any RawBytes memory), so we can release the read lock that would ++ // be preventing awaitDone from calling the unexported close before we do so. ++ rs.closemuRUnlockIfHeldByScan() ++ + return rs.close(nil) + } + +diff --git a/src/database/sql/sql_test.go b/src/database/sql/sql_test.go +index f771dee..53b38d1 100644 +--- a/src/database/sql/sql_test.go ++++ b/src/database/sql/sql_test.go +@@ -4255,6 +4255,64 @@ func TestRowsScanProperlyWrapsErrors(t *testing.T) { + } + } + ++// From go.dev/issue/60304 ++func TestContextCancelDuringRawBytesScan(t *testing.T) { ++ db := newTestDB(t, "people") ++ defer closeDB(t, db) ++ ++ if _, err := db.Exec("USE_RAWBYTES"); err != nil { ++ t.Fatal(err) ++ } ++ ++ ctx, cancel := context.WithCancel(context.Background()) ++ defer cancel() ++ ++ r, err := db.QueryContext(ctx, "SELECT|people|name|") ++ if err != nil { ++ t.Fatal(err) ++ } ++ numRows := 0 ++ var sink byte ++ for r.Next() { ++ numRows++ ++ var s RawBytes ++ err = r.Scan(&s) ++ if !r.closemuScanHold { ++ t.Errorf("expected closemu to be held") ++ } ++ if err != nil { ++ t.Fatal(err) ++ } ++ t.Logf("read %q", s) ++ if numRows == 2 { ++ cancel() // invalidate the context, which used to call close asynchronously ++ } ++ for _, b := range s { // some operation reading from the raw memory ++ sink += b ++ } ++ } ++ if r.closemuScanHold { ++ t.Errorf("closemu held; should not be") ++ } ++ ++ // There are 3 rows. We canceled after reading 2 so we expect either ++ // 2 or 3 depending on how the awaitDone goroutine schedules. ++ switch numRows { ++ case 0, 1: ++ t.Errorf("got %d rows; want 2+", numRows) ++ case 2: ++ if err := r.Err(); err != context.Canceled { ++ t.Errorf("unexpected error: %v (%T)", err, err) ++ } ++ default: ++ // Made it to the end. This is rare, but fine. Permit it. ++ } ++ ++ if err := r.Close(); err != nil { ++ t.Fatal(err) ++ } ++} ++ + // badConn implements a bad driver.Conn, for TestBadDriver. + // The Exec method panics. + type badConn struct{} diff --git a/meta/recipes-devtools/go/go-1.21/CVE-2025-47907-pre-0002.patch b/meta/recipes-devtools/go/go-1.21/CVE-2025-47907-pre-0002.patch new file mode 100644 index 0000000000..fe0b6a4d9c --- /dev/null +++ b/meta/recipes-devtools/go/go-1.21/CVE-2025-47907-pre-0002.patch @@ -0,0 +1,232 @@ +From c23579f031ecd09bf37c644723b33736dffa8b92 Mon Sep 17 00:00:00 2001 +From: Damien Neil +Date: Tue, 23 Jan 2024 15:59:47 -0800 +Subject: [PATCH] database/sql: avoid clobbering driver-owned memory in + RawBytes + +Depending on the query, a RawBytes can contain memory owned by the +driver or by database/sql: + +If the driver provides the column as a []byte, +RawBytes aliases that []byte. + +If the driver provides the column as any other type, +RawBytes contains memory allocated by database/sql. +Prior to this CL, Rows.Scan will reuse existing capacity in a +RawBytes to permit a single allocation to be reused across rows. + +When a RawBytes is reused across queries, this can result +in database/sql writing to driver-owned memory. + +Add a buffer to Rows to store RawBytes data, and reuse this +buffer across calls to Rows.Scan. + +Fixes #65201 + +Change-Id: Iac640174c7afa97eeb39496f47dec202501b2483 +Reviewed-on: https://go-review.googlesource.com/c/go/+/557917 +Reviewed-by: Brad Fitzpatrick +Reviewed-by: Roland Shoemaker +LUCI-TryBot-Result: Go LUCI + +CVE: CVE-2025-47907 + +Upstream-Status: Backport [https://github.com/golang/go/commit/c23579f031ecd09bf37c644723b33736dffa8b92] + +Signed-off-by: Praveen Kumar +--- + src/database/sql/convert.go | 8 +++--- + src/database/sql/convert_test.go | 14 +++++++--- + src/database/sql/sql.go | 34 +++++++++++++++++++++++ + src/database/sql/sql_test.go | 47 ++++++++++++++++++++++++++++++++ + 4 files changed, 95 insertions(+), 8 deletions(-) + +diff --git a/src/database/sql/convert.go b/src/database/sql/convert.go +index b966ef9..3a581f6 100644 +--- a/src/database/sql/convert.go ++++ b/src/database/sql/convert.go +@@ -237,7 +237,7 @@ func convertAssignRows(dest, src interface{}, rows *Rows) error { + if d == nil { + return errNilPtr + } +- *d = append((*d)[:0], s...) ++ *d = rows.setrawbuf(append(rows.rawbuf(), s...)) + return nil + } + case []byte: +@@ -285,7 +285,7 @@ func convertAssignRows(dest, src interface{}, rows *Rows) error { + if d == nil { + return errNilPtr + } +- *d = s.AppendFormat((*d)[:0], time.RFC3339Nano) ++ *d = rows.setrawbuf(s.AppendFormat(rows.rawbuf(), time.RFC3339Nano)) + return nil + } + case decimalDecompose: +@@ -366,8 +366,8 @@ func convertAssignRows(dest, src interface{}, rows *Rows) error { + } + case *RawBytes: + sv = reflect.ValueOf(src) +- if b, ok := asBytes([]byte(*d)[:0], sv); ok { +- *d = RawBytes(b) ++ if b, ok := asBytes(rows.rawbuf(), sv); ok { ++ *d = rows.setrawbuf(b) + return nil + } + case *bool: +diff --git a/src/database/sql/convert_test.go b/src/database/sql/convert_test.go +index 2668a5e..23a70bf 100644 +--- a/src/database/sql/convert_test.go ++++ b/src/database/sql/convert_test.go +@@ -357,9 +357,10 @@ func TestRawBytesAllocs(t *testing.T) { + {"time", time.Unix(2, 5).UTC(), "1970-01-01T00:00:02.000000005Z"}, + } + +- buf := make(RawBytes, 10) +- test := func(name string, in interface{}, want string) { +- if err := convertAssign(&buf, in); err != nil { ++ var buf RawBytes ++ rows := &Rows{} ++ test := func(name string, in interface{}, want string) { ++ if err := convertAssignRows(&buf, in, rows); err != nil { + t.Fatalf("%s: convertAssign = %v", name, err) + } + match := len(buf) == len(want) +@@ -378,6 +379,7 @@ func TestRawBytesAllocs(t *testing.T) { + + n := testing.AllocsPerRun(100, func() { + for _, tt := range tests { ++ rows.raw = rows.raw[:0] + test(tt.name, tt.in, tt.want) + } + }) +@@ -386,7 +388,11 @@ func TestRawBytesAllocs(t *testing.T) { + // and gc. With 32-bit words there are more convT2E allocs, and + // with gccgo, only pointers currently go in interface data. + // So only care on amd64 gc for now. +- measureAllocs := runtime.GOARCH == "amd64" && runtime.Compiler == "gc" ++ measureAllocs := false ++ switch runtime.GOARCH { ++ case "amd64", "arm64": ++ measureAllocs = runtime.Compiler == "gc" ++ } + + if n > 0.5 && measureAllocs { + t.Fatalf("allocs = %v; want 0", n) +diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go +index ef49e70..e25447c 100644 +--- a/src/database/sql/sql.go ++++ b/src/database/sql/sql.go +@@ -2894,6 +2894,13 @@ type Rows struct { + // not to be called concurrently. + lastcols []driver.Value + ++ // raw is a buffer for RawBytes that persists between Scan calls. ++ // This is used when the driver returns a mismatched type that requires ++ // a cloning allocation. For example, if the driver returns a *string and ++ // the user is scanning into a *RawBytes, we need to copy the string. ++ // The raw buffer here lets us reuse the memory for that copy across Scan calls. ++ raw []byte ++ + // closemuScanHold is whether the previous call to Scan kept closemu RLock'ed + // without unlocking it. It does that when the user passes a *RawBytes scan + // target. In that case, we need to prevent awaitDone from closing the Rows +@@ -3068,6 +3075,32 @@ func (rs *Rows) Err() error { + return rs.lasterrOrErrLocked(nil) + } + ++// rawbuf returns the buffer to append RawBytes values to. ++// This buffer is reused across calls to Rows.Scan. ++// ++// Usage: ++// ++// rawBytes = rows.setrawbuf(append(rows.rawbuf(), value...)) ++func (rs *Rows) rawbuf() []byte { ++ if rs == nil { ++ // convertAssignRows can take a nil *Rows; for simplicity handle it here ++ return nil ++ } ++ return rs.raw ++} ++ ++// setrawbuf updates the RawBytes buffer with the result of appending a new value to it. ++// It returns the new value. ++func (rs *Rows) setrawbuf(b []byte) RawBytes { ++ if rs == nil { ++ // convertAssignRows can take a nil *Rows; for simplicity handle it here ++ return RawBytes(b) ++ } ++ off := len(rs.raw) ++ rs.raw = b ++ return RawBytes(rs.raw[off:]) ++} ++ + var errRowsClosed = errors.New("sql: Rows are closed") + var errNoRows = errors.New("sql: no Rows available") + +@@ -3275,6 +3308,7 @@ func (rs *Rows) Scan(dest ...interface{}) error { + + if scanArgsContainRawBytes(dest) { + rs.closemuScanHold = true ++ rs.raw = rs.raw[:0] + } else { + rs.closemu.RUnlock() + } +diff --git a/src/database/sql/sql_test.go b/src/database/sql/sql_test.go +index 53b38d1..6aa9bf0 100644 +--- a/src/database/sql/sql_test.go ++++ b/src/database/sql/sql_test.go +@@ -4313,6 +4313,53 @@ func TestContextCancelDuringRawBytesScan(t *testing.T) { + } + } + ++// Issue #65201. ++// ++// If a RawBytes is reused across multiple queries, ++// subsequent queries shouldn't overwrite driver-owned memory from previous queries. ++func TestRawBytesReuse(t *testing.T) { ++ db := newTestDB(t, "people") ++ defer closeDB(t, db) ++ ++ if _, err := db.Exec("USE_RAWBYTES"); err != nil { ++ t.Fatal(err) ++ } ++ ++ var raw RawBytes ++ ++ // The RawBytes in this query aliases driver-owned memory. ++ rows, err := db.Query("SELECT|people|name|") ++ if err != nil { ++ t.Fatal(err) ++ } ++ rows.Next() ++ rows.Scan(&raw) // now raw is pointing to driver-owned memory ++ name1 := string(raw) ++ rows.Close() ++ ++ // The RawBytes in this query does not alias driver-owned memory. ++ rows, err = db.Query("SELECT|people|age|") ++ if err != nil { ++ t.Fatal(err) ++ } ++ rows.Next() ++ rows.Scan(&raw) // this must not write to the driver-owned memory in raw ++ rows.Close() ++ ++ // Repeat the first query. Nothing should have changed. ++ rows, err = db.Query("SELECT|people|name|") ++ if err != nil { ++ t.Fatal(err) ++ } ++ rows.Next() ++ rows.Scan(&raw) // raw points to driver-owned memory again ++ name2 := string(raw) ++ rows.Close() ++ if name1 != name2 { ++ t.Fatalf("Scan read name %q, want %q", name2, name1) ++ } ++} ++ + // badConn implements a bad driver.Conn, for TestBadDriver. + // The Exec method panics. + type badConn struct{} diff --git a/meta/recipes-devtools/go/go-1.21/CVE-2025-47907.patch b/meta/recipes-devtools/go/go-1.21/CVE-2025-47907.patch new file mode 100644 index 0000000000..b2af7df81b --- /dev/null +++ b/meta/recipes-devtools/go/go-1.21/CVE-2025-47907.patch @@ -0,0 +1,327 @@ +From 8a924caaf348fdc366bab906424616b2974ad4e9 Mon Sep 17 00:00:00 2001 +From: Damien Neil +Date: Wed, 23 Jul 2025 14:26:54 -0700 +Subject: [PATCH] database/sql: avoid closing Rows while scan is in progress + +A database/sql/driver.Rows can return database-owned data +from Rows.Next. The driver.Rows documentation doesn't explicitly +document the lifetime guarantees for this data, but a reasonable +expectation is that the caller of Next should only access it +until the next call to Rows.Close or Rows.Next. + +Avoid violating that constraint when a query is cancelled while +a call to database/sql.Rows.Scan (note the difference between +the two different Rows types!) is in progress. We previously +took care to avoid closing a driver.Rows while the user has +access to driver-owned memory via a RawData, but we could still +close a driver.Rows while a Scan call was in the process of +reading previously-returned driver-owned data. + +Update the fake DB used in database/sql tests to invalidate +returned data to help catch other places we might be +incorrectly retaining it. + +Updates #74831 +Fixes #74832 + +Change-Id: Ice45b5fad51b679c38e3e1d21ef39156b56d6037 +Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2540 +Reviewed-by: Roland Shoemaker +Reviewed-by: Neal Patel +Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2601 +Reviewed-on: https://go-review.googlesource.com/c/go/+/693558 +TryBot-Bypass: Dmitri Shuralyov +Reviewed-by: Mark Freeman +Reviewed-by: Dmitri Shuralyov +Auto-Submit: Dmitri Shuralyov + +CVE: CVE-2025-47907 + +Upstream-Status: Backport [https://github.com/golang/go/commit/8a924caaf348fdc366bab906424616b2974ad4e9] + +Signed-off-by: Praveen Kumar +--- + src/database/sql/convert.go | 2 -- + src/database/sql/fakedb_test.go | 47 ++++++++++++-------------- + src/database/sql/sql.go | 26 +++++++------- + src/database/sql/sql_test.go | 60 ++++++++++++++++++++++++++++++--- + 4 files changed, 90 insertions(+), 45 deletions(-) + +diff --git a/src/database/sql/convert.go b/src/database/sql/convert.go +index 3a581f6..5b0c6f0 100644 +--- a/src/database/sql/convert.go ++++ b/src/database/sql/convert.go +@@ -324,7 +324,6 @@ func convertAssignRows(dest, src interface{}, rows *Rows) error { + if rows == nil { + return errors.New("invalid context to convert cursor rows, missing parent *Rows") + } +- rows.closemu.Lock() + *d = Rows{ + dc: rows.dc, + releaseConn: func(error) {}, +@@ -340,7 +339,6 @@ func convertAssignRows(dest, src interface{}, rows *Rows) error { + parentCancel() + } + } +- rows.closemu.Unlock() + return nil + } + } +diff --git a/src/database/sql/fakedb_test.go b/src/database/sql/fakedb_test.go +index 33c57b9..9f3d517 100644 +--- a/src/database/sql/fakedb_test.go ++++ b/src/database/sql/fakedb_test.go +@@ -5,6 +5,7 @@ + package sql + + import ( ++ "bytes" + "context" + "database/sql/driver" + "errors" +@@ -15,7 +16,6 @@ import ( + "strconv" + "strings" + "sync" +- "sync/atomic" + "testing" + "time" + ) +@@ -91,8 +91,6 @@ func (cc *fakeDriverCtx) OpenConnector(name string) (driver.Connector, error) { + type fakeDB struct { + name string + +- useRawBytes atomic.Bool +- + mu sync.Mutex + tables map[string]*table + badConn bool +@@ -683,8 +681,6 @@ func (c *fakeConn) PrepareContext(ctx context.Context, query string) (driver.Stm + switch cmd { + case "WIPE": + // Nothing +- case "USE_RAWBYTES": +- c.db.useRawBytes.Store(true) + case "SELECT": + stmt, err = c.prepareSelect(stmt, parts) + case "CREATE": +@@ -788,9 +784,6 @@ func (s *fakeStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (d + case "WIPE": + db.wipe() + return driver.ResultNoRows, nil +- case "USE_RAWBYTES": +- s.c.db.useRawBytes.Store(true) +- return driver.ResultNoRows, nil + case "CREATE": + if err := db.createTable(s.table, s.colName, s.colType); err != nil { + return nil, err +@@ -1073,10 +1066,9 @@ type rowsCursor struct { + errPos int + err error + +- // a clone of slices to give out to clients, indexed by the +- // original slice's first byte address. we clone them +- // just so we're able to corrupt them on close. +- bytesClone map[*byte][]byte ++ // Data returned to clients. ++ // We clone and stash it here so it can be invalidated by Close and Next. ++ driverOwnedMemory [][]byte + + // Every operation writes to line to enable the race detector + // check for data races. +@@ -1090,9 +1082,19 @@ func (rc *rowsCursor) touchMem() { + rc.line++ + } + ++func (rc *rowsCursor) invalidateDriverOwnedMemory() { ++ for _, buf := range rc.driverOwnedMemory { ++ for i := range buf { ++ buf[i] = 'x' ++ } ++ } ++ rc.driverOwnedMemory = nil ++} ++ + func (rc *rowsCursor) Close() error { + rc.touchMem() + rc.parentMem.touchMem() ++ rc.invalidateDriverOwnedMemory() + rc.closed = true + return nil + } +@@ -1123,6 +1125,8 @@ func (rc *rowsCursor) Next(dest []driver.Value) error { + if rc.posRow >= len(rc.rows[rc.posSet]) { + return io.EOF // per interface spec + } ++ // Corrupt any previously returned bytes. ++ rc.invalidateDriverOwnedMemory() + for i, v := range rc.rows[rc.posSet][rc.posRow].cols { + // TODO(bradfitz): convert to subset types? naah, I + // think the subset types should only be input to +@@ -1130,20 +1134,13 @@ func (rc *rowsCursor) Next(dest []driver.Value) error { + // a wider range of types coming out of drivers. all + // for ease of drivers, and to prevent drivers from + // messing up conversions or doing them differently. +- dest[i] = v +- +- if bs, ok := v.([]byte); ok && !rc.db.useRawBytes.Load() { +- if rc.bytesClone == nil { +- rc.bytesClone = make(map[*byte][]byte) +- } +- clone, ok := rc.bytesClone[&bs[0]] +- if !ok { +- clone = make([]byte, len(bs)) +- copy(clone, bs) +- rc.bytesClone[&bs[0]] = clone +- } +- dest[i] = clone ++ if bs, ok := v.([]byte); ok { ++ // Clone []bytes and stash for later invalidation. ++ bs = bytes.Clone(bs) ++ rc.driverOwnedMemory = append(rc.driverOwnedMemory, bs) ++ v = bs + } ++ dest[i] = v + } + return nil + } +diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go +index e25447c..a428e29 100644 +--- a/src/database/sql/sql.go ++++ b/src/database/sql/sql.go +@@ -3294,38 +3294,36 @@ func (rs *Rows) Scan(dest ...interface{}) error { + // without calling Next. + return fmt.Errorf("sql: Scan called without calling Next (closemuScanHold)") + } ++ + rs.closemu.RLock() ++ rs.raw = rs.raw[:0] ++ err := rs.scanLocked(dest...) ++ if err == nil && scanArgsContainRawBytes(dest) { ++ rs.closemuScanHold = true ++ } else { ++ rs.closemu.RUnlock() ++ } ++ return err ++} + ++func (rs *Rows) scanLocked(dest ...interface{}) error { + if rs.lasterr != nil && rs.lasterr != io.EOF { +- rs.closemu.RUnlock() + return rs.lasterr + } + if rs.closed { +- err := rs.lasterrOrErrLocked(errRowsClosed) +- rs.closemu.RUnlock() +- return err +- } +- +- if scanArgsContainRawBytes(dest) { +- rs.closemuScanHold = true +- rs.raw = rs.raw[:0] +- } else { +- rs.closemu.RUnlock() ++ return rs.lasterrOrErrLocked(errRowsClosed) + } + + if rs.lastcols == nil { +- rs.closemuRUnlockIfHeldByScan() + return errors.New("sql: Scan called without calling Next") + } + if len(dest) != len(rs.lastcols) { +- rs.closemuRUnlockIfHeldByScan() + return fmt.Errorf("sql: expected %d destination arguments in Scan, not %d", len(rs.lastcols), len(dest)) + } + + for i, sv := range rs.lastcols { + err := convertAssignRows(dest[i], sv, rs) + if err != nil { +- rs.closemuRUnlockIfHeldByScan() + return fmt.Errorf(`sql: Scan error on column index %d, name %q: %w`, i, rs.rowsi.Columns()[i], err) + } + } +diff --git a/src/database/sql/sql_test.go b/src/database/sql/sql_test.go +index 6aa9bf0..6aec7ec 100644 +--- a/src/database/sql/sql_test.go ++++ b/src/database/sql/sql_test.go +@@ -5,6 +5,7 @@ + package sql + + import ( ++ "bytes" + "context" + "database/sql/driver" + "errors" +@@ -4321,10 +4322,6 @@ func TestRawBytesReuse(t *testing.T) { + db := newTestDB(t, "people") + defer closeDB(t, db) + +- if _, err := db.Exec("USE_RAWBYTES"); err != nil { +- t.Fatal(err) +- } +- + var raw RawBytes + + // The RawBytes in this query aliases driver-owned memory. +@@ -4469,6 +4466,61 @@ func TestTypedString(t *testing.T) { + } + } + ++type testScanner struct { ++ scanf func(src any) error ++} ++ ++func (ts testScanner) Scan(src any) error { return ts.scanf(src) } ++ ++func TestContextCancelDuringScan(t *testing.T) { ++ db := newTestDB(t, "people") ++ defer closeDB(t, db) ++ ++ ctx, cancel := context.WithCancel(context.Background()) ++ defer cancel() ++ ++ scanStart := make(chan any) ++ scanEnd := make(chan error) ++ scanner := &testScanner{ ++ scanf: func(src any) error { ++ scanStart <- src ++ return <-scanEnd ++ }, ++ } ++ ++ // Start a query, and pause it mid-scan. ++ want := []byte("Alice") ++ r, err := db.QueryContext(ctx, "SELECT|people|name|name=?", string(want)) ++ if err != nil { ++ t.Fatal(err) ++ } ++ if !r.Next() { ++ t.Fatalf("r.Next() = false, want true") ++ } ++ go func() { ++ r.Scan(scanner) ++ }() ++ got := <-scanStart ++ defer close(scanEnd) ++ gotBytes, ok := got.([]byte) ++ if !ok { ++ t.Fatalf("r.Scan returned %T, want []byte", got) ++ } ++ if !bytes.Equal(gotBytes, want) { ++ t.Fatalf("before cancel: r.Scan returned %q, want %q", gotBytes, want) ++ } ++ ++ // Cancel the query. ++ // Sleep to give it a chance to finish canceling. ++ cancel() ++ time.Sleep(10 * time.Millisecond) ++ ++ // Cancelling the query should not have changed the result. ++ if !bytes.Equal(gotBytes, want) { ++ t.Fatalf("after cancel: r.Scan result is now %q, want %q", gotBytes, want) ++ } ++} ++ + func BenchmarkConcurrentDBExec(b *testing.B) { + b.ReportAllocs() + ct := new(concurrentDBExecTest)