Sign symbols so that we can trust opening buffers for them from guests

Antonio Scandurra , Nathan Sobo , and Max Brunsfeld created

Co-Authored-By: Nathan Sobo <nathan@zed.dev>
Co-Authored-By: Max Brunsfeld <max@zed.dev>

Change summary

Cargo.lock                    | 84 +++++++++++++++++++++++++++++-------
crates/project/Cargo.toml     |  3 
crates/project/src/project.rs | 32 +++++++++++++
crates/rpc/proto/zed.proto    |  1 
4 files changed, 101 insertions(+), 19 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -409,7 +409,7 @@ dependencies = [
  "rand 0.7.3",
  "serde",
  "serde_json",
- "sha2",
+ "sha2 0.9.5",
 ]
 
 [[package]]
@@ -686,6 +686,15 @@ dependencies = [
  "generic-array 0.14.4",
 ]
 
+[[package]]
+name = "block-buffer"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324"
+dependencies = [
+ "generic-array 0.14.4",
+]
+
 [[package]]
 name = "block-padding"
 version = "0.1.5"
@@ -1124,7 +1133,7 @@ dependencies = [
  "hmac 0.10.1",
  "percent-encoding",
  "rand 0.8.3",
- "sha2",
+ "sha2 0.9.5",
  "time 0.2.25",
  "version_check",
 ]
@@ -1187,6 +1196,15 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "cpufeatures"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469"
+dependencies = [
+ "libc",
+]
+
 [[package]]
 name = "cpuid-bool"
 version = "0.2.0"
@@ -1280,6 +1298,16 @@ dependencies = [
  "zeroize",
 ]
 
+[[package]]
+name = "crypto-common"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8"
+dependencies = [
+ "generic-array 0.14.4",
+ "typenum",
+]
+
 [[package]]
 name = "crypto-mac"
 version = "0.8.0"
@@ -1447,6 +1475,16 @@ dependencies = [
  "generic-array 0.14.4",
 ]
 
+[[package]]
+name = "digest"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506"
+dependencies = [
+ "block-buffer 0.10.2",
+ "crypto-common",
+]
+
 [[package]]
 name = "dirs"
 version = "3.0.1"
@@ -2604,7 +2642,7 @@ dependencies = [
  "cfg-if 1.0.0",
  "ecdsa",
  "elliptic-curve",
- "sha2",
+ "sha2 0.9.5",
 ]
 
 [[package]]
@@ -2691,9 +2729,9 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.98"
+version = "0.2.119"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790"
+checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4"
 
 [[package]]
 name = "libloading"
@@ -3065,7 +3103,7 @@ dependencies = [
  "serde",
  "serde_json",
  "serde_path_to_error",
- "sha2",
+ "sha2 0.9.5",
  "thiserror",
  "url",
 ]
@@ -3183,7 +3221,7 @@ checksum = "d053368e1bae4c8a672953397bd1bd7183dde1c72b0b7612a15719173148d186"
 dependencies = [
  "ecdsa",
  "elliptic-curve",
- "sha2",
+ "sha2 0.9.5",
 ]
 
 [[package]]
