summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--meta/recipes-devtools/go/go-1.17.13.inc125
-rw-r--r--meta/recipes-devtools/go/go-1.21/CVE-2025-47907-pre-0001.patch354
-rw-r--r--meta/recipes-devtools/go/go-1.21/CVE-2025-47907-pre-0002.patch232
-rw-r--r--meta/recipes-devtools/go/go-1.21/CVE-2025-47907.patch327
4 files changed, 977 insertions, 61 deletions
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
4 4
5LIC_FILES_CHKSUM = "file://LICENSE;md5=5d4950ecb7b26d2c5e4e7b4e0dd74707" 5LIC_FILES_CHKSUM = "file://LICENSE;md5=5d4950ecb7b26d2c5e4e7b4e0dd74707"
6 6
7SRC_URI += "\ 7SRC_URI = "https://golang.org/dl/go${PV}.src.tar.gz;name=main \
8 file://0001-allow-CC-and-CXX-to-have-multiple-words.patch \ 8 file://0001-allow-CC-and-CXX-to-have-multiple-words.patch \
9 file://0002-cmd-go-make-content-based-hash-generation-less-pedan.patch \ 9 file://0002-cmd-go-make-content-based-hash-generation-less-pedan.patch \
10 file://0003-allow-GOTOOLDIR-to-be-overridden-in-the-environment.patch \ 10 file://0003-allow-GOTOOLDIR-to-be-overridden-in-the-environment.patch \
11 file://0004-ld-add-soname-to-shareable-objects.patch \ 11 file://0004-ld-add-soname-to-shareable-objects.patch \
12 file://0005-make.bash-override-CC-when-building-dist-and-go_boot.patch \ 12 file://0005-make.bash-override-CC-when-building-dist-and-go_boot.patch \
13 file://0006-cmd-dist-separate-host-and-target-builds.patch \ 13 file://0006-cmd-dist-separate-host-and-target-builds.patch \
14 file://0007-cmd-go-make-GOROOT-precious-by-default.patch \ 14 file://0007-cmd-go-make-GOROOT-precious-by-default.patch \
15 file://0008-use-GOBUILDMODE-to-set-buildmode.patch \ 15 file://0008-use-GOBUILDMODE-to-set-buildmode.patch \
16 file://0009-Revert-cmd-go-make-sure-CC-and-CXX-are-absolute.patch \ 16 file://0009-Revert-cmd-go-make-sure-CC-and-CXX-are-absolute.patch \
17 file://0001-exec.go-do-not-write-linker-flags-into-buildids.patch \ 17 file://0001-exec.go-do-not-write-linker-flags-into-buildids.patch \
18 file://0001-src-cmd-dist-buildgo.go-do-not-hardcode-host-compile.patch \ 18 file://0001-src-cmd-dist-buildgo.go-do-not-hardcode-host-compile.patch \
19 file://0010-net-Fix-issue-with-DNS-not-being-updated.patch \ 19 file://0010-net-Fix-issue-with-DNS-not-being-updated.patch \
20 file://CVE-2022-27664.patch \ 20 file://CVE-2022-27664.patch \
21 file://0001-net-http-httputil-avoid-query-parameter-smuggling.patch \ 21 file://0001-net-http-httputil-avoid-query-parameter-smuggling.patch \
22 file://CVE-2022-41715.patch \ 22 file://CVE-2022-41715.patch \
23 file://CVE-2022-41717.patch \ 23 file://CVE-2022-41717.patch \
24 file://CVE-2022-2879.patch \ 24 file://CVE-2022-2879.patch \
25 file://CVE-2022-41720.patch \ 25 file://CVE-2022-41720.patch \
26 file://CVE-2022-41723.patch \ 26 file://CVE-2022-41723.patch \
27 file://cve-2022-41724.patch \ 27 file://cve-2022-41724.patch \
28 file://add_godebug.patch \ 28 file://add_godebug.patch \
29 file://cve-2022-41725.patch \ 29 file://cve-2022-41725.patch \
30 file://CVE-2022-41722.patch \ 30 file://CVE-2022-41722.patch \
31 file://CVE-2023-24537.patch \ 31 file://CVE-2023-24537.patch \
32 file://CVE-2023-24534.patch \ 32 file://CVE-2023-24534.patch \
33 file://CVE-2023-24538_1.patch \ 33 file://CVE-2023-24538_1.patch \
34 file://CVE-2023-24538_2.patch \ 34 file://CVE-2023-24538_2.patch \
35 file://CVE-2023-24540.patch \ 35 file://CVE-2023-24540.patch \
36 file://CVE-2023-24539.patch \ 36 file://CVE-2023-24539.patch \
37 file://CVE-2023-29404.patch \ 37 file://CVE-2023-29404.patch \
38 file://CVE-2023-29405.patch \ 38 file://CVE-2023-29405.patch \
39 file://CVE-2023-29402.patch \ 39 file://CVE-2023-29402.patch \
40 file://CVE-2023-29400.patch \ 40 file://CVE-2023-29400.patch \
41 file://CVE-2023-29406-1.patch \ 41 file://CVE-2023-29406-1.patch \
42 file://CVE-2023-29406-2.patch \ 42 file://CVE-2023-29406-2.patch \
43 file://CVE-2023-24536_1.patch \ 43 file://CVE-2023-24536_1.patch \
44 file://CVE-2023-24536_2.patch \ 44 file://CVE-2023-24536_2.patch \
45 file://CVE-2023-24536_3.patch \ 45 file://CVE-2023-24536_3.patch \
46 file://CVE-2023-24531_1.patch \ 46 file://CVE-2023-24531_1.patch \
47 file://CVE-2023-24531_2.patch \ 47 file://CVE-2023-24531_2.patch \
48 file://CVE-2023-29409.patch \ 48 file://CVE-2023-29409.patch \
49 file://CVE-2023-39319.patch \ 49 file://CVE-2023-39319.patch \
50 file://CVE-2023-39318.patch \ 50 file://CVE-2023-39318.patch \
51 file://CVE-2023-39326.patch \ 51 file://CVE-2023-39326.patch \
52 file://CVE-2023-45285.patch \ 52 file://CVE-2023-45285.patch \
53 file://CVE-2023-45287.patch \ 53 file://CVE-2023-45287.patch \
54 file://CVE-2023-45289.patch \ 54 file://CVE-2023-45289.patch \
55 file://CVE-2023-45290.patch \ 55 file://CVE-2023-45290.patch \
56 file://CVE-2024-24784.patch \ 56 file://CVE-2024-24784.patch \
57 file://CVE-2024-24785.patch \ 57 file://CVE-2024-24785.patch \
58 file://CVE-2023-45288.patch \ 58 file://CVE-2023-45288.patch \
59 file://CVE-2024-24789.patch \ 59 file://CVE-2024-24789.patch \
60 file://CVE-2024-24791.patch \ 60 file://CVE-2024-24791.patch \
61 file://CVE-2024-34155.patch \ 61 file://CVE-2024-34155.patch \
62 file://CVE-2024-34156.patch \ 62 file://CVE-2024-34156.patch \
63 file://CVE-2024-34158.patch \ 63 file://CVE-2024-34158.patch \
64 file://CVE-2024-45336.patch \ 64 file://CVE-2024-45336.patch \
65 file://CVE-2025-22871.patch \ 65 file://CVE-2025-22871.patch \
66 file://CVE-2025-4673.patch \ 66 file://CVE-2025-4673.patch \
67" 67 file://CVE-2025-47907-pre-0001.patch \
68 file://CVE-2025-47907-pre-0002.patch \
69 file://CVE-2025-47907.patch \
70 "
68SRC_URI[main.sha256sum] = "a1a48b23afb206f95e7bbaa9b898d965f90826f6f1d1fc0c1d784ada0cd300fd" 71SRC_URI[main.sha256sum] = "a1a48b23afb206f95e7bbaa9b898d965f90826f6f1d1fc0c1d784ada0cd300fd"
69 72
70# Upstream don't believe it is a signifiant real world issue and will only 73# 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 @@
1From 298fe517a9333c05143a8a8e1f9d5499f0c6e59b Mon Sep 17 00:00:00 2001
2From: Brad Fitzpatrick <bradfitz@golang.org>
3Date: Tue, 23 May 2023 15:12:47 -0700
4Subject: [PATCH] database/sql: make RawBytes safely usable with contexts
5
6sql.RawBytes was added the very first Go release, Go 1. Its docs
7say:
8
9> RawBytes is a byte slice that holds a reference to memory owned by
10> the database itself. After a Scan into a RawBytes, the slice is only
11> valid until the next call to Next, Scan, or Close.
12
13That "only valid until the next call" bit was true at the time,
14until contexts were added to database/sql in Go 1.8.
15
16In the past ~dozen releases it's been unsafe to use QueryContext with
17a context that might become Done to get an *sql.Rows that's scanning
18into a RawBytes. The Scan can succeed, but then while the caller's
19reading the memory, a database/sql-managed goroutine can see the
20context becoming done and call Close on the database/sql/driver and
21make the caller's view of the RawBytes memory no longer valid,
22introducing races, crashes, or database corruption. See #60304
23and #53970 for details.
24
25This change does the minimal surgery on database/sql to make it safe
26again: Rows.Scan was already acquiring a mutex to check whether the
27rows had been closed, so this change make Rows.Scan notice whether
28*RawBytes was used and, if so, doesn't release the mutex on exit
29before returning. That mean it's still locked while the user code
30operates on the RawBytes memory and the concurrent context-watching
31goroutine to close the database still runs, but if it fires, it then
32gets blocked on the mutex until the next call to a Rows method (Next,
33NextResultSet, Err, Close).
34
35Updates #60304
36Updates #53970 (earlier one I'd missed)
37
38Change-Id: Ie41c0c6f32c24887b2f53ec3686c2aab73a1bfff
39Reviewed-on: https://go-review.googlesource.com/c/go/+/497675
40TryBot-Result: Gopher Robot <gobot@golang.org>
41Reviewed-by: Ian Lance Taylor <iant@google.com>
42Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
43Auto-Submit: Ian Lance Taylor <iant@google.com>
44Reviewed-by: Russ Cox <rsc@golang.org>
45
46CVE: CVE-2025-47907
47
48Upstream-Status: Backport [https://github.com/golang/go/commit/298fe517a9333c05143a8a8e1f9d5499f0c6e59b]
49
50Signed-off-by: Praveen Kumar <praveen.kumar@windriver.com>
51---
52 src/database/sql/fakedb_test.go | 13 +++++-
53 src/database/sql/sql.go | 72 ++++++++++++++++++++++++++++++++-
54 src/database/sql/sql_test.go | 58 ++++++++++++++++++++++++++
55 3 files changed, 141 insertions(+), 2 deletions(-)
56
57diff --git a/src/database/sql/fakedb_test.go b/src/database/sql/fakedb_test.go
58index 4b68f1c..33c57b9 100644
59--- a/src/database/sql/fakedb_test.go
60+++ b/src/database/sql/fakedb_test.go
61@@ -15,6 +15,7 @@ import (
62 "strconv"
63 "strings"
64 "sync"
65+ "sync/atomic"
66 "testing"
67 "time"
68 )
69@@ -90,6 +91,8 @@ func (cc *fakeDriverCtx) OpenConnector(name string) (driver.Connector, error) {
70 type fakeDB struct {
71 name string
72
73+ useRawBytes atomic.Bool
74+
75 mu sync.Mutex
76 tables map[string]*table
77 badConn bool
78@@ -680,6 +683,8 @@ func (c *fakeConn) PrepareContext(ctx context.Context, query string) (driver.Stm
79 switch cmd {
80 case "WIPE":
81 // Nothing
82+ case "USE_RAWBYTES":
83+ c.db.useRawBytes.Store(true)
84 case "SELECT":
85 stmt, err = c.prepareSelect(stmt, parts)
86 case "CREATE":
87@@ -783,6 +788,9 @@ func (s *fakeStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (d
88 case "WIPE":
89 db.wipe()
90 return driver.ResultNoRows, nil
91+ case "USE_RAWBYTES":
92+ s.c.db.useRawBytes.Store(true)
93+ return driver.ResultNoRows, nil
94 case "CREATE":
95 if err := db.createTable(s.table, s.colName, s.colType); err != nil {
96 return nil, err
97@@ -912,6 +920,7 @@ func (s *fakeStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (
98 txStatus = "transaction"
99 }
100 cursor := &rowsCursor{
101+ db: s.c.db,
102 parentMem: s.c,
103 posRow: -1,
104 rows: [][]*row{
105@@ -1008,6 +1017,7 @@ func (s *fakeStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (
106 }
107
108 cursor := &rowsCursor{
109+ db: s.c.db,
110 parentMem: s.c,
111 posRow: -1,
112 rows: setMRows,
113@@ -1050,6 +1060,7 @@ func (tx *fakeTx) Rollback() error {
114 }
115
116 type rowsCursor struct {
117+ db *fakeDB
118 parentMem memToucher
119 cols [][]string
120 colType [][]string
121@@ -1121,7 +1132,7 @@ func (rc *rowsCursor) Next(dest []driver.Value) error {
122 // messing up conversions or doing them differently.
123 dest[i] = v
124
125- if bs, ok := v.([]byte); ok {
126+ if bs, ok := v.([]byte); ok && !rc.db.useRawBytes.Load() {
127 if rc.bytesClone == nil {
128 rc.bytesClone = make(map[*byte][]byte)
129 }
130diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go
131index 68fb392..ef49e70 100644
132--- a/src/database/sql/sql.go
133+++ b/src/database/sql/sql.go
134@@ -2879,6 +2879,8 @@ type Rows struct {
135 cancel func() // called when Rows is closed, may be nil.
136 closeStmt *driverStmt // if non-nil, statement to Close on close
137
138+ contextDone atomic.Value // error that awaitDone saw; set before close attempt
139+
140 // closemu prevents Rows from closing while there
141 // is an active streaming result. It is held for read during non-close operations
142 // and exclusively during close.
143@@ -2891,6 +2893,15 @@ type Rows struct {
144 // lastcols is only used in Scan, Next, and NextResultSet which are expected
145 // not to be called concurrently.
146 lastcols []driver.Value
147+
148+ // closemuScanHold is whether the previous call to Scan kept closemu RLock'ed
149+ // without unlocking it. It does that when the user passes a *RawBytes scan
150+ // target. In that case, we need to prevent awaitDone from closing the Rows
151+ // while the user's still using the memory. See go.dev/issue/60304.
152+ //
153+ // It is only used by Scan, Next, and NextResultSet which are expected
154+ // not to be called concurrently.
155+ closemuScanHold bool
156 }
157
158 // lasterrOrErrLocked returns either lasterr or the provided err.
159@@ -2928,7 +2939,11 @@ func (rs *Rows) awaitDone(ctx, txctx context.Context) {
160 }
161 select {
162 case <-ctx.Done():
163+ err := ctx.Err()
164+ rs.contextDone.Store(&err)
165 case <-txctxDone:
166+ err := txctx.Err()
167+ rs.contextDone.Store(&err)
168 }
169 rs.close(ctx.Err())
170 }
171@@ -2940,6 +2955,15 @@ func (rs *Rows) awaitDone(ctx, txctx context.Context) {
172 //
173 // Every call to Scan, even the first one, must be preceded by a call to Next.
174 func (rs *Rows) Next() bool {
175+ // If the user's calling Next, they're done with their previous row's Scan
176+ // results (any RawBytes memory), so we can release the read lock that would
177+ // be preventing awaitDone from calling close.
178+ rs.closemuRUnlockIfHeldByScan()
179+
180+ if rs.contextDone.Load() != nil {
181+ return false
182+ }
183+
184 var doClose, ok bool
185 withLock(rs.closemu.RLocker(), func() {
186 doClose, ok = rs.nextLocked()
187@@ -2994,6 +3018,11 @@ func (rs *Rows) nextLocked() (doClose, ok bool) {
188 // scanning. If there are further result sets they may not have rows in the result
189 // set.
190 func (rs *Rows) NextResultSet() bool {
191+ // If the user's calling NextResultSet, they're done with their previous
192+ // row's Scan results (any RawBytes memory), so we can release the read lock
193+ // that would be preventing awaitDone from calling close.
194+ rs.closemuRUnlockIfHeldByScan()
195+
196 var doClose bool
197 defer func() {
198 if doClose {
199@@ -3030,6 +3059,10 @@ func (rs *Rows) NextResultSet() bool {
200 // Err returns the error, if any, that was encountered during iteration.
201 // Err may be called after an explicit or implicit Close.
202 func (rs *Rows) Err() error {
203+ if errp := rs.contextDone.Load(); errp != nil {
204+ return *(errp.(*error))
205+ }
206+
207 rs.closemu.RLock()
208 defer rs.closemu.RUnlock()
209 return rs.lasterrOrErrLocked(nil)
210@@ -3223,6 +3256,11 @@ func rowsColumnInfoSetupConnLocked(rowsi driver.Rows) []*ColumnType {
211 // If any of the first arguments implementing Scanner returns an error,
212 // that error will be wrapped in the returned error
213 func (rs *Rows) Scan(dest ...interface{}) error {
214+ if rs.closemuScanHold {
215+ // This should only be possible if the user calls Scan twice in a row
216+ // without calling Next.
217+ return fmt.Errorf("sql: Scan called without calling Next (closemuScanHold)")
218+ }
219 rs.closemu.RLock()
220
221 if rs.lasterr != nil && rs.lasterr != io.EOF {
222@@ -3234,23 +3272,50 @@ func (rs *Rows) Scan(dest ...interface{}) error {
223 rs.closemu.RUnlock()
224 return err
225 }
226- rs.closemu.RUnlock()
227+
228+ if scanArgsContainRawBytes(dest) {
229+ rs.closemuScanHold = true
230+ } else {
231+ rs.closemu.RUnlock()
232+ }
233
234 if rs.lastcols == nil {
235+ rs.closemuRUnlockIfHeldByScan()
236 return errors.New("sql: Scan called without calling Next")
237 }
238 if len(dest) != len(rs.lastcols) {
239+ rs.closemuRUnlockIfHeldByScan()
240 return fmt.Errorf("sql: expected %d destination arguments in Scan, not %d", len(rs.lastcols), len(dest))
241 }
242+
243 for i, sv := range rs.lastcols {
244 err := convertAssignRows(dest[i], sv, rs)
245 if err != nil {
246+ rs.closemuRUnlockIfHeldByScan()
247 return fmt.Errorf(`sql: Scan error on column index %d, name %q: %w`, i, rs.rowsi.Columns()[i], err)
248 }
249 }
250 return nil
251 }
252
253+// closemuRUnlockIfHeldByScan releases any closemu.RLock held open by a previous
254+// call to Scan with *RawBytes.
255+func (rs *Rows) closemuRUnlockIfHeldByScan() {
256+ if rs.closemuScanHold {
257+ rs.closemuScanHold = false
258+ rs.closemu.RUnlock()
259+ }
260+}
261+
262+func scanArgsContainRawBytes(args []interface{}) bool {
263+ for _, a := range args {
264+ if _, ok := a.(*RawBytes); ok {
265+ return true
266+ }
267+ }
268+ return false
269+}
270+
271 // rowsCloseHook returns a function so tests may install the
272 // hook through a test only mutex.
273 var rowsCloseHook = func() func(*Rows, *error) { return nil }
274@@ -3260,6 +3325,11 @@ var rowsCloseHook = func() func(*Rows, *error) { return nil }
275 // the Rows are closed automatically and it will suffice to check the
276 // result of Err. Close is idempotent and does not affect the result of Err.
277 func (rs *Rows) Close() error {
278+ // If the user's calling Close, they're done with their previous row's Scan
279+ // results (any RawBytes memory), so we can release the read lock that would
280+ // be preventing awaitDone from calling the unexported close before we do so.
281+ rs.closemuRUnlockIfHeldByScan()
282+
283 return rs.close(nil)
284 }
285
286diff --git a/src/database/sql/sql_test.go b/src/database/sql/sql_test.go
287index f771dee..53b38d1 100644
288--- a/src/database/sql/sql_test.go
289+++ b/src/database/sql/sql_test.go
290@@ -4255,6 +4255,64 @@ func TestRowsScanProperlyWrapsErrors(t *testing.T) {
291 }
292 }
293
294+// From go.dev/issue/60304
295+func TestContextCancelDuringRawBytesScan(t *testing.T) {
296+ db := newTestDB(t, "people")
297+ defer closeDB(t, db)
298+
299+ if _, err := db.Exec("USE_RAWBYTES"); err != nil {
300+ t.Fatal(err)
301+ }
302+
303+ ctx, cancel := context.WithCancel(context.Background())
304+ defer cancel()
305+
306+ r, err := db.QueryContext(ctx, "SELECT|people|name|")
307+ if err != nil {
308+ t.Fatal(err)
309+ }
310+ numRows := 0
311+ var sink byte
312+ for r.Next() {
313+ numRows++
314+ var s RawBytes
315+ err = r.Scan(&s)
316+ if !r.closemuScanHold {
317+ t.Errorf("expected closemu to be held")
318+ }
319+ if err != nil {
320+ t.Fatal(err)
321+ }
322+ t.Logf("read %q", s)
323+ if numRows == 2 {
324+ cancel() // invalidate the context, which used to call close asynchronously
325+ }
326+ for _, b := range s { // some operation reading from the raw memory
327+ sink += b
328+ }
329+ }
330+ if r.closemuScanHold {
331+ t.Errorf("closemu held; should not be")
332+ }
333+
334+ // There are 3 rows. We canceled after reading 2 so we expect either
335+ // 2 or 3 depending on how the awaitDone goroutine schedules.
336+ switch numRows {
337+ case 0, 1:
338+ t.Errorf("got %d rows; want 2+", numRows)
339+ case 2:
340+ if err := r.Err(); err != context.Canceled {
341+ t.Errorf("unexpected error: %v (%T)", err, err)
342+ }
343+ default:
344+ // Made it to the end. This is rare, but fine. Permit it.
345+ }
346+
347+ if err := r.Close(); err != nil {
348+ t.Fatal(err)
349+ }
350+}
351+
352 // badConn implements a bad driver.Conn, for TestBadDriver.
353 // The Exec method panics.
354 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 @@
1From c23579f031ecd09bf37c644723b33736dffa8b92 Mon Sep 17 00:00:00 2001
2From: Damien Neil <dneil@google.com>
3Date: Tue, 23 Jan 2024 15:59:47 -0800
4Subject: [PATCH] database/sql: avoid clobbering driver-owned memory in
5 RawBytes
6
7Depending on the query, a RawBytes can contain memory owned by the
8driver or by database/sql:
9
10If the driver provides the column as a []byte,
11RawBytes aliases that []byte.
12
13If the driver provides the column as any other type,
14RawBytes contains memory allocated by database/sql.
15Prior to this CL, Rows.Scan will reuse existing capacity in a
16RawBytes to permit a single allocation to be reused across rows.
17
18When a RawBytes is reused across queries, this can result
19in database/sql writing to driver-owned memory.
20
21Add a buffer to Rows to store RawBytes data, and reuse this
22buffer across calls to Rows.Scan.
23
24Fixes #65201
25
26Change-Id: Iac640174c7afa97eeb39496f47dec202501b2483
27Reviewed-on: https://go-review.googlesource.com/c/go/+/557917
28Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
29Reviewed-by: Roland Shoemaker <roland@golang.org>
30LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
31
32CVE: CVE-2025-47907
33
34Upstream-Status: Backport [https://github.com/golang/go/commit/c23579f031ecd09bf37c644723b33736dffa8b92]
35
36Signed-off-by: Praveen Kumar <praveen.kumar@windriver.com>
37---
38 src/database/sql/convert.go | 8 +++---
39 src/database/sql/convert_test.go | 14 +++++++---
40 src/database/sql/sql.go | 34 +++++++++++++++++++++++
41 src/database/sql/sql_test.go | 47 ++++++++++++++++++++++++++++++++
42 4 files changed, 95 insertions(+), 8 deletions(-)
43
44diff --git a/src/database/sql/convert.go b/src/database/sql/convert.go
45index b966ef9..3a581f6 100644
46--- a/src/database/sql/convert.go
47+++ b/src/database/sql/convert.go
48@@ -237,7 +237,7 @@ func convertAssignRows(dest, src interface{}, rows *Rows) error {
49 if d == nil {
50 return errNilPtr
51 }
52- *d = append((*d)[:0], s...)
53+ *d = rows.setrawbuf(append(rows.rawbuf(), s...))
54 return nil
55 }
56 case []byte:
57@@ -285,7 +285,7 @@ func convertAssignRows(dest, src interface{}, rows *Rows) error {
58 if d == nil {
59 return errNilPtr
60 }
61- *d = s.AppendFormat((*d)[:0], time.RFC3339Nano)
62+ *d = rows.setrawbuf(s.AppendFormat(rows.rawbuf(), time.RFC3339Nano))
63 return nil
64 }
65 case decimalDecompose:
66@@ -366,8 +366,8 @@ func convertAssignRows(dest, src interface{}, rows *Rows) error {
67 }
68 case *RawBytes:
69 sv = reflect.ValueOf(src)
70- if b, ok := asBytes([]byte(*d)[:0], sv); ok {
71- *d = RawBytes(b)
72+ if b, ok := asBytes(rows.rawbuf(), sv); ok {
73+ *d = rows.setrawbuf(b)
74 return nil
75 }
76 case *bool:
77diff --git a/src/database/sql/convert_test.go b/src/database/sql/convert_test.go
78index 2668a5e..23a70bf 100644
79--- a/src/database/sql/convert_test.go
80+++ b/src/database/sql/convert_test.go
81@@ -357,9 +357,10 @@ func TestRawBytesAllocs(t *testing.T) {
82 {"time", time.Unix(2, 5).UTC(), "1970-01-01T00:00:02.000000005Z"},
83 }
84
85- buf := make(RawBytes, 10)
86- test := func(name string, in interface{}, want string) {
87- if err := convertAssign(&buf, in); err != nil {
88+ var buf RawBytes
89+ rows := &Rows{}
90+ test := func(name string, in interface{}, want string) {
91+ if err := convertAssignRows(&buf, in, rows); err != nil {
92 t.Fatalf("%s: convertAssign = %v", name, err)
93 }
94 match := len(buf) == len(want)
95@@ -378,6 +379,7 @@ func TestRawBytesAllocs(t *testing.T) {
96
97 n := testing.AllocsPerRun(100, func() {
98 for _, tt := range tests {
99+ rows.raw = rows.raw[:0]
100 test(tt.name, tt.in, tt.want)
101 }
102 })
103@@ -386,7 +388,11 @@ func TestRawBytesAllocs(t *testing.T) {
104 // and gc. With 32-bit words there are more convT2E allocs, and
105 // with gccgo, only pointers currently go in interface data.
106 // So only care on amd64 gc for now.
107- measureAllocs := runtime.GOARCH == "amd64" && runtime.Compiler == "gc"
108+ measureAllocs := false
109+ switch runtime.GOARCH {
110+ case "amd64", "arm64":
111+ measureAllocs = runtime.Compiler == "gc"
112+ }
113
114 if n > 0.5 && measureAllocs {
115 t.Fatalf("allocs = %v; want 0", n)
116diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go
117index ef49e70..e25447c 100644
118--- a/src/database/sql/sql.go
119+++ b/src/database/sql/sql.go
120@@ -2894,6 +2894,13 @@ type Rows struct {
121 // not to be called concurrently.
122 lastcols []driver.Value
123
124+ // raw is a buffer for RawBytes that persists between Scan calls.
125+ // This is used when the driver returns a mismatched type that requires
126+ // a cloning allocation. For example, if the driver returns a *string and
127+ // the user is scanning into a *RawBytes, we need to copy the string.
128+ // The raw buffer here lets us reuse the memory for that copy across Scan calls.
129+ raw []byte
130+
131 // closemuScanHold is whether the previous call to Scan kept closemu RLock'ed
132 // without unlocking it. It does that when the user passes a *RawBytes scan
133 // target. In that case, we need to prevent awaitDone from closing the Rows
134@@ -3068,6 +3075,32 @@ func (rs *Rows) Err() error {
135 return rs.lasterrOrErrLocked(nil)
136 }
137
138+// rawbuf returns the buffer to append RawBytes values to.
139+// This buffer is reused across calls to Rows.Scan.
140+//
141+// Usage:
142+//
143+// rawBytes = rows.setrawbuf(append(rows.rawbuf(), value...))
144+func (rs *Rows) rawbuf() []byte {
145+ if rs == nil {
146+ // convertAssignRows can take a nil *Rows; for simplicity handle it here
147+ return nil
148+ }
149+ return rs.raw
150+}
151+
152+// setrawbuf updates the RawBytes buffer with the result of appending a new value to it.
153+// It returns the new value.
154+func (rs *Rows) setrawbuf(b []byte) RawBytes {
155+ if rs == nil {
156+ // convertAssignRows can take a nil *Rows; for simplicity handle it here
157+ return RawBytes(b)
158+ }
159+ off := len(rs.raw)
160+ rs.raw = b
161+ return RawBytes(rs.raw[off:])
162+}
163+
164 var errRowsClosed = errors.New("sql: Rows are closed")
165 var errNoRows = errors.New("sql: no Rows available")
166
167@@ -3275,6 +3308,7 @@ func (rs *Rows) Scan(dest ...interface{}) error {
168
169 if scanArgsContainRawBytes(dest) {
170 rs.closemuScanHold = true
171+ rs.raw = rs.raw[:0]
172 } else {
173 rs.closemu.RUnlock()
174 }
175diff --git a/src/database/sql/sql_test.go b/src/database/sql/sql_test.go
176index 53b38d1..6aa9bf0 100644
177--- a/src/database/sql/sql_test.go
178+++ b/src/database/sql/sql_test.go
179@@ -4313,6 +4313,53 @@ func TestContextCancelDuringRawBytesScan(t *testing.T) {
180 }
181 }
182
183+// Issue #65201.
184+//
185+// If a RawBytes is reused across multiple queries,
186+// subsequent queries shouldn't overwrite driver-owned memory from previous queries.
187+func TestRawBytesReuse(t *testing.T) {
188+ db := newTestDB(t, "people")
189+ defer closeDB(t, db)
190+
191+ if _, err := db.Exec("USE_RAWBYTES"); err != nil {
192+ t.Fatal(err)
193+ }
194+
195+ var raw RawBytes
196+
197+ // The RawBytes in this query aliases driver-owned memory.
198+ rows, err := db.Query("SELECT|people|name|")
199+ if err != nil {
200+ t.Fatal(err)
201+ }
202+ rows.Next()
203+ rows.Scan(&raw) // now raw is pointing to driver-owned memory
204+ name1 := string(raw)
205+ rows.Close()
206+
207+ // The RawBytes in this query does not alias driver-owned memory.
208+ rows, err = db.Query("SELECT|people|age|")
209+ if err != nil {
210+ t.Fatal(err)
211+ }
212+ rows.Next()
213+ rows.Scan(&raw) // this must not write to the driver-owned memory in raw
214+ rows.Close()
215+
216+ // Repeat the first query. Nothing should have changed.
217+ rows, err = db.Query("SELECT|people|name|")
218+ if err != nil {
219+ t.Fatal(err)
220+ }
221+ rows.Next()
222+ rows.Scan(&raw) // raw points to driver-owned memory again
223+ name2 := string(raw)
224+ rows.Close()
225+ if name1 != name2 {
226+ t.Fatalf("Scan read name %q, want %q", name2, name1)
227+ }
228+}
229+
230 // badConn implements a bad driver.Conn, for TestBadDriver.
231 // The Exec method panics.
232 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 @@
1From 8a924caaf348fdc366bab906424616b2974ad4e9 Mon Sep 17 00:00:00 2001
2From: Damien Neil <dneil@google.com>
3Date: Wed, 23 Jul 2025 14:26:54 -0700
4Subject: [PATCH] database/sql: avoid closing Rows while scan is in progress
5
6A database/sql/driver.Rows can return database-owned data
7from Rows.Next. The driver.Rows documentation doesn't explicitly
8document the lifetime guarantees for this data, but a reasonable
9expectation is that the caller of Next should only access it
10until the next call to Rows.Close or Rows.Next.
11
12Avoid violating that constraint when a query is cancelled while
13a call to database/sql.Rows.Scan (note the difference between
14the two different Rows types!) is in progress. We previously
15took care to avoid closing a driver.Rows while the user has
16access to driver-owned memory via a RawData, but we could still
17close a driver.Rows while a Scan call was in the process of
18reading previously-returned driver-owned data.
19
20Update the fake DB used in database/sql tests to invalidate
21returned data to help catch other places we might be
22incorrectly retaining it.
23
24Updates #74831
25Fixes #74832
26
27Change-Id: Ice45b5fad51b679c38e3e1d21ef39156b56d6037
28Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2540
29Reviewed-by: Roland Shoemaker <bracewell@google.com>
30Reviewed-by: Neal Patel <nealpatel@google.com>
31Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2601
32Reviewed-on: https://go-review.googlesource.com/c/go/+/693558
33TryBot-Bypass: Dmitri Shuralyov <dmitshur@golang.org>
34Reviewed-by: Mark Freeman <markfreeman@google.com>
35Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
36Auto-Submit: Dmitri Shuralyov <dmitshur@google.com>
37
38CVE: CVE-2025-47907
39
40Upstream-Status: Backport [https://github.com/golang/go/commit/8a924caaf348fdc366bab906424616b2974ad4e9]
41
42Signed-off-by: Praveen Kumar <praveen.kumar@windriver.com>
43---
44 src/database/sql/convert.go | 2 --
45 src/database/sql/fakedb_test.go | 47 ++++++++++++--------------
46 src/database/sql/sql.go | 26 +++++++-------
47 src/database/sql/sql_test.go | 60 ++++++++++++++++++++++++++++++---
48 4 files changed, 90 insertions(+), 45 deletions(-)
49
50diff --git a/src/database/sql/convert.go b/src/database/sql/convert.go
51index 3a581f6..5b0c6f0 100644
52--- a/src/database/sql/convert.go
53+++ b/src/database/sql/convert.go
54@@ -324,7 +324,6 @@ func convertAssignRows(dest, src interface{}, rows *Rows) error {
55 if rows == nil {
56 return errors.New("invalid context to convert cursor rows, missing parent *Rows")
57 }
58- rows.closemu.Lock()
59 *d = Rows{
60 dc: rows.dc,
61 releaseConn: func(error) {},
62@@ -340,7 +339,6 @@ func convertAssignRows(dest, src interface{}, rows *Rows) error {
63 parentCancel()
64 }
65 }
66- rows.closemu.Unlock()
67 return nil
68 }
69 }
70diff --git a/src/database/sql/fakedb_test.go b/src/database/sql/fakedb_test.go
71index 33c57b9..9f3d517 100644
72--- a/src/database/sql/fakedb_test.go
73+++ b/src/database/sql/fakedb_test.go
74@@ -5,6 +5,7 @@
75 package sql
76
77 import (
78+ "bytes"
79 "context"
80 "database/sql/driver"
81 "errors"
82@@ -15,7 +16,6 @@ import (
83 "strconv"
84 "strings"
85 "sync"
86- "sync/atomic"
87 "testing"
88 "time"
89 )
90@@ -91,8 +91,6 @@ func (cc *fakeDriverCtx) OpenConnector(name string) (driver.Connector, error) {
91 type fakeDB struct {
92 name string
93
94- useRawBytes atomic.Bool
95-
96 mu sync.Mutex
97 tables map[string]*table
98 badConn bool
99@@ -683,8 +681,6 @@ func (c *fakeConn) PrepareContext(ctx context.Context, query string) (driver.Stm
100 switch cmd {
101 case "WIPE":
102 // Nothing
103- case "USE_RAWBYTES":
104- c.db.useRawBytes.Store(true)
105 case "SELECT":
106 stmt, err = c.prepareSelect(stmt, parts)
107 case "CREATE":
108@@ -788,9 +784,6 @@ func (s *fakeStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (d
109 case "WIPE":
110 db.wipe()
111 return driver.ResultNoRows, nil
112- case "USE_RAWBYTES":
113- s.c.db.useRawBytes.Store(true)
114- return driver.ResultNoRows, nil
115 case "CREATE":
116 if err := db.createTable(s.table, s.colName, s.colType); err != nil {
117 return nil, err
118@@ -1073,10 +1066,9 @@ type rowsCursor struct {
119 errPos int
120 err error
121
122- // a clone of slices to give out to clients, indexed by the
123- // original slice's first byte address. we clone them
124- // just so we're able to corrupt them on close.
125- bytesClone map[*byte][]byte
126+ // Data returned to clients.
127+ // We clone and stash it here so it can be invalidated by Close and Next.
128+ driverOwnedMemory [][]byte
129
130 // Every operation writes to line to enable the race detector
131 // check for data races.
132@@ -1090,9 +1082,19 @@ func (rc *rowsCursor) touchMem() {
133 rc.line++
134 }
135
136+func (rc *rowsCursor) invalidateDriverOwnedMemory() {
137+ for _, buf := range rc.driverOwnedMemory {
138+ for i := range buf {
139+ buf[i] = 'x'
140+ }
141+ }
142+ rc.driverOwnedMemory = nil
143+}
144+
145 func (rc *rowsCursor) Close() error {
146 rc.touchMem()
147 rc.parentMem.touchMem()
148+ rc.invalidateDriverOwnedMemory()
149 rc.closed = true
150 return nil
151 }
152@@ -1123,6 +1125,8 @@ func (rc *rowsCursor) Next(dest []driver.Value) error {
153 if rc.posRow >= len(rc.rows[rc.posSet]) {
154 return io.EOF // per interface spec
155 }
156+ // Corrupt any previously returned bytes.
157+ rc.invalidateDriverOwnedMemory()
158 for i, v := range rc.rows[rc.posSet][rc.posRow].cols {
159 // TODO(bradfitz): convert to subset types? naah, I
160 // think the subset types should only be input to
161@@ -1130,20 +1134,13 @@ func (rc *rowsCursor) Next(dest []driver.Value) error {
162 // a wider range of types coming out of drivers. all
163 // for ease of drivers, and to prevent drivers from
164 // messing up conversions or doing them differently.
165- dest[i] = v
166-
167- if bs, ok := v.([]byte); ok && !rc.db.useRawBytes.Load() {
168- if rc.bytesClone == nil {
169- rc.bytesClone = make(map[*byte][]byte)
170- }
171- clone, ok := rc.bytesClone[&bs[0]]
172- if !ok {
173- clone = make([]byte, len(bs))
174- copy(clone, bs)
175- rc.bytesClone[&bs[0]] = clone
176- }
177- dest[i] = clone
178+ if bs, ok := v.([]byte); ok {
179+ // Clone []bytes and stash for later invalidation.
180+ bs = bytes.Clone(bs)
181+ rc.driverOwnedMemory = append(rc.driverOwnedMemory, bs)
182+ v = bs
183 }
184+ dest[i] = v
185 }
186 return nil
187 }
188diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go
189index e25447c..a428e29 100644
190--- a/src/database/sql/sql.go
191+++ b/src/database/sql/sql.go
192@@ -3294,38 +3294,36 @@ func (rs *Rows) Scan(dest ...interface{}) error {
193 // without calling Next.
194 return fmt.Errorf("sql: Scan called without calling Next (closemuScanHold)")
195 }
196+
197 rs.closemu.RLock()
198+ rs.raw = rs.raw[:0]
199+ err := rs.scanLocked(dest...)
200+ if err == nil && scanArgsContainRawBytes(dest) {
201+ rs.closemuScanHold = true
202+ } else {
203+ rs.closemu.RUnlock()
204+ }
205+ return err
206+}
207
208+func (rs *Rows) scanLocked(dest ...interface{}) error {
209 if rs.lasterr != nil && rs.lasterr != io.EOF {
210- rs.closemu.RUnlock()
211 return rs.lasterr
212 }
213 if rs.closed {
214- err := rs.lasterrOrErrLocked(errRowsClosed)
215- rs.closemu.RUnlock()
216- return err
217- }
218-
219- if scanArgsContainRawBytes(dest) {
220- rs.closemuScanHold = true
221- rs.raw = rs.raw[:0]
222- } else {
223- rs.closemu.RUnlock()
224+ return rs.lasterrOrErrLocked(errRowsClosed)
225 }
226
227 if rs.lastcols == nil {
228- rs.closemuRUnlockIfHeldByScan()
229 return errors.New("sql: Scan called without calling Next")
230 }
231 if len(dest) != len(rs.lastcols) {
232- rs.closemuRUnlockIfHeldByScan()
233 return fmt.Errorf("sql: expected %d destination arguments in Scan, not %d", len(rs.lastcols), len(dest))
234 }
235
236 for i, sv := range rs.lastcols {
237 err := convertAssignRows(dest[i], sv, rs)
238 if err != nil {
239- rs.closemuRUnlockIfHeldByScan()
240 return fmt.Errorf(`sql: Scan error on column index %d, name %q: %w`, i, rs.rowsi.Columns()[i], err)
241 }
242 }
243diff --git a/src/database/sql/sql_test.go b/src/database/sql/sql_test.go
244index 6aa9bf0..6aec7ec 100644
245--- a/src/database/sql/sql_test.go
246+++ b/src/database/sql/sql_test.go
247@@ -5,6 +5,7 @@
248 package sql
249
250 import (
251+ "bytes"
252 "context"
253 "database/sql/driver"
254 "errors"
255@@ -4321,10 +4322,6 @@ func TestRawBytesReuse(t *testing.T) {
256 db := newTestDB(t, "people")
257 defer closeDB(t, db)
258
259- if _, err := db.Exec("USE_RAWBYTES"); err != nil {
260- t.Fatal(err)
261- }
262-
263 var raw RawBytes
264
265 // The RawBytes in this query aliases driver-owned memory.
266@@ -4469,6 +4466,61 @@ func TestTypedString(t *testing.T) {
267 }
268 }
269
270+type testScanner struct {
271+ scanf func(src any) error
272+}
273+
274+func (ts testScanner) Scan(src any) error { return ts.scanf(src) }
275+
276+func TestContextCancelDuringScan(t *testing.T) {
277+ db := newTestDB(t, "people")
278+ defer closeDB(t, db)
279+
280+ ctx, cancel := context.WithCancel(context.Background())
281+ defer cancel()
282+
283+ scanStart := make(chan any)
284+ scanEnd := make(chan error)
285+ scanner := &testScanner{
286+ scanf: func(src any) error {
287+ scanStart <- src
288+ return <-scanEnd
289+ },
290+ }
291+
292+ // Start a query, and pause it mid-scan.
293+ want := []byte("Alice")
294+ r, err := db.QueryContext(ctx, "SELECT|people|name|name=?", string(want))
295+ if err != nil {
296+ t.Fatal(err)
297+ }
298+ if !r.Next() {
299+ t.Fatalf("r.Next() = false, want true")
300+ }
301+ go func() {
302+ r.Scan(scanner)
303+ }()
304+ got := <-scanStart
305+ defer close(scanEnd)
306+ gotBytes, ok := got.([]byte)
307+ if !ok {
308+ t.Fatalf("r.Scan returned %T, want []byte", got)
309+ }
310+ if !bytes.Equal(gotBytes, want) {
311+ t.Fatalf("before cancel: r.Scan returned %q, want %q", gotBytes, want)
312+ }
313+
314+ // Cancel the query.
315+ // Sleep to give it a chance to finish canceling.
316+ cancel()
317+ time.Sleep(10 * time.Millisecond)
318+
319+ // Cancelling the query should not have changed the result.
320+ if !bytes.Equal(gotBytes, want) {
321+ t.Fatalf("after cancel: r.Scan result is now %q, want %q", gotBytes, want)
322+ }
323+}
324+
325 func BenchmarkConcurrentDBExec(b *testing.B) {
326 b.ReportAllocs()
327 ct := new(concurrentDBExecTest)