Просмотр исходного кода

contract/deployooor: Validate webassembly binary and search for needed symbols

parazyd 2 лет назад
Родитель
Сommit
69cfa99860

+ 12 - 1
Cargo.lock

@@ -1872,6 +1872,7 @@ dependencies = [
  "darkfi-serial",
  "getrandom 0.2.11",
  "thiserror",
+ "wasmparser 0.118.0",
 ]
 
 [[package]]
@@ -7593,7 +7594,7 @@ dependencies = [
  "thiserror",
  "wasmer-types",
  "wasmer-vm",
- "wasmparser",
+ "wasmparser 0.95.0",
  "winapi",
 ]
 
@@ -7712,6 +7713,16 @@ dependencies = [
  "url",
 ]
 
+[[package]]
+name = "wasmparser"
+version = "0.118.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebbb91574de0011ded32b14db12777e7dd5e9ea2f9d7317a1ab51a9495c75924"
+dependencies = [
+ "indexmap 2.1.0",
+ "semver 1.0.20",
+]
+
 [[package]]
 name = "wast"
 version = "64.0.0"

+ 1 - 0
src/contract/deployooor/Cargo.toml

@@ -12,6 +12,7 @@ crate-type = ["cdylib", "rlib"]
 darkfi-sdk = { path = "../../sdk" }
 darkfi-serial = { path = "../../serial", features = ["derive", "crypto"] }
 thiserror = "1.0.50"
+wasmparser = "0.118.0"
 
 async-trait = { version = "0.1.74", optional = true }
 

+ 72 - 0
src/contract/deployooor/src/entrypoint/deploy_v1.rs

@@ -25,6 +25,10 @@ use darkfi_sdk::{
     ContractCall,
 };
 use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
+use wasmparser::{
+    ExternalKind::{Func, Memory},
+    Payload::ExportSection,
+};
 
 use crate::{
     error::DeployError,
@@ -85,6 +89,74 @@ pub(crate) fn deploy_process_instruction_v1(
         }
     }
 
+    // Then validate the wasm binary
+    if let Err(e) = wasmparser::validate(&params.wasm_bincode) {
+        msg!("[DeployV1] Error: Failed to validate WASM binary: {}", e);
+        return Err(DeployError::WasmBincodeInvalid.into())
+    }
+
+    // And find all the necessary exports/symbols
+    let mut found_memory = false;
+    let mut found_initialize = false;
+    let mut found_entrypoint = false;
+    let mut found_update = false;
+    let mut found_metadata = false;
+
+    let parser = wasmparser::Parser::new(0);
+    for payload in parser.parse_all(&params.wasm_bincode) {
+        let payload = match payload {
+            Ok(v) => v,
+            Err(e) => {
+                msg!("[DeployV1] Error: Failed parsing WASM payload: {}", e);
+                return Err(DeployError::WasmBincodeInvalid.into())
+            }
+        };
+
+        match payload {
+            ExportSection(v) => {
+                for element in v.into_iter_with_offsets() {
+                    let (_, element) = match element {
+                        Ok(v) => v,
+                        Err(e) => {
+                            msg!("[DeployV1] Error: Failed parsing WASM payload: {}", e);
+                            return Err(DeployError::WasmBincodeInvalid.into())
+                        }
+                    };
+
+                    if element.name == "memory" && element.kind == Memory {
+                        found_memory = true;
+                        continue
+                    }
+
+                    if element.name == "__initialize" && element.kind == Func {
+                        found_initialize = true;
+                        continue
+                    }
+
+                    if element.name == "__entrypoint" && element.kind == Func {
+                        found_entrypoint = true;
+                        continue
+                    }
+
+                    if element.name == "__update" && element.kind == Func {
+                        found_update = true;
+                        continue
+                    }
+
+                    if element.name == "__metadata" && element.kind == Func {
+                        found_metadata = true;
+                    }
+                }
+            }
+            _ => {}
+        }
+    }
+
+    if !found_memory || !found_initialize || !found_entrypoint || !found_update || !found_metadata {
+        msg!("[DeployV1] Error: Failed to find all symbols");
+        return Err(DeployError::WasmBincodeInvalid.into())
+    }
+
     let update = DeployUpdateV1 { contract_id };
     let mut update_data = vec![];
     update_data.write_u8(DeployFunction::DeployV1 as u8)?;

+ 4 - 0
src/contract/deployooor/src/error.rs

@@ -25,6 +25,9 @@ pub enum DeployError {
 
     #[error("Contract does not exist.")]
     ContractNonExistent,
+
+    #[error("WASM bincode invalid.")]
+    WasmBincodeInvalid,
 }
 
 impl From<DeployError> for ContractError {
@@ -32,6 +35,7 @@ impl From<DeployError> for ContractError {
         match e {
             DeployError::ContractLocked => Self::Custom(1),
             DeployError::ContractNonExistent => Self::Custom(2),
+            DeployError::WasmBincodeInvalid => Self::Custom(3),
         }
     }
 }