kernel: Allow dropping capabilities for dead domains
b15c0ef266f1da250c3dc0485b79dc58082a8eee8946b7687337a1a111366662
1 parent
f5d37a5e
kernel/kernel/calls.rad
+0 -1
| 112 | 112 | let number = try interrupts::query(&interrupts::STORE, table, handle); |
|
| 113 | 113 | plic::mask(number); |
|
| 114 | 114 | try! interrupts::drop(&mut interrupts::STORE, table, handle); |
|
| 115 | 115 | }, |
|
| 116 | 116 | else => { |
|
| 117 | - | try resident(entry); |
|
| 118 | 117 | let removed = try! capability::invalidate(table, handle); |
|
| 119 | 118 | }, |
|
| 120 | 119 | } |
|
| 121 | 120 | } |
|
| 122 | 121 |
kernel/kernel/tests/calls.rad
+27 -1
| 35 | 35 | set domains::STORE.contextSlots[object.index] = slots::Slot { generation: object.generation, state: slots::State::Live }; |
|
| 36 | 36 | set domains::STORE.contexts[object.index].owner = object; |
|
| 37 | 37 | set domains::STORE.contexts[object.index].state = domains::ContextState::Stopped; |
|
| 38 | 38 | set domains::STORE.contexts[object.index].hart = nil; |
|
| 39 | 39 | set domains::STORE.contexts[object.index].userStack = { start: 0, end: 0 }; |
|
| 40 | - | for operation in [47 as u64, 48, 62, 10, 12, 21, 61, 20, 30, 51] { |
|
| 40 | + | for operation in [47 as u64, 48, 62, 10, 21, 61, 20, 30, 51] { |
|
| 41 | 41 | let mut kind = abi::Kind::Domain; |
|
| 42 | 42 | if operation == 48 { set kind = abi::Kind::Events; } |
|
| 43 | 43 | let handle = try! capability::install(&mut MEMORY.table, capability::Entry { |
|
| 44 | 44 | kind: kind, object: object, |
|
| 45 | 45 | rights: abi::Rights(abi::GRANT | abi::EXECUTE | abi::DESTROY | abi::CREATE | abi::ALLOCATE), |
| 54 | 54 | assert rejected; |
|
| 55 | 55 | assert (try! capability::get(&MEMORY.table, handle)).object == object; |
|
| 56 | 56 | } |
|
| 57 | 57 | } |
|
| 58 | 58 | ||
| 59 | + | /// Dead and recycled domain references can be dropped without exhausting handles. |
|
| 60 | + | @test unsafe fn dropDeadHandles() throws (testing::TestError) { |
|
| 61 | + | let owner = initialize(); |
|
| 62 | + | for i in 0..limits::HANDLES + 1 { |
|
| 63 | + | let pending = try! slots::reserve(&mut domains::STORE.slots[..]); |
|
| 64 | + | let object = try! slots::commit(&mut domains::STORE.slots[..], pending); |
|
| 65 | + | set domains::STORE.records[object.index].state = domains::Lifecycle::Dead; |
|
| 66 | + | let handle = try! capability::install(&mut MEMORY.table, capability::Entry { |
|
| 67 | + | kind: abi::Kind::Domain, object, rights: abi::Rights(0), |
|
| 68 | + | }); |
|
| 69 | + | if i % 2 == 0 { try! slots::release(&mut domains::STORE.slots[..], object); } |
|
| 70 | + | assert try! calls::invoke(owner, 12, &[*handle, 0, 0, 0], 0) == 0; |
|
| 71 | + | let replacement = try! capability::install(&mut MEMORY.table, capability::Entry { |
|
| 72 | + | kind: abi::Kind::Domain, object: owner, rights: abi::Rights(0), |
|
| 73 | + | }); |
|
| 74 | + | assert (try! abi::decode(replacement)).object.index == (try! abi::decode(handle)).object.index; |
|
| 75 | + | let mut rejected = false; |
|
| 76 | + | try calls::invoke(owner, 12, &[*handle, 0, 0, 0], 0) catch error { |
|
| 77 | + | assert error == abi::Error::BadHandle; set rejected = true; |
|
| 78 | + | }; |
|
| 79 | + | assert rejected and (try! capability::get(&MEMORY.table, replacement)).object == owner; |
|
| 80 | + | assert try! calls::invoke(owner, 12, &[*replacement, 0, 0, 0], 0) == 0; |
|
| 81 | + | if i % 2 <> 0 { try! slots::release(&mut domains::STORE.slots[..], object); } |
|
| 82 | + | } |
|
| 83 | + | } |
|
| 84 | + | ||
| 59 | 85 | /// Administrative destruction checks authority and follows creation ancestry only on request. |
|
| 60 | 86 | @test unsafe fn administrativeTermination() throws (testing::TestError) { |
|
| 61 | 87 | for flags in [0 as u64, abi::CASCADE] { |
|
| 62 | 88 | let owner = initialize(); |
|
| 63 | 89 | try! events::open(&mut domains::STORE.events, owner, &mut MEMORY.ring); |