kernel: Allow dropping capabilities for dead domains
807886ea6a5721a8b4a107c4a44aa3d60451bd21545259e5c820a45ee45a4d0a
1 parent
bf3d3cc5
kernel/kernel/calls.rad
+0 -1
| 143 | 143 | let number = try interrupts::query(&interrupts::STORE, table, handle); |
|
| 144 | 144 | plic::mask(number); |
|
| 145 | 145 | try! interrupts::drop(&mut interrupts::STORE, table, handle); |
|
| 146 | 146 | }, |
|
| 147 | 147 | else => { |
|
| 148 | - | try resident(entry); |
|
| 149 | 148 | let removed = try! capability::invalidate(table, handle); |
|
| 150 | 149 | }, |
|
| 151 | 150 | } |
|
| 152 | 151 | } |
|
| 153 | 152 |
kernel/kernel/tests/calls.rad
+31 -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 { |
|
| 43 | 43 | set kind = abi::Kind::Events; |
|
| 44 | 44 | } |
|
| 45 | 45 | let handle = try! capability::install(&mut MEMORY.table, capability::Entry { |
| 58 | 58 | assert rejected; |
|
| 59 | 59 | assert (try! capability::get(&MEMORY.table, handle)).object == object; |
|
| 60 | 60 | } |
|
| 61 | 61 | } |
|
| 62 | 62 | ||
| 63 | + | /// Dead and recycled domain references can be dropped without exhausting handles. |
|
| 64 | + | @test unsafe fn dropDeadHandles() throws (testing::TestError) { |
|
| 65 | + | let owner = initialize(); |
|
| 66 | + | for i in 0..limits::HANDLES + 1 { |
|
| 67 | + | let pending = try! slots::reserve(&mut domains::STORE.slots[..]); |
|
| 68 | + | let object = try! slots::commit(&mut domains::STORE.slots[..], pending); |
|
| 69 | + | set domains::STORE.records[object.index].state = domains::Lifecycle::Dead; |
|
| 70 | + | let handle = try! capability::install(&mut MEMORY.table, capability::Entry { |
|
| 71 | + | kind: abi::Kind::Domain, object, rights: abi::Rights(0), |
|
| 72 | + | }); |
|
| 73 | + | if i % 2 == 0 { |
|
| 74 | + | try! slots::release(&mut domains::STORE.slots[..], object); |
|
| 75 | + | } |
|
| 76 | + | assert try! calls::invoke(owner, 12, &[*handle, 0, 0, 0], 0) == 0; |
|
| 77 | + | let replacement = try! capability::install(&mut MEMORY.table, capability::Entry { |
|
| 78 | + | kind: abi::Kind::Domain, object: owner, rights: abi::Rights(0), |
|
| 79 | + | }); |
|
| 80 | + | assert (try! abi::decode(replacement)).object.index == (try! abi::decode(handle)).object.index; |
|
| 81 | + | let mut rejected = false; |
|
| 82 | + | try calls::invoke(owner, 12, &[*handle, 0, 0, 0], 0) catch error { |
|
| 83 | + | assert error == abi::Error::BadHandle; set rejected = true; |
|
| 84 | + | }; |
|
| 85 | + | assert rejected and (try! capability::get(&MEMORY.table, replacement)).object == owner; |
|
| 86 | + | assert try! calls::invoke(owner, 12, &[*replacement, 0, 0, 0], 0) == 0; |
|
| 87 | + | if i % 2 <> 0 { |
|
| 88 | + | try! slots::release(&mut domains::STORE.slots[..], object); |
|
| 89 | + | } |
|
| 90 | + | } |
|
| 91 | + | } |
|
| 92 | + | ||
| 63 | 93 | /// Administrative destruction checks authority and follows creation ancestry only on request. |
|
| 64 | 94 | @test unsafe fn administrativeTermination() throws (testing::TestError) { |
|
| 65 | 95 | for flags in [0 as u64, abi::CASCADE] { |
|
| 66 | 96 | let owner = initialize(); |
|
| 67 | 97 | try! events::open(&mut domains::STORE.events, owner, &mut MEMORY.ring); |