1
0
Fork 0
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:
Kane York 2016-01-17 19:46:01 -08:00
parent fdbcfe98dd
commit 43ecbff656
6 changed files with 37 additions and 17 deletions

View file

@ -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

View file

@ -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 == "" {

View file

@ -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))

View file

@ -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
} }

View file

@ -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") != ""

View file

@ -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