Fixing Race Conditions
the build was successful Details

This commit is contained in:
Sarah Jamie Lewis 2019-11-07 16:11:14 -08:00
parent 9ba39b93b7
commit 5a1fc1b94d
6 changed files with 29 additions and 10 deletions

View File

@ -33,7 +33,7 @@ pipeline:
commands: commands:
- ./tor -f ./torrc - ./tor -f ./torrc
- sleep 15 - sleep 15
- go test -v git.openprivacy.ca/openprivacy/libricochet-go/testing - go test -race -v git.openprivacy.ca/openprivacy/libricochet-go/testing
notify-email: notify-email:
image: drillster/drone-email image: drillster/drone-email
host: build.openprivacy.ca host: build.openprivacy.ca

View File

@ -144,7 +144,9 @@ func (ra *RicochetApplication) Run(ls connectivity.ListenService) {
if !ra.v3identity.Initialized() || ra.contactManager == nil { if !ra.v3identity.Initialized() || ra.contactManager == nil {
return return
} }
ra.lock.Lock()
ra.ls = ls ra.ls = ls
ra.lock.Unlock()
var err error var err error
for err == nil { for err == nil {
conn, err := ra.ls.Accept() conn, err := ra.ls.Accept()

View File

@ -33,6 +33,7 @@ type Connection struct {
messageBuilder utils.MessageBuilder messageBuilder utils.MessageBuilder
closed bool closed bool
closingLock sync.Mutex
closing bool closing bool
// This mutex is exclusively for preventing races during blocking // This mutex is exclusively for preventing races during blocking
// interactions with Process; specifically Do and Break. Don't use // interactions with Process; specifically Do and Break. Don't use
@ -311,6 +312,8 @@ func (rc *Connection) Process(handler Handler) error {
go func() { go func() {
rc.processBlockMutex.Lock() rc.processBlockMutex.Lock()
defer rc.processBlockMutex.Unlock() defer rc.processBlockMutex.Unlock()
rc.closingLock.Lock()
defer rc.closingLock.Unlock()
rc.closed = true rc.closed = true
close(closedChan) close(closedChan)
}() }()
@ -468,5 +471,7 @@ func (rc *Connection) Close() {
// Kill the Ricochet Connection. // Kill the Ricochet Connection.
log.Debugf("Closing Ricochet Connection for %v", rc.RemoteHostname) log.Debugf("Closing Ricochet Connection for %v", rc.RemoteHostname)
rc.conn.Close() rc.conn.Close()
rc.closingLock.Lock()
rc.closed = true rc.closed = true
rc.closingLock.Unlock()
} }

View File

@ -53,6 +53,9 @@ func TestProcessAuthAs3DHServer(t *testing.T) {
t.Errorf("Error while testing ProcessAuthAsServer: %v", err) t.Errorf("Error while testing ProcessAuthAsServer: %v", err)
} }
// Wait for server to finish
time.Sleep(time.Second * 2)
// Test Close // Test Close
rc.Close() rc.Close()
} }

View File

@ -4,13 +4,14 @@
set -e set -e
pwd pwd
go test ${1} -coverprofile=utils.cover.out -v ./utils GORACE="haltonerror=1"
go test ${1} -coverprofile=channels.cover.out -v ./channels go test -race ${1} -coverprofile=utils.cover.out -v ./utils
go test ${1} -coverprofile=channels.v3.inbound.cover.out -v ./channels/v3/inbound go test -race ${1} -coverprofile=channels.cover.out -v ./channels
go test ${1} -coverprofile=connection.cover.out -v ./connection go test -race ${1} -coverprofile=channels.v3.inbound.cover.out -v ./channels/v3/inbound
go test ${1} -coverprofile=policies.cover.out -v ./policies go test -race ${1} -coverprofile=connection.cover.out -v ./connection
go test ${1} -coverprofile=identity.cover.out -v ./identity go test -race ${1} -coverprofile=policies.cover.out -v ./policies
go test ${1} -coverprofile=root.cover.out -v ./ go test -race ${1} -coverprofile=identity.cover.out -v ./identity
go test -race ${1} -coverprofile=root.cover.out -v ./
echo "mode: set" > coverage.out && cat *.cover.out | grep -v mode: | sort -r | \ echo "mode: set" > coverage.out && cat *.cover.out | grep -v mode: | sort -r | \
awk '{if($1 != last) {print $0;last=$1}}' >> coverage.out awk '{if($1 != last) {print $0;last=$1}}' >> coverage.out
rm -rf *.cover.out rm -rf *.cover.out

View File

@ -8,6 +8,7 @@ import (
"git.openprivacy.ca/openprivacy/libricochet-go/log" "git.openprivacy.ca/openprivacy/libricochet-go/log"
"golang.org/x/crypto/nacl/secretbox" "golang.org/x/crypto/nacl/secretbox"
"io" "io"
"sync"
) )
const ( const (
@ -43,10 +44,13 @@ type RicochetNetwork struct {
// Derived ephemeral session key for connection // Derived ephemeral session key for connection
key [32]byte key [32]byte
encrypt bool encrypt bool
lock sync.Mutex
} }
// SetEncryptionKey sets the ephemeral encryption key for this session. // SetEncryptionKey sets the ephemeral encryption key for this session.
func (rn *RicochetNetwork) SetEncryptionKey(key [32]byte) { func (rn *RicochetNetwork) SetEncryptionKey(key [32]byte) {
rn.lock.Lock()
defer rn.lock.Unlock()
log.Debugf("turning on ephemeral session encryption for connection") log.Debugf("turning on ephemeral session encryption for connection")
copy(rn.key[:], key[:]) copy(rn.key[:], key[:])
@ -67,6 +71,7 @@ func (rn *RicochetNetwork) SendRicochetPacket(dst io.Writer, channel int32, data
binary.BigEndian.PutUint16(packet[2:4], uint16(channel)) binary.BigEndian.PutUint16(packet[2:4], uint16(channel))
copy(packet[4:], data[:]) copy(packet[4:], data[:])
rn.lock.Lock()
if rn.encrypt { if rn.encrypt {
var nonce [24]byte var nonce [24]byte
if _, err := io.ReadFull(rand.Reader, nonce[:]); err != nil { if _, err := io.ReadFull(rand.Reader, nonce[:]); err != nil {
@ -77,6 +82,7 @@ func (rn *RicochetNetwork) SendRicochetPacket(dst io.Writer, channel int32, data
binary.BigEndian.PutUint16(packet[0:2], uint16(len(encrypted)+2)) binary.BigEndian.PutUint16(packet[0:2], uint16(len(encrypted)+2))
packet = append(packet[0:2], encrypted...) packet = append(packet[0:2], encrypted...)
} }
rn.lock.Unlock()
for pos := 0; pos < len(packet); { for pos := 0; pos < len(packet); {
n, err := dst.Write(packet[pos:]) n, err := dst.Write(packet[pos:])
@ -112,6 +118,7 @@ func (rn *RicochetNetwork) RecvRicochetPacket(reader io.Reader) (RicochetData, e
return packet, err return packet, err
} }
rn.lock.Lock()
if rn.encrypt { if rn.encrypt {
var decryptNonce [24]byte var decryptNonce [24]byte
if len(packetBytes) > 24 { if len(packetBytes) > 24 {
@ -127,6 +134,7 @@ func (rn *RicochetNetwork) RecvRicochetPacket(reader io.Reader) (RicochetData, e
return packet, errors.New("ciphertext length was too short") return packet, errors.New("ciphertext length was too short")
} }
} }
rn.lock.Unlock()
packet.Channel = int32(binary.BigEndian.Uint16(packetBytes[0:2])) packet.Channel = int32(binary.BigEndian.Uint16(packetBytes[0:2]))
packet.Data = make([]byte, len(packetBytes)-2) packet.Data = make([]byte, len(packetBytes)-2)