@@ -3537,6 +3575,7 @@ dependencies = [
  "rpc",
  "serde",
  "serde_json",
+ "sha2 0.10.2",
  "smol",
  "sum_tree",
  "tempdir",
@@ -3972,7 +4011,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ad22c7226e4829104deab21df575e995bfbc4adfad13a595e387477f238c1aec"
 dependencies = [
  "globset",
- "sha2",
+ "sha2 0.9.5",
  "walkdir",
 ]
 
@@ -4111,7 +4150,7 @@ dependencies = [
  "password-hash",
  "pbkdf2",
  "salsa20",
- "sha2",
+ "sha2 0.9.5",
 ]
 
 [[package]]
@@ -4281,7 +4320,7 @@ checksum = "8c4cfa741c5832d0ef7fab46cabed29c2aae926db0b11bb2069edd8db5e64e16"
 dependencies = [
  "block-buffer 0.9.0",
  "cfg-if 1.0.0",
- "cpufeatures",
+ "cpufeatures 0.1.4",
  "digest 0.9.0",
  "opaque-debug 0.3.0",
 ]
@@ -4300,11 +4339,22 @@ checksum = "b362ae5752fd2137731f9fa25fd4d9058af34666ca1966fb969119cc35719f12"
 dependencies = [
  "block-buffer 0.9.0",
  "cfg-if 1.0.0",
- "cpufeatures",
+ "cpufeatures 0.1.4",
  "digest 0.9.0",
  "opaque-debug 0.3.0",
 ]
 
+[[package]]
+name = "sha2"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676"
+dependencies = [
+ "cfg-if 1.0.0",
+ "cpufeatures 0.2.1",
+ "digest 0.10.3",
+]
+
 [[package]]
 name = "shell-words"
 version = "1.0.0"
@@ -4573,7 +4623,7 @@ dependencies = [
  "serde",
  "serde_json",
  "sha-1 0.9.6",
- "sha2",
+ "sha2 0.9.5",
  "smallvec",
  "sqlformat",
  "sqlx-rt 0.2.0",
@@ -4622,7 +4672,7 @@ dependencies = [
  "serde",
  "serde_json",
  "sha-1 0.9.6",
- "sha2",
+ "sha2 0.9.5",
  "smallvec",
  "sqlformat",
  "sqlx-rt 0.5.5",
@@ -4651,7 +4701,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "serde_json",
- "sha2",
+ "sha2 0.9.5",
  "sqlx-core 0.4.2",
  "sqlx-rt 0.2.0",
  "syn",
@@ -4671,7 +4721,7 @@ dependencies = [
  "once_cell",
  "proc-macro2",
  "quote",
- "sha2",
+ "sha2 0.9.5",
  "sqlx-core 0.5.5",
  "sqlx-rt 0.5.5",
  "syn",
@@ -5293,9 +5343,9 @@ checksum = "a9b2228007eba4120145f785df0f6c92ea538f5a3635a612ecf4e334c8c1446d"
 
 [[package]]
 name = "typenum"
-version = "1.13.0"
+version = "1.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06"
+checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
 
 [[package]]
 name = "ucd-trie"

crates/project/Cargo.toml 🔗

@@ -35,8 +35,10 @@ libc = "0.2"
 log = "0.4"
 parking_lot = "0.11.1"
 postage = { version = "0.4.1", features = ["futures-traits"] }
+rand = "0.8.3"
 serde = { version = "1", features = ["derive"] }
 serde_json = { version = "1.0.64", features = ["preserve_order"] }
+sha2 = "0.10"
 smol = "1.2.5"
 toml = "0.5"
 
@@ -48,6 +50,5 @@ language = { path = "../language", features = ["test-support"] }
 lsp = { path = "../lsp", features = ["test-support"] }
 util = { path = "../util", features = ["test-support"] }
 rpc = { path = "../rpc", features = ["test-support"] }
-rand = "0.8.3"
 tempdir = { version = "0.3.7" }
 unindent = "0.1.7"

crates/project/src/project.rs 🔗

@@ -21,9 +21,12 @@ use language::{
 use lsp::{DiagnosticSeverity, LanguageServer};
 use lsp_command::*;
 use postage::{broadcast, prelude::Stream, sink::Sink, watch};
+use rand::prelude::*;
+use sha2::{Digest, Sha256};
 use smol::block_on;
 use std::{
     convert::TryInto,
+    hash::Hash,
     mem,
     ops::Range,
     path::{Component, Path, PathBuf},
@@ -56,6 +59,7 @@ pub struct Project {
         postage::watch::Receiver<Option<Result<ModelHandle<Buffer>, Arc<anyhow::Error>>>>,
     >,
     shared_buffers: HashMap<PeerId, HashMap<u64, ModelHandle<Buffer>>>,
+    nonce: u128,
 }
 
 enum OpenBuffer {
@@ -129,6 +133,7 @@ pub struct Symbol {
     pub name: String,
     pub kind: lsp::SymbolKind,
     pub range: Range<PointUtf16>,
+    pub signature: [u8; 32],
 }
 
 #[derive(Default)]
@@ -276,6 +281,7 @@ impl Project {
                 language_servers_with_diagnostics_running: 0,
                 language_servers: Default::default(),
                 started_language_servers: Default::default(),
+                nonce: StdRng::from_entropy().gen(),
             }
         })
     }
@@ -328,6 +334,7 @@ impl Project {
                 language_servers_with_diagnostics_running: 0,
                 language_servers: Default::default(),
                 started_language_servers: Default::default(),
+                nonce: StdRng::from_entropy().gen(),
             };
             for worktree in worktrees {
                 this.add_worktree(&worktree, cx);
@@ -1289,6 +1296,7 @@ impl Project {
                                         .unwrap_or_else(|| {
                                             CodeLabel::plain(lsp_symbol.name.clone(), None)
                                         });
+                                    let signature = this.symbol_signature(worktree_id, &path);
 
                                     Some(Symbol {
                                         source_worktree_id,
@@ -1299,6 +1307,7 @@ impl Project {
                                         label,
                                         path,
                                         range: range_from_lsp(lsp_symbol.location.range),
+                                        signature,
                                     })
                                 },
                             ));
@@ -2725,7 +2734,15 @@ impl Project {
             .payload
             .symbol
             .ok_or_else(|| anyhow!("invalid symbol"))?;
-        let symbol = this.read_with(&cx, |this, _| this.deserialize_symbol(symbol))?;
+        let symbol = this.read_with(&cx, |this, _| {
+            let symbol = this.deserialize_symbol(symbol)?;
+            let signature = this.symbol_signature(symbol.worktree_id, &symbol.path);
+            if signature == symbol.signature {
+                Ok(symbol)
+            } else {
+                Err(anyhow!("invalid symbol signature"))
+            }
+        })?;
         let buffer = this
             .update(&mut cx, |this, cx| this.open_buffer_for_symbol(&symbol, cx))
             .await?;
@@ -2737,6 +2754,14 @@ impl Project {
         })
     }
 
+    fn symbol_signature(&self, worktree_id: WorktreeId, path: &Path) -> [u8; 32] {
+        let mut hasher = Sha256::new();
+        hasher.update(worktree_id.to_proto().to_be_bytes());
+        hasher.update(path.to_string_lossy().as_bytes());
+        hasher.update(self.nonce.to_be_bytes());
+        hasher.finalize().as_slice().try_into().unwrap()
+    }
+
     async fn handle_open_buffer(
         this: ModelHandle<Self>,
         envelope: TypedEnvelope<proto::OpenBuffer>,
@@ -2920,6 +2945,10 @@ impl Project {
             path: PathBuf::from(serialized_symbol.path),
             range: PointUtf16::new(start.row, start.column)..PointUtf16::new(end.row, end.column),
             kind,
+            signature: serialized_symbol
+                .signature
+                .try_into()
+                .map_err(|_| anyhow!("invalid signature"))?,
         })
     }
 
@@ -3220,6 +3249,7 @@ fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
             row: symbol.range.end.row,
             column: symbol.range.end.column,
         }),
+        signature: symbol.signature.to_vec(),
     }
 }
 

crates/rpc/proto/zed.proto 🔗

@@ -193,6 +193,7 @@ message Symbol {
     string path = 6;
     Point start = 7;
     Point end = 8;
+    bytes signature = 9;
 }
 
 message OpenBufferForSymbol {