bugfix: protect field access with lock to avoid possible data race (#5211)

This commit is contained in:
Stone-afk 2023-05-18 21:22:41 +08:00 committed by Ming Deng
parent f61065d674
commit 4e481606f7
12 changed files with 81 additions and 98 deletions

View File

@ -9,6 +9,7 @@
- [Fix 5079: only log msg when the channel is not closed](https://github.com/beego/beego/pull/5132) - [Fix 5079: only log msg when the channel is not closed](https://github.com/beego/beego/pull/5132)
- [Fix 4435: Controller SaveToFile remove all temp file](https://github.com/beego/beego/pull/5138) - [Fix 4435: Controller SaveToFile remove all temp file](https://github.com/beego/beego/pull/5138)
- [Fix 5079: Split signalChan into flushChan and closeChan](https://github.com/beego/beego/pull/5139) - [Fix 5079: Split signalChan into flushChan and closeChan](https://github.com/beego/beego/pull/5139)
- [Fix 5172: protect field access with lock to avoid possible data race](https://github.com/beego/beego/pull/5210)
# v2.0.7 # v2.0.7
- [Upgrade github.com/go-kit/kit, CVE-2022-24450](https://github.com/beego/beego/pull/5121) - [Upgrade github.com/go-kit/kit, CVE-2022-24450](https://github.com/beego/beego/pull/5121)

View File

@ -1,54 +0,0 @@
## cache
cache is a Go cache manager. It can use many cache adapters. The repo is inspired by `database/sql` .
## How to install?
go get github.com/beego/beego/v2/client/cache
## What adapters are supported?
As of now this cache support memory, Memcache and Redis.
## How to use it?
First you must import it
import (
"github.com/beego/beego/v2/client/cache"
)
Then init a Cache (example with memory adapter)
bm, err := cache.NewCache("memory", `{"interval":60}`)
Use it like this:
bm.Put("astaxie", 1, 10 * time.Second)
bm.Get("astaxie")
bm.IsExist("astaxie")
bm.Delete("astaxie")
## Memory adapter
Configure memory adapter like this:
{"interval":60}
interval means the gc time. The cache will check at each time interval, whether item has expired.
## Memcache adapter
Memcache adapter use the [gomemcache](http://github.com/bradfitz/gomemcache) client.
Configure like this:
{"conn":"127.0.0.1:11211"}
## Redis adapter
Redis adapter use the [redigo](http://github.com/gomodule/redigo) client.
Configure like this:
{"conn":":6039"}

View File

@ -20,15 +20,16 @@
// //
// Usage: // Usage:
// import( // import(
// _ "github.com/beego/beego/v2/server/web/session/couchbase" //
// "github.com/beego/beego/v2/server/web/session" // _ "github.com/beego/beego/v2/server/web/session/couchbase"
// "github.com/beego/beego/v2/server/web/session"
//
// ) // )
// //
// func init() { // func init() {
// globalSessions, _ = session.NewManager("couchbase", ``{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"http://host:port/, Pool, Bucket"}``) // globalSessions, _ = session.NewManager("couchbase", ``{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"http://host:port/, Pool, Bucket"}``)
// go globalSessions.GC() // go globalSessions.GC()
// } // }
//
package couchbase package couchbase
import ( import (
@ -105,8 +106,10 @@ func (cs *SessionStore) SessionID(context.Context) string {
// SessionRelease Write couchbase session with Gob string // SessionRelease Write couchbase session with Gob string
func (cs *SessionStore) SessionRelease(ctx context.Context, w http.ResponseWriter) { func (cs *SessionStore) SessionRelease(ctx context.Context, w http.ResponseWriter) {
defer cs.b.Close() defer cs.b.Close()
cs.lock.RLock()
bo, err := session.EncodeGob(cs.values) values := cs.values
cs.lock.RUnlock()
bo, err := session.EncodeGob(values)
if err != nil { if err != nil {
return return
} }

View File

@ -69,7 +69,10 @@ func (ls *SessionStore) SessionID(context.Context) string {
// SessionRelease save session values to ledis // SessionRelease save session values to ledis
func (ls *SessionStore) SessionRelease(ctx context.Context, w http.ResponseWriter) { func (ls *SessionStore) SessionRelease(ctx context.Context, w http.ResponseWriter) {
b, err := session.EncodeGob(ls.values) ls.lock.RLock()
values := ls.values
ls.lock.RUnlock()
b, err := session.EncodeGob(values)
if err != nil { if err != nil {
return return
} }

View File

@ -20,15 +20,16 @@
// //
// Usage: // Usage:
// import( // import(
// _ "github.com/beego/beego/v2/server/web/session/memcache" //
// "github.com/beego/beego/v2/server/web/session" // _ "github.com/beego/beego/v2/server/web/session/memcache"
// "github.com/beego/beego/v2/server/web/session"
//
// ) // )
// //
// func init() { // func init() {
// globalSessions, _ = session.NewManager("memcache", ``{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"127.0.0.1:11211"}``) // globalSessions, _ = session.NewManager("memcache", ``{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"127.0.0.1:11211"}``)
// go globalSessions.GC() // go globalSessions.GC()
// } // }
//
package memcache package memcache
import ( import (
@ -96,7 +97,10 @@ func (rs *SessionStore) SessionID(context.Context) string {
// SessionRelease save session values to memcache // SessionRelease save session values to memcache
func (rs *SessionStore) SessionRelease(ctx context.Context, w http.ResponseWriter) { func (rs *SessionStore) SessionRelease(ctx context.Context, w http.ResponseWriter) {
b, err := session.EncodeGob(rs.values) rs.lock.RLock()
values := rs.values
rs.lock.RUnlock()
b, err := session.EncodeGob(values)
if err != nil { if err != nil {
return return
} }

View File

@ -19,6 +19,7 @@
// go install github.com/go-sql-driver/mysql // go install github.com/go-sql-driver/mysql
// //
// mysql session support need create table as sql: // mysql session support need create table as sql:
//
// CREATE TABLE `session` ( // CREATE TABLE `session` (
// `session_key` char(64) NOT NULL, // `session_key` char(64) NOT NULL,
// `session_data` blob, // `session_data` blob,
@ -28,15 +29,16 @@
// //
// Usage: // Usage:
// import( // import(
// _ "github.com/beego/beego/v2/server/web/session/mysql" //
// "github.com/beego/beego/v2/server/web/session" // _ "github.com/beego/beego/v2/server/web/session/mysql"
// "github.com/beego/beego/v2/server/web/session"
//
// ) // )
// //
// func init() { // func init() {
// globalSessions, _ = session.NewManager("mysql", ``{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...&paramN=valueN]"}``) // globalSessions, _ = session.NewManager("mysql", ``{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...&paramN=valueN]"}``)
// go globalSessions.GC() // go globalSessions.GC()
// } // }
//
package mysql package mysql
import ( import (
@ -109,7 +111,10 @@ func (st *SessionStore) SessionID(context.Context) string {
// must call this method to save values to database. // must call this method to save values to database.
func (st *SessionStore) SessionRelease(ctx context.Context, w http.ResponseWriter) { func (st *SessionStore) SessionRelease(ctx context.Context, w http.ResponseWriter) {
defer st.c.Close() defer st.c.Close()
b, err := session.EncodeGob(st.values) st.lock.RLock()
values := st.values
st.lock.RUnlock()
b, err := session.EncodeGob(values)
if err != nil { if err != nil {
return return
} }

View File

@ -18,7 +18,6 @@
// //
// go install github.com/lib/pq // go install github.com/lib/pq
// //
//
// needs this table in your database: // needs this table in your database:
// //
// CREATE TABLE session ( // CREATE TABLE session (
@ -35,18 +34,18 @@
// SessionSavePath = "user=a password=b dbname=c sslmode=disable" // SessionSavePath = "user=a password=b dbname=c sslmode=disable"
// SessionName = session // SessionName = session
// //
//
// Usage: // Usage:
// import( // import(
// _ "github.com/beego/beego/v2/server/web/session/postgresql" //
// "github.com/beego/beego/v2/server/web/session" // _ "github.com/beego/beego/v2/server/web/session/postgresql"
// "github.com/beego/beego/v2/server/web/session"
//
// ) // )
// //
// func init() { // func init() {
// globalSessions, _ = session.NewManager("postgresql", ``{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"user=pqgotest dbname=pqgotest sslmode=verify-full"}``) // globalSessions, _ = session.NewManager("postgresql", ``{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"user=pqgotest dbname=pqgotest sslmode=verify-full"}``)
// go globalSessions.GC() // go globalSessions.GC()
// } // }
//
package postgres package postgres
import ( import (
@ -115,7 +114,10 @@ func (st *SessionStore) SessionID(context.Context) string {
// must call this method to save values to database. // must call this method to save values to database.
func (st *SessionStore) SessionRelease(ctx context.Context, w http.ResponseWriter) { func (st *SessionStore) SessionRelease(ctx context.Context, w http.ResponseWriter) {
defer st.c.Close() defer st.c.Close()
b, err := session.EncodeGob(st.values) st.lock.RLock()
values := st.values
st.lock.RUnlock()
b, err := session.EncodeGob(values)
if err != nil { if err != nil {
return return
} }

View File

@ -20,15 +20,16 @@
// //
// Usage: // Usage:
// import( // import(
// _ "github.com/beego/beego/v2/server/web/session/redis" //
// "github.com/beego/beego/v2/server/web/session" // _ "github.com/beego/beego/v2/server/web/session/redis"
// "github.com/beego/beego/v2/server/web/session"
//
// ) // )
// //
// func init() { // func init() {
// globalSessions, _ = session.NewManager("redis", ``{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"127.0.0.1:7070"}``) // globalSessions, _ = session.NewManager("redis", ``{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"127.0.0.1:7070"}``)
// go globalSessions.GC() // go globalSessions.GC()
// } // }
//
package redis package redis
import ( import (
@ -100,7 +101,10 @@ func (rs *SessionStore) SessionID(context.Context) string {
// SessionRelease save session values to redis // SessionRelease save session values to redis
func (rs *SessionStore) SessionRelease(ctx context.Context, w http.ResponseWriter) { func (rs *SessionStore) SessionRelease(ctx context.Context, w http.ResponseWriter) {
b, err := session.EncodeGob(rs.values) rs.lock.RLock()
values := rs.values
rs.lock.RUnlock()
b, err := session.EncodeGob(values)
if err != nil { if err != nil {
return return
} }

View File

@ -20,15 +20,16 @@
// //
// Usage: // Usage:
// import( // import(
// _ "github.com/beego/beego/v2/server/web/session/redis_cluster" //
// "github.com/beego/beego/v2/server/web/session" // _ "github.com/beego/beego/v2/server/web/session/redis_cluster"
// "github.com/beego/beego/v2/server/web/session"
//
// ) // )
// //
// func init() { // func init() {
// globalSessions, _ = session.NewManager("redis_cluster", ``{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"127.0.0.1:7070;127.0.0.1:7071"}``) // globalSessions, _ = session.NewManager("redis_cluster", ``{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"127.0.0.1:7070;127.0.0.1:7071"}``)
// go globalSessions.GC() // go globalSessions.GC()
// } // }
//
package redis_cluster package redis_cluster
import ( import (
@ -100,7 +101,10 @@ func (rs *SessionStore) SessionID(context.Context) string {
// SessionRelease save session values to redis_cluster // SessionRelease save session values to redis_cluster
func (rs *SessionStore) SessionRelease(ctx context.Context, w http.ResponseWriter) { func (rs *SessionStore) SessionRelease(ctx context.Context, w http.ResponseWriter) {
b, err := session.EncodeGob(rs.values) rs.lock.RLock()
values := rs.values
rs.lock.RUnlock()
b, err := session.EncodeGob(values)
if err != nil { if err != nil {
return return
} }

View File

@ -20,8 +20,10 @@
// //
// Usage: // Usage:
// import( // import(
// _ "github.com/beego/beego/v2/server/web/session/redis_sentinel" //
// "github.com/beego/beego/v2/server/web/session" // _ "github.com/beego/beego/v2/server/web/session/redis_sentinel"
// "github.com/beego/beego/v2/server/web/session"
//
// ) // )
// //
// func init() { // func init() {
@ -101,7 +103,10 @@ func (rs *SessionStore) SessionID(context.Context) string {
// SessionRelease save session values to redis_sentinel // SessionRelease save session values to redis_sentinel
func (rs *SessionStore) SessionRelease(ctx context.Context, w http.ResponseWriter) { func (rs *SessionStore) SessionRelease(ctx context.Context, w http.ResponseWriter) {
b, err := session.EncodeGob(rs.values) rs.lock.RLock()
values := rs.values
rs.lock.RUnlock()
b, err := session.EncodeGob(values)
if err != nil { if err != nil {
return return
} }

View File

@ -75,9 +75,11 @@ func (st *CookieSessionStore) SessionID(context.Context) string {
// SessionRelease Write cookie session to http response cookie // SessionRelease Write cookie session to http response cookie
func (st *CookieSessionStore) SessionRelease(ctx context.Context, w http.ResponseWriter) { func (st *CookieSessionStore) SessionRelease(ctx context.Context, w http.ResponseWriter) {
st.lock.Lock() st.lock.RLock()
encodedCookie, err := encodeCookie(cookiepder.block, cookiepder.config.SecurityKey, cookiepder.config.SecurityName, st.values) values := st.values
st.lock.Unlock() st.lock.RUnlock()
encodedCookie, err := encodeCookie(
cookiepder.block, cookiepder.config.SecurityKey, cookiepder.config.SecurityName, values)
if err == nil { if err == nil {
cookie := &http.Cookie{ cookie := &http.Cookie{
Name: cookiepder.config.CookieName, Name: cookiepder.config.CookieName,
@ -110,11 +112,12 @@ type CookieProvider struct {
// SessionInit Init cookie session provider with max lifetime and config json. // SessionInit Init cookie session provider with max lifetime and config json.
// maxlifetime is ignored. // maxlifetime is ignored.
// json config: // json config:
// securityKey - hash string //
// blockKey - gob encode hash string. it's saved as aes crypto. // securityKey - hash string
// securityName - recognized name in encoded cookie string // blockKey - gob encode hash string. it's saved as aes crypto.
// cookieName - cookie name // securityName - recognized name in encoded cookie string
// maxage - cookie max life time. // cookieName - cookie name
// maxage - cookie max life time.
func (pder *CookieProvider) SessionInit(ctx context.Context, maxlifetime int64, config string) error { func (pder *CookieProvider) SessionInit(ctx context.Context, maxlifetime int64, config string) error {
pder.config = &cookieConfig{} pder.config = &cookieConfig{}
err := json.Unmarshal([]byte(config), pder.config) err := json.Unmarshal([]byte(config), pder.config)

View File

@ -205,7 +205,10 @@ func (s *SessionStore) SessionID(context.Context) string {
// SessionRelease Store the keyvalues into ssdb // SessionRelease Store the keyvalues into ssdb
func (s *SessionStore) SessionRelease(ctx context.Context, w http.ResponseWriter) { func (s *SessionStore) SessionRelease(ctx context.Context, w http.ResponseWriter) {
b, err := session.EncodeGob(s.values) s.lock.RLock()
values := s.values
s.lock.RUnlock()
b, err := session.EncodeGob(values)
if err != nil { if err != nil {
return return
} }