1use crate::dict::Key;
6use crate::fidl::registry;
7use crate::{Capability, Connector, Dict, DirConnector, Message};
8use cm_types::RelativePath;
9use fidl::handle::Signals;
10use fidl::AsHandleRef;
11use futures::{FutureExt, TryStreamExt};
12use log::warn;
13use std::collections::hash_map::Entry;
14use std::collections::HashMap;
15use std::sync::{self, Arc, Weak};
16use {fidl_fuchsia_component_sandbox as fsandbox, fuchsia_async as fasync};
17
18type Store = sync::Mutex<HashMap<u64, Capability>>;
19
20pub async fn serve_capability_store(
21 mut stream: fsandbox::CapabilityStoreRequestStream,
22 receiver_scope: &fasync::Scope,
30) -> Result<(), fidl::Error> {
31 let outer_store: Arc<Store> = Arc::new(Store::new(Default::default()));
32 while let Some(request) = stream.try_next().await? {
33 let mut store = outer_store.lock().unwrap();
34 match request {
35 fsandbox::CapabilityStoreRequest::Duplicate { id, dest_id, responder } => {
36 let result = (|| {
37 let cap = store.get(&id).ok_or(fsandbox::CapabilityStoreError::IdNotFound)?;
38 let cap = cap
39 .try_clone()
40 .map_err(|_| fsandbox::CapabilityStoreError::NotDuplicatable)?;
41 insert_capability(&mut store, dest_id, cap)
42 })();
43 responder.send(result)?;
44 }
45 fsandbox::CapabilityStoreRequest::Drop { id, responder } => {
46 let result =
47 store.remove(&id).map(|_| ()).ok_or(fsandbox::CapabilityStoreError::IdNotFound);
48 responder.send(result)?;
49 }
50 fsandbox::CapabilityStoreRequest::Export { id, responder } => {
51 let result = (|| {
52 let cap =
53 store.remove(&id).ok_or(fsandbox::CapabilityStoreError::IdNotFound)?;
54 Ok(cap.into())
55 })();
56 responder.send(result)?;
57 }
58 fsandbox::CapabilityStoreRequest::Import { id, capability, responder } => {
59 let result = (|| {
60 let capability = capability
61 .try_into()
62 .map_err(|_| fsandbox::CapabilityStoreError::BadCapability)?;
63 insert_capability(&mut store, id, capability)
64 })();
65 responder.send(result)?;
66 }
67 fsandbox::CapabilityStoreRequest::ConnectorCreate { id, receiver, responder } => {
68 let result = (|| {
69 let connector = Connector::new_with_fidl_receiver(receiver, receiver_scope);
70 insert_capability(&mut store, id, Capability::Connector(connector))
71 })();
72 responder.send(result)?;
73 }
74 fsandbox::CapabilityStoreRequest::ConnectorOpen { id, server_end, responder } => {
75 let result = (|| {
76 let this = get_connector(&store, id)?;
77 let _ = this.send(Message { channel: server_end });
78 Ok(())
79 })();
80 responder.send(result)?;
81 }
82 fsandbox::CapabilityStoreRequest::DirConnectorCreate { id, receiver, responder } => {
83 let result = (|| {
84 let connector = DirConnector::new_with_fidl_receiver(receiver, receiver_scope);
85 insert_capability(&mut store, id, Capability::DirConnector(connector))
86 })();
87 responder.send(result)?;
88 }
89 fsandbox::CapabilityStoreRequest::DirConnectorOpen { id, server_end, responder } => {
90 let result = (|| {
91 let this = get_dir_connector(&store, id)?;
92 let _ = this.send(server_end, RelativePath::dot(), None);
93 Ok(())
94 })();
95 responder.send(result)?;
96 }
97 fsandbox::CapabilityStoreRequest::DictionaryCreate { id, responder } => {
98 let result = insert_capability(&mut store, id, Capability::Dictionary(Dict::new()));
99 responder.send(result)?;
100 }
101 fsandbox::CapabilityStoreRequest::DictionaryLegacyImport {
102 id,
103 client_end,
104 responder,
105 } => {
106 let result = (|| {
107 let capability = Dict::try_from(client_end)
108 .map_err(|_| fsandbox::CapabilityStoreError::BadCapability)?
109 .into();
110 insert_capability(&mut store, id, capability)
111 })();
112 responder.send(result)?;
113 }
114 fsandbox::CapabilityStoreRequest::DictionaryLegacyExport {
115 id,
116 server_end,
117 responder,
118 } => {
119 let result = (|| {
120 let cap =
121 store.remove(&id).ok_or(fsandbox::CapabilityStoreError::IdNotFound)?;
122 let Capability::Dictionary(_) = &cap else {
123 return Err(fsandbox::CapabilityStoreError::WrongType);
124 };
125 let koid = server_end.basic_info().unwrap().related_koid;
126 registry::insert(
127 cap,
128 koid,
129 fasync::OnSignals::new(server_end, Signals::OBJECT_PEER_CLOSED).map(|_| ()),
130 );
131 Ok(())
132 })();
133 responder.send(result)?
134 }
135 fsandbox::CapabilityStoreRequest::DictionaryInsert { id, item, responder } => {
136 let result = (|| {
137 let this = get_dictionary(&store, id)?;
138 let this = this.clone();
139 let key =
140 item.key.parse().map_err(|_| fsandbox::CapabilityStoreError::InvalidKey)?;
141 let value = store
142 .remove(&item.value)
143 .ok_or(fsandbox::CapabilityStoreError::IdNotFound)?;
144 this.insert(key, value)
145 })();
146 responder.send(result)?;
147 }
148 fsandbox::CapabilityStoreRequest::DictionaryGet { id, key, dest_id, responder } => {
149 let result = (|| {
150 let this = get_dictionary(&store, id)?;
151 let key =
152 Key::new(key).map_err(|_| fsandbox::CapabilityStoreError::InvalidKey)?;
153 let cap = match this.get(&key) {
154 Ok(Some(cap)) => Ok(cap),
155 Ok(None) => {
156 this.not_found(key.as_str());
157 Err(fsandbox::CapabilityStoreError::ItemNotFound)
158 }
159 Err(()) => Err(fsandbox::CapabilityStoreError::NotDuplicatable),
160 }?;
161 insert_capability(&mut store, dest_id, cap)
162 })();
163 responder.send(result)?;
164 }
165 fsandbox::CapabilityStoreRequest::DictionaryRemove { id, key, dest_id, responder } => {
166 let result = (|| {
167 let this = get_dictionary(&store, id)?;
168 let key =
169 Key::new(key).map_err(|_| fsandbox::CapabilityStoreError::InvalidKey)?;
170 if let Some(dest_id) = dest_id.as_ref() {
172 if store.contains_key(&dest_id.id) {
173 return Err(fsandbox::CapabilityStoreError::IdAlreadyExists);
174 }
175 }
176 let cap = match this.remove(&key) {
177 Some(cap) => Ok(cap.into()),
178 None => {
179 this.not_found(key.as_str());
180 Err(fsandbox::CapabilityStoreError::ItemNotFound)
181 }
182 }?;
183 if let Some(dest_id) = dest_id.as_ref() {
184 store.insert(dest_id.id, cap);
185 }
186 Ok(())
187 })();
188 responder.send(result)?;
189 }
190 fsandbox::CapabilityStoreRequest::DictionaryCopy { id, dest_id, responder } => {
191 let result = (|| {
192 let this = get_dictionary(&store, id)?;
193 let dict = this
194 .shallow_copy()
195 .map_err(|_| fsandbox::CapabilityStoreError::NotDuplicatable)?;
196 insert_capability(&mut store, dest_id, Capability::Dictionary(dict))
197 })();
198 responder.send(result)?
199 }
200 fsandbox::CapabilityStoreRequest::DictionaryKeys {
201 id,
202 iterator: server_end,
203 responder,
204 } => {
205 let result = (|| {
206 let this = get_dictionary(&store, id)?;
207 let keys = this.keys();
208 let stream = server_end.into_stream();
209 let mut this = this.lock();
210 this.tasks().spawn(serve_dictionary_keys_iterator(keys, stream));
211 Ok(())
212 })();
213 responder.send(result)?
214 }
215 fsandbox::CapabilityStoreRequest::DictionaryEnumerate {
216 id,
217 iterator: server_end,
218 responder,
219 } => {
220 let result = (|| {
221 let this = get_dictionary(&store, id)?;
222 let items = this.enumerate();
223 let stream = server_end.into_stream();
224 let mut this = this.lock();
225 this.tasks().spawn(serve_dictionary_enumerate_iterator(
226 Arc::downgrade(&outer_store),
227 items,
228 stream,
229 ));
230 Ok(())
231 })();
232 responder.send(result)?
233 }
234 fsandbox::CapabilityStoreRequest::DictionaryDrain {
235 id,
236 iterator: server_end,
237 responder,
238 } => {
239 let result = (|| {
240 let this = get_dictionary(&store, id)?;
241 let items = this.drain();
244 if let Some(server_end) = server_end {
245 let stream = server_end.into_stream();
246 let mut this = this.lock();
247 this.tasks().spawn(serve_dictionary_drain_iterator(
248 Arc::downgrade(&outer_store),
249 items,
250 stream,
251 ));
252 }
253 Ok(())
254 })();
255 responder.send(result)?
256 }
257 fsandbox::CapabilityStoreRequest::_UnknownMethod { ordinal, .. } => {
258 warn!("Received unknown CapabilityStore request with ordinal {ordinal}");
259 }
260 }
261 }
262 Ok(())
263}
264
265async fn serve_dictionary_keys_iterator(
266 mut keys: impl Iterator<Item = Key>,
267 mut stream: fsandbox::DictionaryKeysIteratorRequestStream,
268) {
269 while let Ok(Some(request)) = stream.try_next().await {
270 match request {
271 fsandbox::DictionaryKeysIteratorRequest::GetNext { responder } => {
272 let mut chunk = vec![];
273 for _ in 0..fsandbox::MAX_DICTIONARY_ITERATOR_CHUNK {
274 match keys.next() {
275 Some(key) => {
276 chunk.push(key.into());
277 }
278 None => break,
279 }
280 }
281 let _ = responder.send(&chunk);
282 }
283 fsandbox::DictionaryKeysIteratorRequest::_UnknownMethod { ordinal, .. } => {
284 warn!(ordinal:%; "Unknown DictionaryKeysIterator request");
285 }
286 }
287 }
288}
289
290async fn serve_dictionary_enumerate_iterator(
291 store: Weak<Store>,
292 mut items: impl Iterator<Item = (Key, Result<Capability, ()>)>,
293 mut stream: fsandbox::DictionaryEnumerateIteratorRequestStream,
294) {
295 while let Ok(Some(request)) = stream.try_next().await {
296 let Some(store) = store.upgrade() else {
297 return;
298 };
299 let mut store = store.lock().unwrap();
300 match request {
301 fsandbox::DictionaryEnumerateIteratorRequest::GetNext {
302 start_id,
303 limit,
304 responder,
305 } => {
306 let result = (|| {
307 let mut next_id = start_id;
308 let chunk = get_next_chunk(&*store, &mut items, &mut next_id, limit)?;
309 let end_id = next_id;
310
311 let chunk: Vec<_> = chunk
312 .into_iter()
313 .map(|(key, value)| {
314 if let Some((capability, id)) = value {
315 store.insert(id, capability);
316 fsandbox::DictionaryOptionalItem {
317 key: key.into(),
318 value: Some(Box::new(fsandbox::WrappedCapabilityId { id })),
319 }
320 } else {
321 fsandbox::DictionaryOptionalItem { key: key.into(), value: None }
322 }
323 })
324 .collect();
325 Ok((chunk, end_id))
326 })();
327 let err = result.is_err();
328 let _ = responder.send(result);
329 if err {
330 return;
331 }
332 }
333 fsandbox::DictionaryEnumerateIteratorRequest::_UnknownMethod { ordinal, .. } => {
334 warn!(ordinal:%; "Unknown DictionaryEnumerateIterator request");
335 }
336 }
337 }
338}
339
340async fn serve_dictionary_drain_iterator(
341 store: Weak<Store>,
342 items: impl Iterator<Item = (Key, Capability)>,
343 mut stream: fsandbox::DictionaryDrainIteratorRequestStream,
344) {
345 let mut items = items.map(|(key, capability)| (key, Ok(capability)));
347 while let Ok(Some(request)) = stream.try_next().await {
348 let Some(store) = store.upgrade() else {
349 return;
350 };
351 let mut store = store.lock().unwrap();
352 match request {
353 fsandbox::DictionaryDrainIteratorRequest::GetNext { start_id, limit, responder } => {
354 let result = (|| {
355 let mut next_id = start_id;
356 let chunk = get_next_chunk(&*store, &mut items, &mut next_id, limit)?;
357 let end_id = next_id;
358
359 let chunk: Vec<_> = chunk
360 .into_iter()
361 .map(|(key, value)| {
362 let value = value.expect("unreachable: all values are present");
363 let (capability, id) = value;
364 store.insert(id, capability);
365 fsandbox::DictionaryItem { key: key.into(), value: id }
366 })
367 .collect();
368 Ok((chunk, end_id))
369 })();
370 match result {
371 Ok((chunk, id)) => {
372 let _ = responder.send(Ok((&chunk[..], id)));
373 }
374 Err(e) => {
375 let _ = responder.send(Err(e));
376 return;
377 }
378 }
379 }
380 fsandbox::DictionaryDrainIteratorRequest::_UnknownMethod { ordinal, .. } => {
381 warn!(ordinal:%; "Unknown DictionaryDrainIterator request");
382 }
383 }
384 }
385}
386
387fn get_next_chunk(
388 store: &HashMap<u64, Capability>,
389 items: &mut impl Iterator<Item = (Key, Result<Capability, ()>)>,
390 next_id: &mut u64,
391 limit: u32,
392) -> Result<Vec<(Key, Option<(Capability, fsandbox::CapabilityId)>)>, fsandbox::CapabilityStoreError>
393{
394 if limit == 0 || limit > fsandbox::MAX_DICTIONARY_ITERATOR_CHUNK {
395 return Err(fsandbox::CapabilityStoreError::InvalidArgs);
396 }
397
398 let mut chunk = vec![];
399 for _ in 0..limit {
400 match items.next() {
401 Some((key, value)) => {
402 let value = match value {
403 Ok(value) => {
404 let id = *next_id;
405 if store.contains_key(&id) {
408 return Err(fsandbox::CapabilityStoreError::IdAlreadyExists);
409 }
410 *next_id += 1;
411 Some((value, id))
412 }
413 Err(_) => None,
414 };
415 chunk.push((key, value));
416 }
417 None => break,
418 }
419 }
420 Ok(chunk)
421}
422
423fn get_connector(
424 store: &HashMap<u64, Capability>,
425 id: u64,
426) -> Result<&Connector, fsandbox::CapabilityStoreError> {
427 let conn = store.get(&id).ok_or(fsandbox::CapabilityStoreError::IdNotFound)?;
428 if let Capability::Connector(conn) = conn {
429 Ok(conn)
430 } else {
431 Err(fsandbox::CapabilityStoreError::WrongType)
432 }
433}
434
435fn get_dir_connector(
436 store: &HashMap<u64, Capability>,
437 id: u64,
438) -> Result<&DirConnector, fsandbox::CapabilityStoreError> {
439 let conn = store.get(&id).ok_or(fsandbox::CapabilityStoreError::IdNotFound)?;
440 if let Capability::DirConnector(conn) = conn {
441 Ok(conn)
442 } else {
443 Err(fsandbox::CapabilityStoreError::WrongType)
444 }
445}
446
447fn get_dictionary(
448 store: &HashMap<u64, Capability>,
449 id: u64,
450) -> Result<&Dict, fsandbox::CapabilityStoreError> {
451 let dict = store.get(&id).ok_or(fsandbox::CapabilityStoreError::IdNotFound)?;
452 if let Capability::Dictionary(dict) = dict {
453 Ok(dict)
454 } else {
455 Err(fsandbox::CapabilityStoreError::WrongType)
456 }
457}
458
459fn insert_capability(
460 store: &mut HashMap<u64, Capability>,
461 id: u64,
462 cap: Capability,
463) -> Result<(), fsandbox::CapabilityStoreError> {
464 match store.entry(id) {
465 Entry::Occupied(_) => Err(fsandbox::CapabilityStoreError::IdAlreadyExists),
466 Entry::Vacant(entry) => {
467 entry.insert(cap);
468 Ok(())
469 }
470 }
471}
472
473#[cfg(test)]
474mod tests {
475 use super::*;
476 use crate::Data;
477 use assert_matches::assert_matches;
478 use fidl::{endpoints, HandleBased};
479
480 #[fuchsia::test]
481 async fn import_export() {
482 let (store, stream) =
483 endpoints::create_proxy_and_stream::<fsandbox::CapabilityStoreMarker>();
484 let _server = fasync::Task::spawn(async move {
485 let receiver_scope = fasync::Scope::new();
486 serve_capability_store(stream, &receiver_scope).await
487 });
488
489 let (ch, _) = fidl::Channel::create();
490 let handle = ch.into_handle();
491 let handle_koid = handle.get_koid().unwrap();
492 let cap1 = Capability::Handle(handle.into());
493 let cap2 = Capability::Data(Data::Int64(42));
494 store.import(1, cap1.into()).await.unwrap().unwrap();
495 store.import(2, cap2.into()).await.unwrap().unwrap();
496
497 let cap1 = store.export(1).await.unwrap().unwrap();
498 let cap2 = store.export(2).await.unwrap().unwrap();
499 assert_matches!(
500 cap1,
501 fsandbox::Capability::Handle(h) if h.get_koid().unwrap() == handle_koid
502 );
503 assert_matches!(
504 cap2,
505 fsandbox::Capability::Data(fsandbox::Data::Int64(i)) if i == 42
506 );
507 }
508
509 #[fuchsia::test]
510 async fn import_error() {
511 let (store, stream) =
512 endpoints::create_proxy_and_stream::<fsandbox::CapabilityStoreMarker>();
513 let _server = fasync::Task::spawn(async move {
514 let receiver_scope = fasync::Scope::new();
515 serve_capability_store(stream, &receiver_scope).await
516 });
517
518 let cap1 = Capability::Data(Data::Int64(42));
519 store.import(1, cap1.try_clone().unwrap().into()).await.unwrap().unwrap();
520 assert_matches!(
521 store.import(1, cap1.into()).await.unwrap(),
522 Err(fsandbox::CapabilityStoreError::IdAlreadyExists)
523 );
524
525 let (token, _) = fidl::EventPair::create();
526 let bad_connector = fsandbox::Capability::Connector(fsandbox::Connector { token });
527 assert_matches!(
528 store.import(2, bad_connector).await.unwrap(),
529 Err(fsandbox::CapabilityStoreError::BadCapability)
530 );
531 }
532
533 #[fuchsia::test]
534 async fn export_error() {
535 let (store, stream) =
536 endpoints::create_proxy_and_stream::<fsandbox::CapabilityStoreMarker>();
537 let _server = fasync::Task::spawn(async move {
538 let receiver_scope = fasync::Scope::new();
539 serve_capability_store(stream, &receiver_scope).await
540 });
541
542 let cap1 = Capability::Data(Data::Int64(42));
543 store.import(1, cap1.try_clone().unwrap().into()).await.unwrap().unwrap();
544
545 assert_matches!(
546 store.export(2).await.unwrap(),
547 Err(fsandbox::CapabilityStoreError::IdNotFound)
548 );
549 }
550
551 #[fuchsia::test]
552 async fn drop() {
553 let (store, stream) =
554 endpoints::create_proxy_and_stream::<fsandbox::CapabilityStoreMarker>();
555 let _server = fasync::Task::spawn(async move {
556 let receiver_scope = fasync::Scope::new();
557 serve_capability_store(stream, &receiver_scope).await
558 });
559
560 let (ch, _) = fidl::Channel::create();
561 let handle = ch.into_handle();
562 let handle_koid = handle.get_koid().unwrap();
563 let cap1 = Capability::Handle(handle.into());
564 let cap2 = Capability::Data(Data::Int64(42));
565 store.import(1, cap1.into()).await.unwrap().unwrap();
566 store.import(2, cap2.into()).await.unwrap().unwrap();
567
568 store.drop(2).await.unwrap().unwrap();
570 assert_matches!(
571 store.export(1).await.unwrap(),
572 Ok(fsandbox::Capability::Handle(h)) if h.get_koid().unwrap() == handle_koid
573 );
574 assert_matches!(
575 store.export(2).await.unwrap(),
576 Err(fsandbox::CapabilityStoreError::IdNotFound)
577 );
578
579 let cap2 = Capability::Data(Data::Int64(84));
581 store.import(2, cap2.into()).await.unwrap().unwrap();
582 assert_matches!(
583 store.export(2).await.unwrap(),
584 Ok(fsandbox::Capability::Data(fsandbox::Data::Int64(i))) if i == 84
585 );
586 }
587
588 #[fuchsia::test]
589 async fn drop_error() {
590 let (store, stream) =
591 endpoints::create_proxy_and_stream::<fsandbox::CapabilityStoreMarker>();
592 let _server = fasync::Task::spawn(async move {
593 let receiver_scope = fasync::Scope::new();
594 serve_capability_store(stream, &receiver_scope).await
595 });
596
597 let cap1 = Capability::Data(Data::Int64(42));
598 store.import(1, cap1.into()).await.unwrap().unwrap();
599
600 assert_matches!(
601 store.drop(2).await.unwrap(),
602 Err(fsandbox::CapabilityStoreError::IdNotFound)
603 );
604 }
605
606 #[fuchsia::test]
607 async fn duplicate() {
608 let (store, stream) =
609 endpoints::create_proxy_and_stream::<fsandbox::CapabilityStoreMarker>();
610 let _server = fasync::Task::spawn(async move {
611 let receiver_scope = fasync::Scope::new();
612 serve_capability_store(stream, &receiver_scope).await
613 });
614
615 let (event, _) = fidl::EventPair::create();
616 let handle = event.into_handle();
617 let handle_koid = handle.get_koid().unwrap();
618 let cap1 = Capability::Handle(handle.into());
619 store.import(1, cap1.into()).await.unwrap().unwrap();
620 store.duplicate(1, 2).await.unwrap().unwrap();
621 store.drop(1).await.unwrap().unwrap();
622
623 let cap1 = store.export(2).await.unwrap().unwrap();
624 assert_matches!(
625 cap1,
626 fsandbox::Capability::Handle(h) if h.get_koid().unwrap() == handle_koid
627 );
628 }
629
630 #[fuchsia::test]
631 async fn duplicate_error() {
632 let (store, stream) =
633 endpoints::create_proxy_and_stream::<fsandbox::CapabilityStoreMarker>();
634 let _server = fasync::Task::spawn(async move {
635 let receiver_scope = fasync::Scope::new();
636 serve_capability_store(stream, &receiver_scope).await
637 });
638
639 assert_matches!(
640 store.duplicate(1, 2).await.unwrap(),
641 Err(fsandbox::CapabilityStoreError::IdNotFound)
642 );
643
644 let cap1 = Capability::Data(Data::Int64(42));
645 let cap2 = Capability::Data(Data::Int64(84));
646 store.import(1, cap1.into()).await.unwrap().unwrap();
647 store.import(2, cap2.into()).await.unwrap().unwrap();
648 assert_matches!(
649 store.duplicate(1, 2).await.unwrap(),
650 Err(fsandbox::CapabilityStoreError::IdAlreadyExists)
651 );
652
653 let (ch, _) = fidl::Channel::create();
655 let handle = ch.into_handle();
656 let cap1 = Capability::Handle(handle.into());
657 store.import(3, cap1.into()).await.unwrap().unwrap();
658 assert_matches!(
659 store.duplicate(3, 4).await.unwrap(),
660 Err(fsandbox::CapabilityStoreError::NotDuplicatable)
661 );
662 }
663}