vendor: go.etcd.io/bbolt v1.4.3

Fix potential data corruption in (*Tx)WriteTo if underlying db file
is overwritten

full diff: https://github.com/etcd-io/bbolt/compare/v1.4.2...v1.4.3

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 15f92925f0)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn
2025-08-21 23:05:05 +02:00
parent cc6af47b61
commit 8ae706833d
5 changed files with 59 additions and 19 deletions

View File

@@ -99,7 +99,7 @@ require (
github.com/vbatts/tar-split v0.12.1
github.com/vishvananda/netlink v1.3.1
github.com/vishvananda/netns v0.0.5
go.etcd.io/bbolt v1.4.2
go.etcd.io/bbolt v1.4.3
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0
go.opentelemetry.io/contrib/processors/baggagecopy v0.4.0

View File

@@ -601,8 +601,8 @@ github.com/zmap/zcrypto v0.0.0-20210511125630-18f1e0152cfc h1:zkGwegkOW709y0oiAr
github.com/zmap/zcrypto v0.0.0-20210511125630-18f1e0152cfc/go.mod h1:FM4U1E3NzlNMRnSUTU3P1UdukWhYGifqEsjk9fn7BCk=
github.com/zmap/zlint/v3 v3.1.0 h1:WjVytZo79m/L1+/Mlphl09WBob6YTGljN5IGWZFpAv0=
github.com/zmap/zlint/v3 v3.1.0/go.mod h1:L7t8s3sEKkb0A2BxGy1IWrxt1ZATa1R4QfJZaQOD3zU=
go.etcd.io/bbolt v1.4.2 h1:IrUHp260R8c+zYx/Tm8QZr04CX+qWS5PGfPdevhdm1I=
go.etcd.io/bbolt v1.4.2/go.mod h1:Is8rSHO/b4f3XigBC0lL0+4FwAQv3HXEEIgFMuKHceM=
go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo=
go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E=
go.etcd.io/etcd/client/pkg/v3 v3.5.16 h1:ZgY48uH6UvB+/7R9Yf4x574uCO3jIx0TRDyetSfId3Q=
go.etcd.io/etcd/client/pkg/v3 v3.5.16/go.mod h1:V8acl8pcEK0Y2g19YlOV9m9ssUe6MgiDSobSoaBAM0E=
go.etcd.io/etcd/pkg/v3 v3.5.16 h1:cnavs5WSPWeK4TYwPYfmcr3Joz9BH+TZ6qoUtz6/+mc=

View File

@@ -1 +1 @@
1.23.10
1.23.12

68
vendor/go.etcd.io/bbolt/tx.go generated vendored
View File

@@ -387,16 +387,43 @@ func (tx *Tx) Copy(w io.Writer) error {
// WriteTo writes the entire database to a writer.
// If err == nil then exactly tx.Size() bytes will be written into the writer.
func (tx *Tx) WriteTo(w io.Writer) (n int64, err error) {
// Attempt to open reader with WriteFlag
f, err := tx.db.openFile(tx.db.path, os.O_RDONLY|tx.WriteFlag, 0)
if err != nil {
return 0, err
}
defer func() {
if cerr := f.Close(); err == nil {
err = cerr
var f *os.File
// There is a risk that between the time a read-only transaction
// is created and the time the file is actually opened, the
// underlying db file at tx.db.path may have been replaced
// (e.g. via rename). In that case, opening the file again would
// unexpectedly point to a different file, rather than the one
// the transaction was based on.
//
// To overcome this, we reuse the already opened file handle when
// WritFlag not set. When the WriteFlag is set, we reopen the file
// but verify that it still refers to the same underlying file
// (by device and inode). If it does not, we fall back to
// reusing the existing already opened file handle.
if tx.WriteFlag != 0 {
// Attempt to open reader with WriteFlag
f, err = tx.db.openFile(tx.db.path, os.O_RDONLY|tx.WriteFlag, 0)
if err != nil {
return 0, err
}
}()
if ok, err := sameFile(tx.db.file, f); !ok {
lg := tx.db.Logger()
if cerr := f.Close(); cerr != nil {
lg.Errorf("failed to close the file (%s): %v", tx.db.path, cerr)
}
lg.Warningf("The underlying file has changed, so reuse the already opened file (%s): %v", tx.db.path, err)
f = tx.db.file
} else {
defer func() {
if cerr := f.Close(); err == nil {
err = cerr
}
}()
}
} else {
f = tx.db.file
}
// Generate a meta page. We use the same page data for both meta pages.
buf := make([]byte, tx.db.pageSize)
@@ -423,13 +450,13 @@ func (tx *Tx) WriteTo(w io.Writer) (n int64, err error) {
return n, fmt.Errorf("meta 1 copy: %s", err)
}
// Move past the meta pages in the file.
if _, err := f.Seek(int64(tx.db.pageSize*2), io.SeekStart); err != nil {
return n, fmt.Errorf("seek: %s", err)
}
// Copy data pages using a SectionReader to avoid affecting f's offset.
dataOffset := int64(tx.db.pageSize * 2)
dataSize := tx.Size() - dataOffset
sr := io.NewSectionReader(f, dataOffset, dataSize)
// Copy data pages.
wn, err := io.CopyN(w, f, tx.Size()-int64(tx.db.pageSize*2))
wn, err := io.CopyN(w, sr, dataSize)
n += wn
if err != nil {
return n, err
@@ -438,6 +465,19 @@ func (tx *Tx) WriteTo(w io.Writer) (n int64, err error) {
return n, nil
}
func sameFile(f1, f2 *os.File) (bool, error) {
fi1, err := f1.Stat()
if err != nil {
return false, fmt.Errorf("failed to get fileInfo of the first file (%s): %w", f1.Name(), err)
}
fi2, err := f2.Stat()
if err != nil {
return false, fmt.Errorf("failed to get fileInfo of the second file (%s): %w", f2.Name(), err)
}
return os.SameFile(fi1, fi2), nil
}
// CopyFile copies the entire database to file at the given path.
// A reader transaction is maintained during the copy so it is safe to continue
// using the database while a copy is in progress.

2
vendor/modules.txt vendored
View File

@@ -1247,7 +1247,7 @@ github.com/zmap/zlint/v3/lints/etsi
github.com/zmap/zlint/v3/lints/mozilla
github.com/zmap/zlint/v3/lints/rfc
github.com/zmap/zlint/v3/util
# go.etcd.io/bbolt v1.4.2
# go.etcd.io/bbolt v1.4.3
## explicit; go 1.23
go.etcd.io/bbolt
go.etcd.io/bbolt/errors