kernel: Allow dropping capabilities for dead domains

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