mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-08-12 09:00:54 +00:00
Treat all strings from read buffers as gc-tainted
Rule: Copies must be made before retaining the string.
This commit is contained in:
parent
fdbcfe98dd
commit
43ecbff656
6 changed files with 37 additions and 17 deletions
|
@ -93,7 +93,7 @@ func HTTPBackendUncachedPublish(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cm := ClientMessage{MessageID: -1, Command: CommandPool.Intern(cmd), origArguments: json}
|
cm := ClientMessage{MessageID: -1, Command: CommandPool.InternCommand(cmd), origArguments: json}
|
||||||
cm.parseOrigArguments()
|
cm.parseOrigArguments()
|
||||||
var count int
|
var count int
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,10 @@ var commandHandlers = map[Command]CommandHandler{
|
||||||
"user_history": C2SHandleRemoteCommand,
|
"user_history": C2SHandleRemoteCommand,
|
||||||
}
|
}
|
||||||
|
|
||||||
func internCommands() {
|
func setupInterning() {
|
||||||
|
PubSubChannelPool = NewStringPool()
|
||||||
|
TwitchChannelPool = NewStringPool()
|
||||||
|
|
||||||
CommandPool = NewStringPool()
|
CommandPool = NewStringPool()
|
||||||
CommandPool._Intern_Setup(string(HelloCommand))
|
CommandPool._Intern_Setup(string(HelloCommand))
|
||||||
CommandPool._Intern_Setup("ping")
|
CommandPool._Intern_Setup("ping")
|
||||||
|
@ -114,7 +117,7 @@ func C2SHello(conn *websocket.Conn, client *ClientInfo, msg ClientMessage) (rmsg
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
client.VersionString = version
|
client.VersionString = copyString(version)
|
||||||
client.Version = VersionFromString(version)
|
client.Version = VersionFromString(version)
|
||||||
|
|
||||||
client.ClientID = uuid.FromStringOrNil(clientID)
|
client.ClientID = uuid.FromStringOrNil(clientID)
|
||||||
|
@ -154,6 +157,8 @@ func C2SSetUser(conn *websocket.Conn, client *ClientInfo, msg ClientMessage) (rm
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
username = copyString(username)
|
||||||
|
|
||||||
client.Mutex.Lock()
|
client.Mutex.Lock()
|
||||||
client.UsernameValidated = false
|
client.UsernameValidated = false
|
||||||
client.TwitchUsername = username
|
client.TwitchUsername = username
|
||||||
|
@ -198,11 +203,12 @@ func C2SReady(conn *websocket.Conn, client *ClientInfo, msg ClientMessage) (rmsg
|
||||||
|
|
||||||
func C2SSubscribe(conn *websocket.Conn, client *ClientInfo, msg ClientMessage) (rmsg ClientMessage, err error) {
|
func C2SSubscribe(conn *websocket.Conn, client *ClientInfo, msg ClientMessage) (rmsg ClientMessage, err error) {
|
||||||
channel, err := msg.ArgumentsAsString()
|
channel, err := msg.ArgumentsAsString()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
channel = PubSubChannelPool.Intern(channel)
|
||||||
|
|
||||||
client.Mutex.Lock()
|
client.Mutex.Lock()
|
||||||
AddToSliceS(&client.CurrentChannels, channel)
|
AddToSliceS(&client.CurrentChannels, channel)
|
||||||
if usePendingSubscrptionsBacklog {
|
if usePendingSubscrptionsBacklog {
|
||||||
|
@ -219,11 +225,12 @@ func C2SSubscribe(conn *websocket.Conn, client *ClientInfo, msg ClientMessage) (
|
||||||
// It removes the channel from ClientInfo.CurrentChannels and calls UnsubscribeSingleChat.
|
// It removes the channel from ClientInfo.CurrentChannels and calls UnsubscribeSingleChat.
|
||||||
func C2SUnsubscribe(conn *websocket.Conn, client *ClientInfo, msg ClientMessage) (rmsg ClientMessage, err error) {
|
func C2SUnsubscribe(conn *websocket.Conn, client *ClientInfo, msg ClientMessage) (rmsg ClientMessage, err error) {
|
||||||
channel, err := msg.ArgumentsAsString()
|
channel, err := msg.ArgumentsAsString()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
channel = PubSubChannelPool.Intern(channel)
|
||||||
|
|
||||||
client.Mutex.Lock()
|
client.Mutex.Lock()
|
||||||
RemoveFromSliceS(&client.CurrentChannels, channel)
|
RemoveFromSliceS(&client.CurrentChannels, channel)
|
||||||
client.Mutex.Unlock()
|
client.Mutex.Unlock()
|
||||||
|
@ -261,6 +268,8 @@ func C2STrackFollow(conn *websocket.Conn, client *ClientInfo, msg ClientMessage)
|
||||||
}
|
}
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
|
|
||||||
|
channel = TwitchChannelPool.Intern(channel)
|
||||||
|
|
||||||
followEventsLock.Lock()
|
followEventsLock.Lock()
|
||||||
followEvents = append(followEvents, followEvent{User: client.TwitchUsername, Channel: channel, NowFollowing: following, Timestamp: now})
|
followEvents = append(followEvents, followEvent{User: client.TwitchUsername, Channel: channel, NowFollowing: following, Timestamp: now})
|
||||||
followEventsLock.Unlock()
|
followEventsLock.Unlock()
|
||||||
|
@ -323,6 +332,7 @@ func C2SEmoticonUses(conn *websocket.Conn, client *ClientInfo, msg ClientMessage
|
||||||
if count > 200 {
|
if count > 200 {
|
||||||
count = 200
|
count = 200
|
||||||
}
|
}
|
||||||
|
roomName = TwitchChannelPool.Intern(roomName)
|
||||||
destMapInner[roomName] += count
|
destMapInner[roomName] += count
|
||||||
total += count
|
total += count
|
||||||
}
|
}
|
||||||
|
@ -422,7 +432,7 @@ var bunchCacheCleanupSignal = sync.NewCond(&bunchCacheLock)
|
||||||
var bunchCacheLastCleanup time.Time
|
var bunchCacheLastCleanup time.Time
|
||||||
|
|
||||||
func bunchedRequestFromCM(msg *ClientMessage) bunchedRequest {
|
func bunchedRequestFromCM(msg *ClientMessage) bunchedRequest {
|
||||||
return bunchedRequest{Command: msg.Command, Param: msg.origArguments}
|
return bunchedRequest{Command: msg.Command, Param: copyString(msg.origArguments)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// is_init_func
|
// is_init_func
|
||||||
|
@ -563,7 +573,7 @@ const AuthorizationFailedErrorString = "Failed to verify your Twitch username."
|
||||||
const AuthorizationNeededError = "You must be signed in to use that command."
|
const AuthorizationNeededError = "You must be signed in to use that command."
|
||||||
|
|
||||||
func doRemoteCommand(conn *websocket.Conn, msg ClientMessage, client *ClientInfo) {
|
func doRemoteCommand(conn *websocket.Conn, msg ClientMessage, client *ClientInfo) {
|
||||||
resp, err := SendRemoteCommandCached(string(msg.Command), msg.origArguments, client.AuthInfo)
|
resp, err := SendRemoteCommandCached(string(msg.Command), copyString(msg.origArguments), client.AuthInfo)
|
||||||
|
|
||||||
if err == ErrAuthorizationNeeded {
|
if err == ErrAuthorizationNeeded {
|
||||||
if client.TwitchUsername == "" {
|
if client.TwitchUsername == "" {
|
||||||
|
|
|
@ -61,6 +61,8 @@ var Configuration *ConfigFile
|
||||||
var janitorsOnce sync.Once
|
var janitorsOnce sync.Once
|
||||||
|
|
||||||
var CommandPool *StringPool
|
var CommandPool *StringPool
|
||||||
|
var PubSubChannelPool *StringPool
|
||||||
|
var TwitchChannelPool *StringPool
|
||||||
|
|
||||||
// SetupServerAndHandle starts all background goroutines and registers HTTP listeners on the given ServeMux.
|
// SetupServerAndHandle starts all background goroutines and registers HTTP listeners on the given ServeMux.
|
||||||
// Essentially, this function completely preps the server for a http.ListenAndServe call.
|
// Essentially, this function completely preps the server for a http.ListenAndServe call.
|
||||||
|
@ -115,7 +117,7 @@ func SetupServerAndHandle(config *ConfigFile, serveMux *http.ServeMux) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
internCommands()
|
setupInterning()
|
||||||
}
|
}
|
||||||
|
|
||||||
// startJanitors starts the 'is_init_func' goroutines
|
// startJanitors starts the 'is_init_func' goroutines
|
||||||
|
@ -514,11 +516,11 @@ func UnmarshalClientMessage(data []byte, payloadType int, v interface{}) (err er
|
||||||
|
|
||||||
spaceIdx = strings.IndexRune(dataStr, ' ')
|
spaceIdx = strings.IndexRune(dataStr, ' ')
|
||||||
if spaceIdx == -1 {
|
if spaceIdx == -1 {
|
||||||
out.Command = CommandPool.Intern(dataStr)
|
out.Command = CommandPool.InternCommand(dataStr)
|
||||||
out.Arguments = nil
|
out.Arguments = nil
|
||||||
return nil
|
return nil
|
||||||
} else {
|
} else {
|
||||||
out.Command = CommandPool.Intern(dataStr[:spaceIdx])
|
out.Command = CommandPool.InternCommand(dataStr[:spaceIdx])
|
||||||
}
|
}
|
||||||
dataStr = dataStr[spaceIdx+1:]
|
dataStr = dataStr[spaceIdx+1:]
|
||||||
argumentsJSON := string([]byte(dataStr))
|
argumentsJSON := string([]byte(dataStr))
|
||||||
|
|
|
@ -6,19 +6,23 @@ import (
|
||||||
|
|
||||||
type StringPool struct {
|
type StringPool struct {
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
lookup map[string]Command
|
lookup map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStringPool() *StringPool {
|
func NewStringPool() *StringPool {
|
||||||
return &StringPool{lookup: make(map[string]Command)}
|
return &StringPool{lookup: make(map[string]string)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// doesn't lock, doesn't check for dupes.
|
// doesn't lock, doesn't check for dupes.
|
||||||
func (p *StringPool) _Intern_Setup(s string) {
|
func (p *StringPool) _Intern_Setup(s string) {
|
||||||
p.lookup[s] = Command(s)
|
p.lookup[s] = s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *StringPool) Intern(s string) Command {
|
func (p *StringPool) InternCommand(s string) Command {
|
||||||
|
return Command(p.Intern(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *StringPool) Intern(s string) string {
|
||||||
p.RLock()
|
p.RLock()
|
||||||
ss, exists := p.lookup[s]
|
ss, exists := p.lookup[s]
|
||||||
p.RUnlock()
|
p.RUnlock()
|
||||||
|
@ -32,7 +36,7 @@ func (p *StringPool) Intern(s string) Command {
|
||||||
if exists {
|
if exists {
|
||||||
return ss
|
return ss
|
||||||
}
|
}
|
||||||
ss = Command(string([]byte(s))) // make a copy
|
ss = copyString(s)
|
||||||
p.lookup[s] = ss
|
p.lookup[ss] = ss
|
||||||
return ss
|
return ss
|
||||||
}
|
}
|
||||||
|
|
|
@ -198,7 +198,7 @@ func HTTPBackendCachedPublish(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := CommandPool.Intern(formData.Get("cmd"))
|
cmd := CommandPool.InternCommand(formData.Get("cmd"))
|
||||||
json := formData.Get("args")
|
json := formData.Get("args")
|
||||||
channel := formData.Get("channel")
|
channel := formData.Get("channel")
|
||||||
deleteMode := formData.Get("delete") != ""
|
deleteMode := formData.Get("delete") != ""
|
||||||
|
|
|
@ -27,6 +27,10 @@ func New4KByteBuffer() interface{} {
|
||||||
return make([]byte, 0, 4096)
|
return make([]byte, 0, 4096)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func copyString(s string) string {
|
||||||
|
return string([]byte(s))
|
||||||
|
}
|
||||||
|
|
||||||
func SealRequest(form url.Values) (url.Values, error) {
|
func SealRequest(form url.Values) (url.Values, error) {
|
||||||
var nonce [24]byte
|
var nonce [24]byte
|
||||||
var err error
|
var err error
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue