Skip to content

Commit

Permalink
whitelist certain wasms (#175)
Browse files Browse the repository at this point in the history
* whitelist certain wasms

* use backend to hash

* new whitelist approach

* cleanup

* add to whitelist

* fix

* fix

* address code review

* appease CI?

* next try
  • Loading branch information
sesi200 committed Jul 5, 2023
1 parent fa60278 commit a62d764
Show file tree
Hide file tree
Showing 14 changed files with 69 additions and 18 deletions.
14 changes: 10 additions & 4 deletions service/pool/Main.mo
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ shared (creator) actor class Self(opt_params : ?Types.InitParams) = this {
await getExpiredCanisterInfo();
};

public func installCode(info : Types.CanisterInfo, args : Types.InstallArgs, profiling : Bool) : async Types.CanisterInfo {
public shared ({ caller }) func installCode(info : Types.CanisterInfo, args : Types.InstallArgs, profiling : Bool, is_whitelisted : Bool) : async Types.CanisterInfo {
if (info.timestamp == 0) {
stats := Logs.updateStats(stats, #mismatch);
throw Error.reject "Cannot install removed canister";
Expand All @@ -140,7 +140,13 @@ shared (creator) actor class Self(opt_params : ?Types.InitParams) = this {
limit_stable_memory_page = ?(16384 : Nat32); // Limit to 1G of stable memory
backend_canister_id = ?Principal.fromActor(this);
};
let wasm = await Wasm.transform(args.wasm_module, config);
let wasm = if (caller == controller and is_whitelisted) {
args.wasm_module;
} else if (is_whitelisted) {
await Wasm.is_whitelisted(args.wasm_module);
} else {
await Wasm.transform(args.wasm_module, config);
};
let newArgs = {
arg = args.arg;
wasm_module = wasm;
Expand Down Expand Up @@ -313,7 +319,7 @@ shared (creator) actor class Self(opt_params : ?Types.InitParams) = this {
switch (sanitizeInputs(caller, canister_id)) {
case (#ok info) {
let args = { arg; wasm_module; mode; canister_id };
ignore await installCode(info, args, pool.profiling caller); // inherit the profiling of the parent
ignore await installCode(info, args, pool.profiling caller, false); // inherit the profiling of the parent
};
case (#err makeMsg) throw Error.reject(makeMsg "install_code");
};
Expand Down Expand Up @@ -378,7 +384,7 @@ shared (creator) actor class Self(opt_params : ?Types.InitParams) = this {
msg : {
#GCCanisters : Any;
#balance : Any;
#callForward: Any;
#callForward : Any;
#dump : Any;
#getCanisterId : Any;
#getSubtree : Any;
Expand Down
8 changes: 4 additions & 4 deletions service/pool/tests/actor_class/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ let S = install(wasm, null, opt 100_000_000_000_000);
let nonce = record { timestamp = 1 : int; nonce = 1 : nat };
let c1 = call S.getCanisterId(nonce);
let args = record { arg = blob ""; wasm_module = parent; mode = variant { install }; canister_id = c1.id };
call S.installCode(c1, args, false);
call S.installCode(c1, args, false, false);

let c1 = c1.id;

Expand Down Expand Up @@ -50,7 +50,7 @@ let S = install(wasm, init, opt 100_000_000_000_000);
let nonce = record { timestamp = 1 : int; nonce = 1 : nat };
let c1 = call S.getCanisterId(nonce);
let args = record { arg = blob ""; wasm_module = parent; mode = variant { install }; canister_id = c1.id };
call S.installCode(c1, args, false);
call S.installCode(c1, args, false, false);
let c1 = c1.id;

fail call c1.makeChild(0);
Expand All @@ -63,11 +63,11 @@ let S = install(wasm, null, opt 100_000_000_000_000);
let nonce = record { timestamp = 1 : int; nonce = 1 : nat };
let c1 = call S.getCanisterId(nonce);
let args = record { arg = blob ""; wasm_module = parent; mode = variant { install }; canister_id = c1.id };
call S.installCode(c1, args, false);
call S.installCode(c1, args, false, false);

let c2 = call S.getCanisterId(nonce);
let args = record { arg = blob ""; wasm_module = deleter; mode = variant { install }; canister_id = c2.id };
call S.installCode(c2, args, false);
call S.installCode(c2, args, false, false);

let c1 = c1.id;
let c2 = c2.id;
Expand Down
2 changes: 1 addition & 1 deletion service/pool/tests/canisterPool.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ let init = opt record {
let S = install(wasm, init, null);
let nonce = record { timestamp = 1 : int; nonce = 1 : nat };
let CID = call S.getCanisterId(nonce);
call S.installCode(CID, record { arg = blob ""; wasm_module = empty_wasm; mode = variant { install }; canister_id = CID.id }, false);
call S.installCode(CID, record { arg = blob ""; wasm_module = empty_wasm; mode = variant { install }; canister_id = CID.id }, false, false);
metadata(CID.id, "module_hash");

// Immediately expire
Expand Down
2 changes: 2 additions & 0 deletions service/wasm-utils/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions service/wasm-utils/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ path = "lib.rs"
crate-type = ["cdylib"]

[dependencies]
hex = "0.4.3"
ic-cdk = "0.8.0-beta.0"
ic-cdk-macros = "0.8.0-beta.0"
serde = "1.0"
serde_bytes = "0.11"
candid = "0.9.0-beta.2"
ic-wasm = { version = "0.3.7", default-features = false }
sha2 = "0.10.6"
walrus = "0.19"

[profile.release]
Expand Down
15 changes: 15 additions & 0 deletions service/wasm-utils/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use candid::{CandidType, Deserialize};
use serde_bytes::ByteBuf;

use ic_wasm::*;
use sha2::Digest;

#[derive(CandidType, Deserialize)]
struct Config {
Expand All @@ -11,6 +12,20 @@ struct Config {
backend_canister_id: Option<candid::Principal>,
}

const WHITELISTED_WASMS: [&str; 1] = [
"651425d92d3796ddae581191452e0e87484eeff4ff6352fe9a59c7e1f97a2310", // dfx 0.14.1 frontend canister
];

#[ic_cdk_macros::query]
fn is_whitelisted(wasm: ByteBuf) -> ByteBuf {
let wasm_hash = hex::encode(sha2::Sha256::digest(&wasm));
if WHITELISTED_WASMS.contains(&wasm_hash.as_str()) {
wasm
} else {
ic_cdk::trap("Wasm is not whitelisted")
}
}

#[ic_cdk_macros::query]
fn transform(wasm: ByteBuf, config: Config) -> ByteBuf {
let mut m = walrus::Module::from_buffer(&wasm).unwrap();
Expand Down
10 changes: 8 additions & 2 deletions service/wasm-utils/wasm-utils.did
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
type Config = record { profiling: bool; remove_cycles_add: bool; limit_stable_memory_page: opt nat32; backend_canister_id: opt principal};
type Config = record {
profiling : bool;
remove_cycles_add : bool;
limit_stable_memory_page : opt nat32;
backend_canister_id : opt principal;
};

service : {
transform : (blob, Config) -> (blob);
transform : (blob, Config) -> (blob) query;
is_whitelisted : (blob) -> (blob) query;
}
3 changes: 2 additions & 1 deletion src/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,8 @@ async function install(
const new_info = await backend.installCode(
canisterInfo,
installArgs,
profiling
profiling,
false
);
canisterInfo = new_info;
logger.log(`Code installed at canister id ${canisterInfo.id}`);
Expand Down
2 changes: 1 addition & 1 deletion src/declarations/backend/backend.did
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ type Self =
vec CanisterInfo;
}) query;
http_request: (HttpRequest) -> (HttpResponse) query;
installCode: (CanisterInfo, InstallArgs, bool) -> (CanisterInfo);
installCode: (CanisterInfo, InstallArgs, bool, bool) -> (CanisterInfo);
install_code:
(record {
arg: blob;
Expand Down
5 changes: 4 additions & 1 deletion src/declarations/backend/backend.did.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,10 @@ export interface Self {
Array<[Principal, Array<CanisterInfo>]>
>;
http_request: ActorMethod<[HttpRequest], HttpResponse>;
installCode: ActorMethod<[CanisterInfo, InstallArgs, boolean], CanisterInfo>;
installCode: ActorMethod<
[CanisterInfo, InstallArgs, boolean, boolean],
CanisterInfo
>;
install_code: ActorMethod<
[
{
Expand Down
2 changes: 1 addition & 1 deletion src/declarations/backend/backend.did.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ export const idlFactory = ({ IDL }) => {
),
http_request: IDL.Func([HttpRequest], [HttpResponse], ["query"]),
installCode: IDL.Func(
[CanisterInfo, InstallArgs, IDL.Bool],
[CanisterInfo, InstallArgs, IDL.Bool, IDL.Bool],
[CanisterInfo],
[]
),
Expand Down
10 changes: 8 additions & 2 deletions src/declarations/wasm-utils/wasm-utils.did
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
type Config = record { profiling: bool; remove_cycles_add: bool; limit_stable_memory_page: opt nat32; backend_canister_id: opt principal};
type Config = record {
profiling : bool;
remove_cycles_add : bool;
limit_stable_memory_page : opt nat32;
backend_canister_id : opt principal;
};

service : {
transform : (blob, Config) -> (blob);
transform : (blob, Config) -> (blob) query;
is_whitelisted : (blob) -> (blob) query;
}
1 change: 1 addition & 0 deletions src/declarations/wasm-utils/wasm-utils.did.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export interface Config {
limit_stable_memory_page: [] | [number];
}
export interface _SERVICE {
is_whitelisted: ActorMethod<[Uint8Array | number[]], Uint8Array | number[]>;
transform: ActorMethod<
[Uint8Array | number[], Config],
Uint8Array | number[]
Expand Down
11 changes: 10 additions & 1 deletion src/declarations/wasm-utils/wasm-utils.did.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,16 @@ export const idlFactory = ({ IDL }) => {
limit_stable_memory_page: IDL.Opt(IDL.Nat32),
});
return IDL.Service({
transform: IDL.Func([IDL.Vec(IDL.Nat8), Config], [IDL.Vec(IDL.Nat8)], []),
is_whitelisted: IDL.Func(
[IDL.Vec(IDL.Nat8)],
[IDL.Vec(IDL.Nat8)],
["query"]
),
transform: IDL.Func(
[IDL.Vec(IDL.Nat8), Config],
[IDL.Vec(IDL.Nat8)],
["query"]
),
});
};
export const init = ({ IDL }) => {
Expand Down

0 comments on commit a62d764

Please sign in to comment.