Kaynağa Gözat

Verify folder<->device permission in Request

Requests from valid devices for valid folders should be rejected if the
folder is not shared with that device.
Jakob Borg 11 yıl önce
ebeveyn
işleme
53cd289b90
2 değiştirilmiş dosya ile 32 ekleme ve 4 silme
  1. 7 2
      internal/model/model.go
  2. 25 2
      internal/model/model_test.go

+ 7 - 2
internal/model/model.go

@@ -710,9 +710,14 @@ func (m *Model) Close(device protocol.DeviceID, err error) {
 // Request returns the specified data segment by reading it from local disk.
 // Request returns the specified data segment by reading it from local disk.
 // Implements the protocol.Model interface.
 // Implements the protocol.Model interface.
 func (m *Model) Request(deviceID protocol.DeviceID, folder, name string, offset int64, size int) ([]byte, error) {
 func (m *Model) Request(deviceID protocol.DeviceID, folder, name string, offset int64, size int) ([]byte, error) {
+	if !m.folderSharedWith(folder, deviceID) {
+		l.Warnf("Request from %s for file %s in unshared folder %q", deviceID, name, folder)
+		return nil, ErrNoSuchFile
+	}
+
 	// Verify that the requested file exists in the local model.
 	// Verify that the requested file exists in the local model.
 	m.fmut.RLock()
 	m.fmut.RLock()
-	r, ok := m.folderFiles[folder]
+	folderFiles, ok := m.folderFiles[folder]
 	m.fmut.RUnlock()
 	m.fmut.RUnlock()
 
 
 	if !ok {
 	if !ok {
@@ -720,7 +725,7 @@ func (m *Model) Request(deviceID protocol.DeviceID, folder, name string, offset
 		return nil, ErrNoSuchFile
 		return nil, ErrNoSuchFile
 	}
 	}
 
 
-	lf, ok := r.Get(protocol.LocalDeviceID, name)
+	lf, ok := folderFiles.Get(protocol.LocalDeviceID, name)
 	if !ok {
 	if !ok {
 		return nil, ErrNoSuchFile
 		return nil, ErrNoSuchFile
 	}
 	}

+ 25 - 2
internal/model/model_test.go

@@ -68,18 +68,41 @@ func init() {
 
 
 func TestRequest(t *testing.T) {
 func TestRequest(t *testing.T) {
 	db, _ := leveldb.Open(storage.NewMemStorage(), nil)
 	db, _ := leveldb.Open(storage.NewMemStorage(), nil)
+
 	m := NewModel(config.Wrap("/tmp/test", config.Configuration{}), "device", "syncthing", "dev", db)
 	m := NewModel(config.Wrap("/tmp/test", config.Configuration{}), "device", "syncthing", "dev", db)
-	m.AddFolder(config.FolderConfiguration{ID: "default", Path: "testdata"})
+
+	// device1 shares default, but device2 doesn't
+	m.AddFolder(config.FolderConfiguration{ID: "default", Path: "testdata", Devices: []config.FolderDeviceConfiguration{{DeviceID: device1}}})
 	m.ScanFolder("default")
 	m.ScanFolder("default")
 
 
+	// Existing, shared file
 	bs, err := m.Request(device1, "default", "foo", 0, 6)
 	bs, err := m.Request(device1, "default", "foo", 0, 6)
 	if err != nil {
 	if err != nil {
-		t.Fatal(err)
+		t.Error(err)
 	}
 	}
 	if bytes.Compare(bs, []byte("foobar")) != 0 {
 	if bytes.Compare(bs, []byte("foobar")) != 0 {
 		t.Errorf("Incorrect data from request: %q", string(bs))
 		t.Errorf("Incorrect data from request: %q", string(bs))
 	}
 	}
 
 
+	// Existing, nonshared file
+	bs, err = m.Request(device2, "default", "foo", 0, 6)
+	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))
+	}
+
+	// Nonexistent file
+	bs, err = m.Request(device1, "default", "nonexistent", 0, 6)
+	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))
+	}
+
+	// Shared folder, but disallowed file name
 	bs, err = m.Request(device1, "default", "../walk.go", 0, 6)
 	bs, err = m.Request(device1, "default", "../walk.go", 0, 6)
 	if err == nil {
 	if err == nil {
 		t.Error("Unexpected nil error on insecure file read")
 		t.Error("Unexpected nil error on insecure file read")