summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--meta/recipes-devtools/go/go-1.22.12.inc2
-rw-r--r--meta/recipes-devtools/go/go/CVE-2025-47907-pre.patch233
-rw-r--r--meta/recipes-devtools/go/go/CVE-2025-47907.patch328
3 files changed, 563 insertions, 0 deletions
diff --git a/meta/recipes-devtools/go/go-1.22.12.inc b/meta/recipes-devtools/go/go-1.22.12.inc
index 12d7539017..d0ce333117 100644
--- a/meta/recipes-devtools/go/go-1.22.12.inc
+++ b/meta/recipes-devtools/go/go-1.22.12.inc
@@ -18,6 +18,8 @@ SRC_URI += "\
18 file://CVE-2025-22871.patch \ 18 file://CVE-2025-22871.patch \
19 file://CVE-2025-4673.patch \ 19 file://CVE-2025-4673.patch \
20 file://CVE-2025-4674.patch \ 20 file://CVE-2025-4674.patch \
21 file://CVE-2025-47907-pre.patch \
22 file://CVE-2025-47907.patch \
21" 23"
22SRC_URI[main.sha256sum] = "012a7e1f37f362c0918c1dfa3334458ac2da1628c4b9cf4d9ca02db986e17d71" 24SRC_URI[main.sha256sum] = "012a7e1f37f362c0918c1dfa3334458ac2da1628c4b9cf4d9ca02db986e17d71"
23 25
diff --git a/meta/recipes-devtools/go/go/CVE-2025-47907-pre.patch b/meta/recipes-devtools/go/go/CVE-2025-47907-pre.patch
new file mode 100644
index 0000000000..dafa878e73
--- /dev/null
+++ b/meta/recipes-devtools/go/go/CVE-2025-47907-pre.patch
@@ -0,0 +1,233 @@
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 1/2] 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 | 12 ++++++--
40 src/database/sql/sql.go | 34 +++++++++++++++++++++++
41 src/database/sql/sql_test.go | 47 ++++++++++++++++++++++++++++++++
42 4 files changed, 94 insertions(+), 7 deletions(-)
43
44diff --git a/src/database/sql/convert.go b/src/database/sql/convert.go
45index cca5d15..999b8f1 100644
46--- a/src/database/sql/convert.go
47+++ b/src/database/sql/convert.go
48@@ -237,7 +237,7 @@ func convertAssignRows(dest, src any, 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 any, 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 any, 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 6d09fa1..f94db8e 100644
79--- a/src/database/sql/convert_test.go
80+++ b/src/database/sql/convert_test.go
81@@ -354,9 +354,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+ var buf RawBytes
87+ rows := &Rows{}
88 test := func(name string, in any, want string) {
89- if err := convertAssign(&buf, in); err != nil {
90+ if err := convertAssignRows(&buf, in, rows); err != nil {
91 t.Fatalf("%s: convertAssign = %v", name, err)
92 }
93 match := len(buf) == len(want)
94@@ -375,6 +376,7 @@ func TestRawBytesAllocs(t *testing.T) {
95
96 n := testing.AllocsPerRun(100, func() {
97 for _, tt := range tests {
98+ rows.raw = rows.raw[:0]
99 test(tt.name, tt.in, tt.want)
100 }
101 })
102@@ -383,7 +385,11 @@ func TestRawBytesAllocs(t *testing.T) {
103 // and gc. With 32-bit words there are more convT2E allocs, and
104 // with gccgo, only pointers currently go in interface data.
105 // So only care on amd64 gc for now.
106- measureAllocs := runtime.GOARCH == "amd64" && runtime.Compiler == "gc"
107+ measureAllocs := false
108+ switch runtime.GOARCH {
109+ case "amd64", "arm64":
110+ measureAllocs = runtime.Compiler == "gc"
111+ }
112
113 if n > 0.5 && measureAllocs {
114 t.Fatalf("allocs = %v; want 0", n)
115diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go
116index 4f1197d..da0f52c 100644
117--- a/src/database/sql/sql.go
118+++ b/src/database/sql/sql.go
119@@ -2936,6 +2936,13 @@ type Rows struct {
120 // not to be called concurrently.
121 lastcols []driver.Value
122
123+ // raw is a buffer for RawBytes that persists between Scan calls.
124+ // This is used when the driver returns a mismatched type that requires
125+ // a cloning allocation. For example, if the driver returns a *string and
126+ // the user is scanning into a *RawBytes, we need to copy the string.
127+ // The raw buffer here lets us reuse the memory for that copy across Scan calls.
128+ raw []byte
129+
130 // closemuScanHold is whether the previous call to Scan kept closemu RLock'ed
131 // without unlocking it. It does that when the user passes a *RawBytes scan
132 // target. In that case, we need to prevent awaitDone from closing the Rows
133@@ -3130,6 +3137,32 @@ func (rs *Rows) Err() error {
134 return rs.lasterrOrErrLocked(nil)
135 }
136
137+// rawbuf returns the buffer to append RawBytes values to.
138+// This buffer is reused across calls to Rows.Scan.
139+//
140+// Usage:
141+//
142+// rawBytes = rows.setrawbuf(append(rows.rawbuf(), value...))
143+func (rs *Rows) rawbuf() []byte {
144+ if rs == nil {
145+ // convertAssignRows can take a nil *Rows; for simplicity handle it here
146+ return nil
147+ }
148+ return rs.raw
149+}
150+
151+// setrawbuf updates the RawBytes buffer with the result of appending a new value to it.
152+// It returns the new value.
153+func (rs *Rows) setrawbuf(b []byte) RawBytes {
154+ if rs == nil {
155+ // convertAssignRows can take a nil *Rows; for simplicity handle it here
156+ return RawBytes(b)
157+ }
158+ off := len(rs.raw)
159+ rs.raw = b
160+ return RawBytes(rs.raw[off:])
161+}
162+
163 var errRowsClosed = errors.New("sql: Rows are closed")
164 var errNoRows = errors.New("sql: no Rows available")
165
166@@ -3337,6 +3370,7 @@ func (rs *Rows) Scan(dest ...any) error {
167
168 if scanArgsContainRawBytes(dest) {
169 rs.closemuScanHold = true
170+ rs.raw = rs.raw[:0]
171 } else {
172 rs.closemu.RUnlock()
173 }
174diff --git a/src/database/sql/sql_test.go b/src/database/sql/sql_test.go
175index c38a348..c3b4822 100644
176--- a/src/database/sql/sql_test.go
177+++ b/src/database/sql/sql_test.go
178@@ -4531,6 +4531,53 @@ func TestNilErrorAfterClose(t *testing.T) {
179 }
180 }
181
182+// Issue #65201.
183+//
184+// If a RawBytes is reused across multiple queries,
185+// subsequent queries shouldn't overwrite driver-owned memory from previous queries.
186+func TestRawBytesReuse(t *testing.T) {
187+ db := newTestDB(t, "people")
188+ defer closeDB(t, db)
189+
190+ if _, err := db.Exec("USE_RAWBYTES"); err != nil {
191+ t.Fatal(err)
192+ }
193+
194+ var raw RawBytes
195+
196+ // The RawBytes in this query aliases driver-owned memory.
197+ rows, err := db.Query("SELECT|people|name|")
198+ if err != nil {
199+ t.Fatal(err)
200+ }
201+ rows.Next()
202+ rows.Scan(&raw) // now raw is pointing to driver-owned memory
203+ name1 := string(raw)
204+ rows.Close()
205+
206+ // The RawBytes in this query does not alias driver-owned memory.
207+ rows, err = db.Query("SELECT|people|age|")
208+ if err != nil {
209+ t.Fatal(err)
210+ }
211+ rows.Next()
212+ rows.Scan(&raw) // this must not write to the driver-owned memory in raw
213+ rows.Close()
214+
215+ // Repeat the first query. Nothing should have changed.
216+ rows, err = db.Query("SELECT|people|name|")
217+ if err != nil {
218+ t.Fatal(err)
219+ }
220+ rows.Next()
221+ rows.Scan(&raw) // raw points to driver-owned memory again
222+ name2 := string(raw)
223+ rows.Close()
224+ if name1 != name2 {
225+ t.Fatalf("Scan read name %q, want %q", name2, name1)
226+ }
227+}
228+
229 // badConn implements a bad driver.Conn, for TestBadDriver.
230 // The Exec method panics.
231 type badConn struct{}
232--
2332.40.0
diff --git a/meta/recipes-devtools/go/go/CVE-2025-47907.patch b/meta/recipes-devtools/go/go/CVE-2025-47907.patch
new file mode 100644
index 0000000000..a556c3dd68
--- /dev/null
+++ b/meta/recipes-devtools/go/go/CVE-2025-47907.patch
@@ -0,0 +1,328 @@
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 2/2] database/sql: avoid closing Rows while scan is in
5 progress
6
7A database/sql/driver.Rows can return database-owned data
8from Rows.Next. The driver.Rows documentation doesn't explicitly
9document the lifetime guarantees for this data, but a reasonable
10expectation is that the caller of Next should only access it
11until the next call to Rows.Close or Rows.Next.
12
13Avoid violating that constraint when a query is cancelled while
14a call to database/sql.Rows.Scan (note the difference between
15the two different Rows types!) is in progress. We previously
16took care to avoid closing a driver.Rows while the user has
17access to driver-owned memory via a RawData, but we could still
18close a driver.Rows while a Scan call was in the process of
19reading previously-returned driver-owned data.
20
21Update the fake DB used in database/sql tests to invalidate
22returned data to help catch other places we might be
23incorrectly retaining it.
24
25Updates #74831
26Fixes #74832
27
28Change-Id: Ice45b5fad51b679c38e3e1d21ef39156b56d6037
29Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2540
30Reviewed-by: Roland Shoemaker <bracewell@google.com>
31Reviewed-by: Neal Patel <nealpatel@google.com>
32Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2601
33Reviewed-on: https://go-review.googlesource.com/c/go/+/693558
34TryBot-Bypass: Dmitri Shuralyov <dmitshur@golang.org>
35Reviewed-by: Mark Freeman <markfreeman@google.com>
36Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
37Auto-Submit: Dmitri Shuralyov <dmitshur@google.com>
38
39CVE: CVE-2025-47907
40
41Upstream-Status: Backport [https://github.com/golang/go/commit/8a924caaf348fdc366bab906424616b2974ad4e9]
42
43Signed-off-by: Praveen Kumar <praveen.kumar@windriver.com>
44---
45 src/database/sql/convert.go | 2 --
46 src/database/sql/fakedb_test.go | 47 ++++++++++++--------------
47 src/database/sql/sql.go | 26 ++++++--------
48 src/database/sql/sql_test.go | 60 ++++++++++++++++++++++++++++++---
49 4 files changed, 89 insertions(+), 46 deletions(-)
50
51diff --git a/src/database/sql/convert.go b/src/database/sql/convert.go
52index 999b8f1..2869a3b 100644
53--- a/src/database/sql/convert.go
54+++ b/src/database/sql/convert.go
55@@ -324,7 +324,6 @@ func convertAssignRows(dest, src any, rows *Rows) error {
56 if rows == nil {
57 return errors.New("invalid context to convert cursor rows, missing parent *Rows")
58 }
59- rows.closemu.Lock()
60 *d = Rows{
61 dc: rows.dc,
62 releaseConn: func(error) {},
63@@ -340,7 +339,6 @@ func convertAssignRows(dest, src any, rows *Rows) error {
64 parentCancel()
65 }
66 }
67- rows.closemu.Unlock()
68 return nil
69 }
70 }
71diff --git a/src/database/sql/fakedb_test.go b/src/database/sql/fakedb_test.go
72index c6c3172..95c0fa3 100644
73--- a/src/database/sql/fakedb_test.go
74+++ b/src/database/sql/fakedb_test.go
75@@ -5,6 +5,7 @@
76 package sql
77
78 import (
79+ "bytes"
80 "context"
81 "database/sql/driver"
82 "errors"
83@@ -15,7 +16,6 @@ import (
84 "strconv"
85 "strings"
86 "sync"
87- "sync/atomic"
88 "testing"
89 "time"
90 )
91@@ -91,8 +91,6 @@ func (cc *fakeDriverCtx) OpenConnector(name string) (driver.Connector, error) {
92 type fakeDB struct {
93 name string
94
95- useRawBytes atomic.Bool
96-
97 mu sync.Mutex
98 tables map[string]*table
99 badConn bool
100@@ -700,8 +698,6 @@ func (c *fakeConn) PrepareContext(ctx context.Context, query string) (driver.Stm
101 switch cmd {
102 case "WIPE":
103 // Nothing
104- case "USE_RAWBYTES":
105- c.db.useRawBytes.Store(true)
106 case "SELECT":
107 stmt, err = c.prepareSelect(stmt, parts)
108 case "CREATE":
109@@ -805,9 +801,6 @@ func (s *fakeStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (d
110 case "WIPE":
111 db.wipe()
112 return driver.ResultNoRows, nil
113- case "USE_RAWBYTES":
114- s.c.db.useRawBytes.Store(true)
115- return driver.ResultNoRows, nil
116 case "CREATE":
117 if err := db.createTable(s.table, s.colName, s.colType); err != nil {
118 return nil, err
119@@ -1090,10 +1083,9 @@ type rowsCursor struct {
120 errPos int
121 err error
122
123- // a clone of slices to give out to clients, indexed by the
124- // original slice's first byte address. we clone them
125- // just so we're able to corrupt them on close.
126- bytesClone map[*byte][]byte
127+ // Data returned to clients.
128+ // We clone and stash it here so it can be invalidated by Close and Next.
129+ driverOwnedMemory [][]byte
130
131 // Every operation writes to line to enable the race detector
132 // check for data races.
133@@ -1110,9 +1102,19 @@ func (rc *rowsCursor) touchMem() {
134 rc.line++
135 }
136
137+func (rc *rowsCursor) invalidateDriverOwnedMemory() {
138+ for _, buf := range rc.driverOwnedMemory {
139+ for i := range buf {
140+ buf[i] = 'x'
141+ }
142+ }
143+ rc.driverOwnedMemory = nil
144+}
145+
146 func (rc *rowsCursor) Close() error {
147 rc.touchMem()
148 rc.parentMem.touchMem()
149+ rc.invalidateDriverOwnedMemory()
150 rc.closed = true
151 return rc.closeErr
152 }
153@@ -1143,6 +1145,8 @@ func (rc *rowsCursor) Next(dest []driver.Value) error {
154 if rc.posRow >= len(rc.rows[rc.posSet]) {
155 return io.EOF // per interface spec
156 }
157+ // Corrupt any previously returned bytes.
158+ rc.invalidateDriverOwnedMemory()
159 for i, v := range rc.rows[rc.posSet][rc.posRow].cols {
160 // TODO(bradfitz): convert to subset types? naah, I
161 // think the subset types should only be input to
162@@ -1150,20 +1154,13 @@ func (rc *rowsCursor) Next(dest []driver.Value) error {
163 // a wider range of types coming out of drivers. all
164 // for ease of drivers, and to prevent drivers from
165 // messing up conversions or doing them differently.
166- dest[i] = v
167-
168- if bs, ok := v.([]byte); ok && !rc.db.useRawBytes.Load() {
169- if rc.bytesClone == nil {
170- rc.bytesClone = make(map[*byte][]byte)
171- }
172- clone, ok := rc.bytesClone[&bs[0]]
173- if !ok {
174- clone = make([]byte, len(bs))
175- copy(clone, bs)
176- rc.bytesClone[&bs[0]] = clone
177- }
178- dest[i] = clone
179+ if bs, ok := v.([]byte); ok {
180+ // Clone []bytes and stash for later invalidation.
181+ bs = bytes.Clone(bs)
182+ rc.driverOwnedMemory = append(rc.driverOwnedMemory, bs)
183+ v = bs
184 }
185+ dest[i] = v
186 }
187 return nil
188 }
189diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go
190index da0f52c..41130d9 100644
191--- a/src/database/sql/sql.go
192+++ b/src/database/sql/sql.go
193@@ -3357,37 +3357,33 @@ func (rs *Rows) Scan(dest ...any) error {
194 return fmt.Errorf("sql: Scan called without calling Next (closemuScanHold)")
195 }
196 rs.closemu.RLock()
197-
198- if rs.lasterr != nil && rs.lasterr != io.EOF {
199+ rs.raw = rs.raw[:0]
200+ err := rs.scanLocked(dest...)
201+ if err == nil && scanArgsContainRawBytes(dest) {
202+ rs.closemuScanHold = true
203+ } else {
204 rs.closemu.RUnlock()
205+ }
206+ return err
207+}
208+func (rs *Rows) scanLocked(dest ...any) error {
209+ if rs.lasterr != nil && rs.lasterr != io.EOF {
210 return rs.lasterr
211 }
212 if rs.closed {
213- err := rs.lasterrOrErrLocked(errRowsClosed)
214- rs.closemu.RUnlock()
215- return err
216- }
217-
218- if scanArgsContainRawBytes(dest) {
219- rs.closemuScanHold = true
220- rs.raw = rs.raw[:0]
221- } else {
222- rs.closemu.RUnlock()
223+ return rs.lasterrOrErrLocked(errRowsClosed)
224 }
225
226 if rs.lastcols == nil {
227- rs.closemuRUnlockIfHeldByScan()
228 return errors.New("sql: Scan called without calling Next")
229 }
230 if len(dest) != len(rs.lastcols) {
231- rs.closemuRUnlockIfHeldByScan()
232 return fmt.Errorf("sql: expected %d destination arguments in Scan, not %d", len(rs.lastcols), len(dest))
233 }
234
235 for i, sv := range rs.lastcols {
236 err := convertAssignRows(dest[i], sv, rs)
237 if err != nil {
238- rs.closemuRUnlockIfHeldByScan()
239 return fmt.Errorf(`sql: Scan error on column index %d, name %q: %w`, i, rs.rowsi.Columns()[i], err)
240 }
241 }
242diff --git a/src/database/sql/sql_test.go b/src/database/sql/sql_test.go
243index c3b4822..ee65b1b 100644
244--- a/src/database/sql/sql_test.go
245+++ b/src/database/sql/sql_test.go
246@@ -5,6 +5,7 @@
247 package sql
248
249 import (
250+ "bytes"
251 "context"
252 "database/sql/driver"
253 "errors"
254@@ -4411,10 +4412,6 @@ func testContextCancelDuringRawBytesScan(t *testing.T, mode string) {
255 db := newTestDB(t, "people")
256 defer closeDB(t, db)
257
258- if _, err := db.Exec("USE_RAWBYTES"); err != nil {
259- t.Fatal(err)
260- }
261-
262 // cancel used to call close asynchronously.
263 // This test checks that it waits so as not to interfere with RawBytes.
264 ctx, cancel := context.WithCancel(context.Background())
265@@ -4506,6 +4503,61 @@ func TestContextCancelBetweenNextAndErr(t *testing.T) {
266 }
267 }
268
269+type testScanner struct {
270+ scanf func(src any) error
271+}
272+
273+func (ts testScanner) Scan(src any) error { return ts.scanf(src) }
274+
275+func TestContextCancelDuringScan(t *testing.T) {
276+ db := newTestDB(t, "people")
277+ defer closeDB(t, db)
278+
279+ ctx, cancel := context.WithCancel(context.Background())
280+ defer cancel()
281+
282+ scanStart := make(chan any)
283+ scanEnd := make(chan error)
284+ scanner := &testScanner{
285+ scanf: func(src any) error {
286+ scanStart <- src
287+ return <-scanEnd
288+ },
289+ }
290+
291+ // Start a query, and pause it mid-scan.
292+ want := []byte("Alice")
293+ r, err := db.QueryContext(ctx, "SELECT|people|name|name=?", string(want))
294+ if err != nil {
295+ t.Fatal(err)
296+ }
297+ if !r.Next() {
298+ t.Fatalf("r.Next() = false, want true")
299+ }
300+ go func() {
301+ r.Scan(scanner)
302+ }()
303+ got := <-scanStart
304+ defer close(scanEnd)
305+ gotBytes, ok := got.([]byte)
306+ if !ok {
307+ t.Fatalf("r.Scan returned %T, want []byte", got)
308+ }
309+ if !bytes.Equal(gotBytes, want) {
310+ t.Fatalf("before cancel: r.Scan returned %q, want %q", gotBytes, want)
311+ }
312+
313+ // Cancel the query.
314+ // Sleep to give it a chance to finish canceling.
315+ cancel()
316+ time.Sleep(10 * time.Millisecond)
317+
318+ // Cancelling the query should not have changed the result.
319+ if !bytes.Equal(gotBytes, want) {
320+ t.Fatalf("after cancel: r.Scan result is now %q, want %q", gotBytes, want)
321+ }
322+}
323+
324 func TestNilErrorAfterClose(t *testing.T) {
325 db := newTestDB(t, "people")
326 defer closeDB(t, db)
327--
3282.40.0