Skip to content

Commit d4c1329

Browse files
mrsinhamJulien Lefevre
authored and
Julien Lefevre
committed
Race on LOAD DATA called from different routines
Maps are not routine safe so if you register readers/files from differents routines, the registry must be locked.
1 parent 69e3ed7 commit d4c1329

File tree

3 files changed

+24
-5
lines changed

3 files changed

+24
-5
lines changed

AUTHORS

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ Soroush Pour <me at soroushjp.com>
3636
Stan Putrya <root.vagner at gmail.com>
3737
Xiaobing Jiang <s7v7nislands at gmail.com>
3838
Xiuming Chen <cc at cxm.cc>
39+
Julien Lefevre <julien.lefevr at gmail.com>
3940

4041
# Organizations
4142

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ import "github.com/go-sql-driver/mysql"
331331

332332
Files must be whitelisted by registering them with `mysql.RegisterLocalFile(filepath)` (recommended) or the Whitelist check must be deactivated by using the DSN parameter `allowAllFiles=true` ([*Might be insecure!*](http://dev.mysql.com/doc/refman/5.7/en/load-data-local.html)).
333333

334-
To use a `io.Reader` a handler function must be registered with `mysql.RegisterReaderHandler(name, handler)` which returns a `io.Reader` or `io.ReadCloser`. The Reader is available with the filepath `Reader::<name>` then.
334+
To use a `io.Reader` a handler function must be registered with `mysql.RegisterReaderHandler(name, handler)` which returns a `io.Reader` or `io.ReadCloser`. The Reader is available with the filepath `Reader::<name>` then. Choose different names for different handlers and `DeregisterReaderHandler` when you don't need it anymore.
335335

336336
See the [godoc of Go-MySQL-Driver](http://godoc.org/github.com/go-sql-driver/mysql "golang mysql driver documentation") for details.
337337

infile.go

+22-4
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,14 @@ import (
1313
"io"
1414
"os"
1515
"strings"
16+
"sync"
1617
)
1718

1819
var (
19-
fileRegister map[string]bool
20-
readerRegister map[string]func() io.Reader
20+
fileRegister map[string]bool
21+
fileRegisterLock sync.RWMutex
22+
readerRegister map[string]func() io.Reader
23+
readerRegisterLock sync.RWMutex
2124
)
2225

2326
// RegisterLocalFile adds the given file to the file whitelist,
@@ -32,17 +35,21 @@ var (
3235
// ...
3336
//
3437
func RegisterLocalFile(filePath string) {
38+
fileRegisterLock.Lock()
3539
// lazy map init
3640
if fileRegister == nil {
3741
fileRegister = make(map[string]bool)
3842
}
3943

4044
fileRegister[strings.Trim(filePath, `"`)] = true
45+
fileRegisterLock.Unlock()
4146
}
4247

4348
// DeregisterLocalFile removes the given filepath from the whitelist.
4449
func DeregisterLocalFile(filePath string) {
50+
fileRegisterLock.Lock()
4551
delete(fileRegister, strings.Trim(filePath, `"`))
52+
fileRegisterLock.Unlock()
4653
}
4754

4855
// RegisterReaderHandler registers a handler function which is used
@@ -61,18 +68,22 @@ func DeregisterLocalFile(filePath string) {
6168
// ...
6269
//
6370
func RegisterReaderHandler(name string, handler func() io.Reader) {
71+
readerRegisterLock.Lock()
6472
// lazy map init
6573
if readerRegister == nil {
6674
readerRegister = make(map[string]func() io.Reader)
6775
}
6876

6977
readerRegister[name] = handler
78+
readerRegisterLock.Unlock()
7079
}
7180

7281
// DeregisterReaderHandler removes the ReaderHandler function with
7382
// the given name from the registry.
7483
func DeregisterReaderHandler(name string) {
84+
readerRegisterLock.Lock()
7585
delete(readerRegister, name)
86+
readerRegisterLock.Unlock()
7687
}
7788

7889
func deferredClose(err *error, closer io.Closer) {
@@ -90,7 +101,11 @@ func (mc *mysqlConn) handleInFileRequest(name string) (err error) {
90101
// The server might return an an absolute path. See issue #355.
91102
name = name[idx+8:]
92103

93-
if handler, inMap := readerRegister[name]; inMap {
104+
readerRegisterLock.RLock()
105+
handler, inMap := readerRegister[name]
106+
readerRegisterLock.RUnlock()
107+
108+
if inMap {
94109
rdr = handler()
95110
if rdr != nil {
96111
data = make([]byte, 4+mc.maxWriteSize)
@@ -106,7 +121,10 @@ func (mc *mysqlConn) handleInFileRequest(name string) (err error) {
106121
}
107122
} else { // File
108123
name = strings.Trim(name, `"`)
109-
if mc.cfg.allowAllFiles || fileRegister[name] {
124+
fileRegisterLock.RLock()
125+
fr := fileRegister[name]
126+
fileRegisterLock.RUnlock()
127+
if mc.cfg.allowAllFiles || fr {
110128
var file *os.File
111129
var fi os.FileInfo
112130

0 commit comments

Comments
 (0)