Browse code

Fix race accessing plugin storage map

`plugins.GetAll()` was not locking the plugin map when checking if a
plugin exists, this can cause a race and potentially a panic if another
goroutine is trying to load a plugin into the map at the same time.

Also fixes a race during activation where a plugin inserts itself into
the plugin map but does not check if something else is already there.
This is already checked before trying to activate the plugin, however
the map lock is not held for this entire period, so other plugins may be
loaded during this time.
To fix, before inserting the plugin into the map, check if one with the
same name already exists and use that instead.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>

Brian Goff authored on 2017/01/05 05:29:10
Showing 1 changed files
... ...
@@ -221,6 +221,10 @@ func loadWithRetry(name string, retry bool) (*Plugin, error) {
221 221
 		}
222 222
 
223 223
 		storage.Lock()
224
+		if pl, exists := storage.plugins[name]; exists {
225
+			storage.Unlock()
226
+			return pl, pl.activate()
227
+		}
224 228
 		storage.plugins[name] = pl
225 229
 		storage.Unlock()
226 230
 
... ...
@@ -298,7 +302,10 @@ func GetAll(imp string) ([]*Plugin, error) {
298 298
 	chPl := make(chan *plLoad, len(pluginNames))
299 299
 	var wg sync.WaitGroup
300 300
 	for _, name := range pluginNames {
301
-		if pl, ok := storage.plugins[name]; ok {
301
+		storage.Lock()
302
+		pl, ok := storage.plugins[name]
303
+		storage.Unlock()
304
+		if ok {
302 305
 			chPl <- &plLoad{pl, nil}
303 306
 			continue
304 307
 		}