From 4d97def768bef86c0025ad907fbb29edaf6c4337 Mon Sep 17 00:00:00 2001 From: Drew Tada Date: Thu, 8 Feb 2024 10:22:03 -0500 Subject: [PATCH] caps revoked on process kill --- kinode/packages/terminal/terminal/src/lib.rs | 36 +------------- kinode/src/kernel/mod.rs | 49 ++++++++++++++++++-- lib/src/core.rs | 7 +++ 3 files changed, 55 insertions(+), 37 deletions(-) diff --git a/kinode/packages/terminal/terminal/src/lib.rs b/kinode/packages/terminal/terminal/src/lib.rs index 414aef51..1b740389 100644 --- a/kinode/packages/terminal/terminal/src/lib.rs +++ b/kinode/packages/terminal/terminal/src/lib.rs @@ -23,7 +23,6 @@ enum TerminalAction { alias: String, process: Option, }, - ProcessEnded(Vec<(ProcessId, Capability)>), } #[derive(Serialize, Deserialize)] @@ -145,12 +144,6 @@ impl Guest for Component { Err(e) => println!("terminal: {e}"), }; } - TerminalAction::ProcessEnded(drop_caps) => { - match handle_process_cleanup(drop_caps) { - Ok(()) => continue, - Err(e) => println!("terminal: {e}"), - } - } } } else { println!("terminal: ignoring message from: {}", source); @@ -261,17 +254,7 @@ fn handle_run( id: parsed_new_process_id.clone(), wasm_bytes_handle: wasm_path.clone(), wit_version: None, - on_exit: kt::OnExit::Requests(vec![( - kt::de_wit_address(our.clone()), - kt::Request { - inherit: false, - expects_response: None, - body: serde_json::to_vec(&TerminalAction::ProcessEnded(granted_caps))?, - metadata: None, - capabilities: vec![], - }, - None, - )]), + on_exit: kt::OnExit::None, initial_capabilities: HashSet::new(), public: entry.public, })?) @@ -318,7 +301,6 @@ fn handle_run( } } // always give it the cap to message the terminal back - // NOTE a malicious script could use this to drop a ton of caps from other processes requested_caps.push(kt::de_wit_capability(Capability { issuer: our.clone(), params: "\"messaging\"".to_string(), @@ -341,7 +323,7 @@ fn handle_run( parsed_new_process_id.clone(), wasm_path.clone(), "None", - kt::OnExit::None, // TODO fix this + kt::OnExit::None, entry.public, { let mut caps_string = "[".to_string(); @@ -426,20 +408,6 @@ fn handle_alias_change( } } -fn handle_process_cleanup(caps_to_remove: Vec<(ProcessId, Capability)>) -> anyhow::Result<()> { - for (process, cap) in caps_to_remove { - println!("terminal: cleaning up process {}, {}", process, cap); - Request::new() - .target(("our", "kernel", "distro", "sys")) - .body(serde_json::to_vec(&kt::KernelCommand::DropCapabilities { - target: process, - capabilities: vec![kt::de_wit_capability(cap)], - })?) - .send()?; - } - Ok(()) -} - fn get_entry(process: &ProcessId) -> anyhow::Result { let drive_path = format!("/{}:{}/pkg", process.package(), process.publisher()); Request::new() diff --git a/kinode/src/kernel/mod.rs b/kinode/src/kernel/mod.rs index 3eeab9c7..9f4dcacd 100644 --- a/kinode/src/kernel/mod.rs +++ b/kinode/src/kernel/mod.rs @@ -86,6 +86,7 @@ async fn handle_kernel_request( senders: &mut Senders, process_handles: &mut ProcessHandles, process_map: &mut t::ProcessMap, + reverse_cap_index: &mut t::ReverseCapIndex, caps_oracle: t::CapMessageSender, engine: &Engine, ) { @@ -334,7 +335,16 @@ async fn handle_kernel_request( ) }) .collect(); - entry.capabilities.extend(signed_caps); + entry.capabilities.extend(signed_caps.clone()); + // add these to reverse cap index + for (cap, _) in &signed_caps { + reverse_cap_index + .entry(cap.clone().issuer.process) + .or_insert_with(HashMap::new) + .entry(target.clone()) + .or_insert_with(Vec::new) + .push(cap.clone()); + } let _ = persist_state(&our_name, &send_to_loop, process_map).await; } t::KernelCommand::DropCapabilities { @@ -444,7 +454,14 @@ async fn handle_kernel_request( t::KernelCommand::KillProcess(process_id) => { // brutal and savage killing: aborting the task. // do not do this to a process if you don't want to risk - // dropped messages / un-replied-to-requests + // dropped messages / un-replied-to-requests / revoked caps + caps_oracle + .send(t::CapMessage::RevokeAll { + on: process_id.clone(), + responder: tokio::sync::oneshot::channel().0, + }) + .await + .expect("event loop: fatal: sender died"); let _ = senders.remove(&process_id); let process_handle = match process_handles.remove(&process_id) { Some(ph) => ph, @@ -643,6 +660,7 @@ pub async fn kernel( our: t::Identity, keypair: Arc, mut process_map: t::ProcessMap, + mut reverse_cap_index: t::ReverseCapIndex, caps_oracle_sender: t::CapMessageSender, mut caps_oracle_receiver: t::CapMessageReceiver, send_to_loop: t::MessageSender, @@ -1025,6 +1043,7 @@ pub async fn kernel( &mut senders, &mut process_handles, &mut process_map, + &mut reverse_cap_index, caps_oracle_sender.clone(), &engine, ).await; @@ -1081,7 +1100,16 @@ pub async fn kernel( cap.clone(), keypair.sign(&rmp_serde::to_vec(&cap).unwrap()).as_ref().to_vec() )).collect(); - entry.capabilities.extend(signed_caps); + entry.capabilities.extend(signed_caps.clone()); + // now we have to insert all caps into the reverse cap index + for (cap, _) in &signed_caps { + reverse_cap_index + .entry(cap.clone().issuer.process) + .or_insert_with(HashMap::new) + .entry(on.clone()) + .or_insert_with(Vec::new) + .push(cap.clone()); + } let _ = persist_state(&our.name, &send_to_loop, &process_map).await; let _ = responder.send(true); }, @@ -1115,6 +1143,21 @@ pub async fn kernel( } ); }, + t::CapMessage::RevokeAll { on, responder } => { + let Some(granter) = reverse_cap_index.get(&on) else { + let _ = responder.send(true); + continue; + }; + for (grantee, caps) in granter { + let Some(entry) = process_map.get_mut(&grantee) else { + continue; + }; + for cap in caps { + entry.capabilities.remove(&cap); + } + } + let _ = responder.send(true); + } t::CapMessage::FilterCaps { on, caps, responder } => { let _ = responder.send( match process_map.get(&on) { diff --git a/lib/src/core.rs b/lib/src/core.rs index a6f39096..5188d9de 100644 --- a/lib/src/core.rs +++ b/lib/src/core.rs @@ -989,6 +989,11 @@ pub enum CapMessage { on: ProcessId, responder: tokio::sync::oneshot::Sender)>>, }, + /// Remove all caps issued by `on` from every process on the entire system + RevokeAll { + on: ProcessId, + responder: tokio::sync::oneshot::Sender, + }, /// before `on` sends a message, filter out any bogus caps it may have attached, sign any new /// caps it may have created, and retreive the signature for the caps in its store. FilterCaps { @@ -998,6 +1003,8 @@ pub enum CapMessage { }, } +pub type ReverseCapIndex = HashMap>>; + pub type ProcessMap = HashMap; #[derive(Clone, Debug, Serialize, Deserialize)]