Selaa lähdekoodia

Verify requests against model (fixes #15)

Jakob Borg 12 vuotta sitten
vanhempi
sitoutus
4b11e66914
3 muutettua tiedostoa jossa 39 lisäystä ja 0 poistoa
  1. 3 0
      README.md
  2. 13 0
      model/model.go
  3. 23 0
      model/model_test.go

+ 3 - 0
README.md

@@ -88,6 +88,9 @@ fingerprint is computed as the SHA-1 hash of the certificate and
 displayed in BASE32 encoding to form a compact yet convenient string.
 Currently SHA-1 is deemed secure against preimage attacks.
 
+Incoming requests for file data are verified to the extent that the
+requested file name must exist in the local index and the global model.
+
 Installing
 ==========
 

+ 13 - 0
model/model.go

@@ -13,6 +13,7 @@ acquire locks, but document what locks they require.
 
 import (
 	"crypto/sha1"
+	"errors"
 	"fmt"
 	"io"
 	"log"
@@ -58,6 +59,8 @@ const (
 	idxBcastMaxDelay = 120 * time.Second // Unless we've already waited this long
 )
 
+var ErrNoSuchFile = errors.New("no such file")
+
 // NewModel creates and starts a new model. The model starts in read-only mode,
 // where it sends index information to connected peers and responds to requests
 // for file data without altering the local repository in any way.
@@ -271,6 +274,16 @@ func (m *Model) Close(node string, err error) {
 // Request returns the specified data segment by reading it from local disk.
 // Implements the protocol.Model interface.
 func (m *Model) Request(nodeID, name string, offset uint64, size uint32, hash []byte) ([]byte, error) {
+	// Verify that the requested file exists in the local and global model.
+	m.RLock()
+	_, localOk := m.local[name]
+	_, globalOk := m.global[name]
+	m.RUnlock()
+	if !localOk || !globalOk {
+		log.Printf("SECURITY (nonexistent file) REQ(in): %s: %q o=%d s=%d h=%x", nodeID, name, offset, size, hash)
+		return nil, ErrNoSuchFile
+	}
+
 	if m.trace["net"] && nodeID != "<local>" {
 		log.Printf("NET REQ(in): %s: %q o=%d s=%d h=%x", nodeID, name, offset, size, hash)
 	}

+ 23 - 0
model/model_test.go

@@ -1,6 +1,7 @@
 package model
 
 import (
+	"bytes"
 	"os"
 	"reflect"
 	"testing"
@@ -317,3 +318,25 @@ func TestForgetNode(t *testing.T) {
 		t.Errorf("Model len(need) incorrect (%d != %d)", l1, l2)
 	}
 }
+
+func TestRequest(t *testing.T) {
+	m := NewModel("testdata")
+	fs, _ := m.Walk(false)
+	m.ReplaceLocal(fs)
+
+	bs, err := m.Request("some node", "foo", 0, 6, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if bytes.Compare(bs, []byte("foobar")) != 0 {
+		t.Errorf("Incorrect data from request: %q", string(bs))
+	}
+
+	bs, err = m.Request("some node", "../walk.go", 0, 6, nil)
+	if err == nil {
+		t.Error("Unexpected nil error on insecure file read")
+	}
+	if bs != nil {
+		t.Errorf("Unexpected non nil data on insecure file read: %q", string(bs))
+	}
+}