kernel: Allow dropping capabilities for dead domains

807886ea6a5721a8b4a107c4a44aa3d60451bd21545259e5c820a45ee45a4d0a
Alexis Sellier committed ago 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);