redo boot around an explicit system volume and fixed kernel/HAL images, redo volumes and filesystem paths around capabilities instead of drive numbers and kernel CWD state, add a capability/security model with derived and revocable handles and security contexts, add port IPC and rssrv to manage the userspace resource namespace and publish the system volume, move process, dll and path loading to userspace and add process builder syscalls, init now supervises rssrv and the session process, redo the syscall ABI around request structs and four arguments, add a volume manager and proper partition arrival/removal handling so FAT and NTFS mount dynamically, clean up the HAL/DDK boundary so drivers don't depend on HAL internals, save fpu state properly now, the serial driver doesn't hang on a missing port, fix AHCI startup races, fix timeout accounting, fix shared mmap writeback, more smoke tests
This commit is contained in:
1 parent
4add6789ba
commit
f882d339fb
232 files changed
+20934
-8898
No files matched your search
@@ -1,10 +1,14 @@
|
||||
// Native handle duplication smoke test.
|
||||
// Verifies explicit rights reduction, same-rights duplication, and invalid duplicate requests.
|
||||
// Native capability-handle smoke test.
|
||||
// Verifies monotonic identities, typed rights, derivation, aliasing, and revocation.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <ntlite/syscall.h>
|
||||
|
||||
#define EVENT_AUTO_RESET 0u
|
||||
#define HANDLE_STRESS_COUNT 512u
|
||||
#define DERIVATION_SUCCESS_COUNT 15u
|
||||
|
||||
typedef struct TEST_QUEUE_MESSAGE {
|
||||
uint32_t Type;
|
||||
uint32_t Flags;
|
||||
@@ -17,7 +21,7 @@ typedef char TEST_QUEUE_MESSAGE_SIZE_CHECK[
|
||||
|
||||
// Prints one NUL-terminated string to the kernel console.
|
||||
static void print(const char* s) {
|
||||
SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromCstr(s) };
|
||||
SYS_WRITE_CONSOLE_REQUEST req = { sizeof(SYS_WRITE_CONSOLE_REQUEST), SysSvFromCstr(s) };
|
||||
SysWriteConsole(&req);
|
||||
}
|
||||
|
||||
@@ -35,7 +39,7 @@ static void print_u64(uint64_t v) {
|
||||
}
|
||||
while (i--) {
|
||||
char c = buf[i];
|
||||
SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromParts(&c, 1) };
|
||||
SYS_WRITE_CONSOLE_REQUEST req = { sizeof(SYS_WRITE_CONSOLE_REQUEST), SysSvFromParts(&c, 1) };
|
||||
SysWriteConsole(&req);
|
||||
}
|
||||
}
|
||||
@@ -54,7 +58,7 @@ static void fail(const char* msg) {
|
||||
}
|
||||
|
||||
// Fails the test with one status value.
|
||||
static void fail_status(const char* what, uint32_t status) {
|
||||
static void fail_status(const char* what, KSTATUS status) {
|
||||
print("handle_dup_smoke: ");
|
||||
print(what);
|
||||
print(" status=");
|
||||
@@ -64,7 +68,7 @@ static void fail_status(const char* what, uint32_t status) {
|
||||
}
|
||||
|
||||
// Requires one exact status value.
|
||||
static void expect_status(const char* what, uint32_t got, uint32_t expected) {
|
||||
static void expect_status(const char* what, KSTATUS got, KSTATUS expected) {
|
||||
if (got == expected) return;
|
||||
print("handle_dup_smoke: ");
|
||||
print(what);
|
||||
@@ -77,8 +81,13 @@ static void expect_status(const char* what, uint32_t got, uint32_t expected) {
|
||||
}
|
||||
|
||||
// Duplicates one handle into the current process.
|
||||
static uint32_t duplicate_handle(uint32_t source, uint32_t process, uint32_t desiredRights, uint32_t flags, uint32_t* out) {
|
||||
static KSTATUS duplicate_handle(SYS_HANDLE source,
|
||||
SYS_HANDLE process,
|
||||
SYS_RIGHTS desiredRights,
|
||||
uint32_t flags,
|
||||
SYS_HANDLE* out) {
|
||||
SYS_DUPLICATE_HANDLE_REQUEST req = {
|
||||
sizeof(SYS_DUPLICATE_HANDLE_REQUEST),
|
||||
source,
|
||||
process,
|
||||
desiredRights,
|
||||
@@ -88,8 +97,19 @@ static uint32_t duplicate_handle(uint32_t source, uint32_t process, uint32_t des
|
||||
return SysDuplicateHandle(&req);
|
||||
}
|
||||
|
||||
// Derives one child capability in the current process.
|
||||
static KSTATUS derive_handle(SYS_HANDLE source, SYS_RIGHTS desiredRights, SYS_HANDLE* out) {
|
||||
SYS_DERIVE_HANDLE_REQUEST req = {
|
||||
sizeof(SYS_DERIVE_HANDLE_REQUEST),
|
||||
source,
|
||||
desiredRights,
|
||||
out,
|
||||
};
|
||||
return SysDeriveHandle(&req);
|
||||
}
|
||||
|
||||
// Sends one queue message.
|
||||
static uint32_t send_message(uint32_t queue, uint32_t type, uint64_t value) {
|
||||
static KSTATUS send_message(SYS_HANDLE queue, uint32_t type, uint64_t value) {
|
||||
TEST_QUEUE_MESSAGE msg = {0};
|
||||
msg.Type = type;
|
||||
msg.Param[0] = value;
|
||||
@@ -104,7 +124,7 @@ static uint32_t send_message(uint32_t queue, uint32_t type, uint64_t value) {
|
||||
}
|
||||
|
||||
// Receives one queue message.
|
||||
static uint32_t recv_message(uint32_t queue, TEST_QUEUE_MESSAGE* msg) {
|
||||
static KSTATUS recv_message(SYS_HANDLE queue, TEST_QUEUE_MESSAGE* msg) {
|
||||
SYS_QUEUE_RECV_REQUEST req = {
|
||||
sizeof(req),
|
||||
queue,
|
||||
@@ -120,84 +140,244 @@ static void check_message(const TEST_QUEUE_MESSAGE* msg, uint32_t type, uint64_t
|
||||
if (msg->Type != type || msg->Param[0] != value) fail("message payload mismatch");
|
||||
}
|
||||
|
||||
// Runs the native handle duplication smoke test.
|
||||
int main(void) {
|
||||
print("handle_dup_smoke: start\n");
|
||||
// Closes one handle and requires success.
|
||||
static void close_handle(const char* what, SYS_HANDLE handle) {
|
||||
KSTATUS status = SysCloseHandle(handle);
|
||||
if (!KSUCCESS(status)) fail_status(what, status);
|
||||
}
|
||||
|
||||
uint32_t currentPid = SysGetCurrentPid();
|
||||
uint32_t process = 0;
|
||||
uint32_t s = SysOpenProcess(currentPid, &process);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("open current process", s);
|
||||
// Verifies that closed identities are not reused and stale values stay invalid.
|
||||
static void test_monotonic_identity(void) {
|
||||
SYS_HANDLE first = SYS_HANDLE_INVALID;
|
||||
KSTATUS status = SysCreateEvent(EVENT_AUTO_RESET, 0, &first);
|
||||
if (!KSUCCESS(status)) fail_status("create first monotonic event", status);
|
||||
close_handle("close first monotonic event", first);
|
||||
|
||||
uint32_t queue = 0;
|
||||
s = SysCreateQueue(&queue);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("create queue", s);
|
||||
SYS_HANDLE second = SYS_HANDLE_INVALID;
|
||||
status = SysCreateEvent(EVENT_AUTO_RESET, 0, &second);
|
||||
if (!KSUCCESS(status)) fail_status("create second monotonic event", status);
|
||||
if (second <= first) fail("handle identity was reused or moved backwards");
|
||||
|
||||
uint32_t readOnly = 0;
|
||||
s = duplicate_handle(queue, process, SYS_HANDLE_RIGHT_READ, SYS_DUPLICATE_HANDLE_FLAG_NONE, &readOnly);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("duplicate read-only", s);
|
||||
expect_status("close stale handle", SysCloseHandle(first), NTLSTATUS_INVALID_HANDLE);
|
||||
close_handle("close second monotonic event", second);
|
||||
}
|
||||
|
||||
uint32_t writeOnly = 0;
|
||||
s = duplicate_handle(queue, process, SYS_HANDLE_RIGHT_WRITE, SYS_DUPLICATE_HANDLE_FLAG_NONE, &writeOnly);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("duplicate write-only", s);
|
||||
// Verifies that live-handle capacity is no longer tied to the old 256-slot table.
|
||||
static void test_dynamic_handle_capacity(void) {
|
||||
SYS_HANDLE handles[HANDLE_STRESS_COUNT];
|
||||
SYS_HANDLE previous = SYS_HANDLE_INVALID;
|
||||
|
||||
uint32_t sameRights = 0;
|
||||
s = duplicate_handle(queue, process, 0, SYS_DUPLICATE_HANDLE_FLAG_SAME_RIGHTS, &sameRights);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("duplicate same rights", s);
|
||||
for (uint32_t i = 0; i < HANDLE_STRESS_COUNT; ++i) {
|
||||
handles[i] = SYS_HANDLE_INVALID;
|
||||
KSTATUS status = SysCreateEvent(EVENT_AUTO_RESET, 0, &handles[i]);
|
||||
if (!KSUCCESS(status)) fail_status("create stress event", status);
|
||||
if (previous != SYS_HANDLE_INVALID && handles[i] <= previous)
|
||||
fail("stress handles were not strictly monotonic");
|
||||
previous = handles[i];
|
||||
}
|
||||
|
||||
s = send_message(readOnly, 10, 100);
|
||||
if (s == NTLSTATUS_SUCCESS) fail("read-only duplicate allowed send");
|
||||
for (uint32_t i = HANDLE_STRESS_COUNT; i != 0; --i)
|
||||
close_handle("close stress event", handles[i - 1]);
|
||||
}
|
||||
|
||||
// Verifies explicit rights attenuation on duplicate aliases.
|
||||
static void test_duplicate_rights(SYS_HANDLE process, SYS_HANDLE queue,
|
||||
SYS_HANDLE* sameRightsOut,
|
||||
SYS_HANDLE* receiveOnlyOut,
|
||||
SYS_HANDLE* sendOnlyOut) {
|
||||
SYS_HANDLE receiveOnly = SYS_HANDLE_INVALID;
|
||||
KSTATUS status = duplicate_handle(queue, process, SYS_QUEUE_RIGHT_RECEIVE,
|
||||
SYS_DUPLICATE_HANDLE_FLAG_NONE, &receiveOnly);
|
||||
if (!KSUCCESS(status)) fail_status("duplicate receive-only", status);
|
||||
|
||||
SYS_HANDLE sendOnly = SYS_HANDLE_INVALID;
|
||||
status = duplicate_handle(queue, process, SYS_QUEUE_RIGHT_SEND,
|
||||
SYS_DUPLICATE_HANDLE_FLAG_NONE, &sendOnly);
|
||||
if (!KSUCCESS(status)) fail_status("duplicate send-only", status);
|
||||
|
||||
SYS_HANDLE sameRights = SYS_HANDLE_INVALID;
|
||||
status = duplicate_handle(queue, process, 0,
|
||||
SYS_DUPLICATE_HANDLE_FLAG_SAME_RIGHTS, &sameRights);
|
||||
if (!KSUCCESS(status)) fail_status("duplicate same rights", status);
|
||||
|
||||
status = send_message(receiveOnly, 10, 100);
|
||||
expect_status("receive-only send denied", status, NTLSTATUS_ACCESS_DENIED);
|
||||
|
||||
TEST_QUEUE_MESSAGE msg;
|
||||
s = recv_message(writeOnly, &msg);
|
||||
if (s == NTLSTATUS_SUCCESS) fail("write-only duplicate allowed receive");
|
||||
status = recv_message(sendOnly, &msg);
|
||||
expect_status("send-only receive denied", status, NTLSTATUS_ACCESS_DENIED);
|
||||
|
||||
s = send_message(queue, 11, 101);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("send original", s);
|
||||
s = recv_message(readOnly, &msg);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("receive read-only", s);
|
||||
status = send_message(queue, 11, 101);
|
||||
if (!KSUCCESS(status)) fail_status("send original", status);
|
||||
status = recv_message(receiveOnly, &msg);
|
||||
if (!KSUCCESS(status)) fail_status("receive receive-only", status);
|
||||
check_message(&msg, 11, 101);
|
||||
|
||||
s = send_message(writeOnly, 12, 102);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("send write-only", s);
|
||||
s = recv_message(queue, &msg);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("receive original", s);
|
||||
status = send_message(sendOnly, 12, 102);
|
||||
if (!KSUCCESS(status)) fail_status("send send-only", status);
|
||||
status = recv_message(queue, &msg);
|
||||
if (!KSUCCESS(status)) fail_status("receive original", status);
|
||||
check_message(&msg, 12, 102);
|
||||
|
||||
s = send_message(sameRights, 13, 103);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("send same-rights", s);
|
||||
s = recv_message(sameRights, &msg);
|
||||
if (s != NTLSTATUS_SUCCESS) fail_status("receive same-rights", s);
|
||||
status = send_message(sameRights, 13, 103);
|
||||
if (!KSUCCESS(status)) fail_status("send same-rights", status);
|
||||
status = recv_message(sameRights, &msg);
|
||||
if (!KSUCCESS(status)) fail_status("receive same-rights", status);
|
||||
check_message(&msg, 13, 103);
|
||||
|
||||
uint32_t ignored = 0;
|
||||
s = duplicate_handle(readOnly, process, SYS_HANDLE_RIGHT_READ, SYS_DUPLICATE_HANDLE_FLAG_NONE, &ignored);
|
||||
expect_status("duplicate non-duplicable handle", s, NTLSTATUS_ACCESS_DENIED);
|
||||
SYS_HANDLE ignored = SYS_HANDLE_INVALID;
|
||||
status = duplicate_handle(receiveOnly, process, SYS_QUEUE_RIGHT_RECEIVE,
|
||||
SYS_DUPLICATE_HANDLE_FLAG_NONE, &ignored);
|
||||
expect_status("duplicate non-duplicable handle", status, NTLSTATUS_ACCESS_DENIED);
|
||||
|
||||
s = duplicate_handle(queue, process, SYS_HANDLE_RIGHT_READ | 0x80000000u, SYS_DUPLICATE_HANDLE_FLAG_NONE, &ignored);
|
||||
expect_status("duplicate unknown rights", s, NTLSTATUS_INVALID_PARAMETER);
|
||||
status = duplicate_handle(queue, process, SYS_QUEUE_RIGHT_RECEIVE | 0x80000000u,
|
||||
SYS_DUPLICATE_HANDLE_FLAG_NONE, &ignored);
|
||||
expect_status("duplicate unknown rights", status, NTLSTATUS_INVALID_PARAMETER);
|
||||
|
||||
s = duplicate_handle(queue, process, SYS_HANDLE_RIGHT_READ, SYS_DUPLICATE_HANDLE_FLAG_SAME_RIGHTS, &ignored);
|
||||
expect_status("duplicate same-rights with desired rights", s, NTLSTATUS_INVALID_PARAMETER);
|
||||
status = duplicate_handle(queue, process, SYS_QUEUE_RIGHT_RECEIVE,
|
||||
SYS_DUPLICATE_HANDLE_FLAG_SAME_RIGHTS, &ignored);
|
||||
expect_status("duplicate same-rights with desired rights", status, NTLSTATUS_INVALID_PARAMETER);
|
||||
|
||||
s = duplicate_handle(queue, process, 0, SYS_DUPLICATE_HANDLE_FLAG_NONE, &ignored);
|
||||
expect_status("duplicate zero rights", s, NTLSTATUS_INVALID_PARAMETER);
|
||||
status = duplicate_handle(queue, process, 0, SYS_DUPLICATE_HANDLE_FLAG_NONE, &ignored);
|
||||
expect_status("duplicate zero rights", status, NTLSTATUS_INVALID_PARAMETER);
|
||||
|
||||
SYS_DUPLICATE_HANDLE_REQUEST badOut = {
|
||||
sizeof(SYS_DUPLICATE_HANDLE_REQUEST),
|
||||
queue,
|
||||
process,
|
||||
SYS_HANDLE_RIGHT_READ,
|
||||
SYS_QUEUE_RIGHT_RECEIVE,
|
||||
SYS_DUPLICATE_HANDLE_FLAG_NONE,
|
||||
0,
|
||||
};
|
||||
s = SysDuplicateHandle(&badOut);
|
||||
expect_status("duplicate null output", s, NTLSTATUS_INVALID_PARAMETER);
|
||||
status = SysDuplicateHandle(&badOut);
|
||||
expect_status("duplicate null output", status, NTLSTATUS_INVALID_PARAMETER);
|
||||
|
||||
SysCloseHandle(sameRights);
|
||||
SysCloseHandle(writeOnly);
|
||||
SysCloseHandle(readOnly);
|
||||
SysCloseHandle(queue);
|
||||
SysCloseHandle(process);
|
||||
*sameRightsOut = sameRights;
|
||||
*receiveOnlyOut = receiveOnly;
|
||||
*sendOnlyOut = sendOnly;
|
||||
}
|
||||
|
||||
// Verifies child grants attenuate authority and can be revoked independently.
|
||||
static void test_derived_revocation(SYS_HANDLE process, SYS_HANDLE queue) {
|
||||
const SYS_RIGHTS childRights = SYS_QUEUE_RIGHT_RECEIVE |
|
||||
SYS_RIGHT_DUPLICATE |
|
||||
SYS_RIGHT_DERIVE |
|
||||
SYS_RIGHT_REVOKE;
|
||||
|
||||
SYS_HANDLE child = SYS_HANDLE_INVALID;
|
||||
KSTATUS status = derive_handle(queue, childRights, &child);
|
||||
if (!KSUCCESS(status)) fail_status("derive child", status);
|
||||
|
||||
SYS_HANDLE childAlias = SYS_HANDLE_INVALID;
|
||||
status = duplicate_handle(child, process, 0,
|
||||
SYS_DUPLICATE_HANDLE_FLAG_SAME_RIGHTS, &childAlias);
|
||||
if (!KSUCCESS(status)) fail_status("duplicate child alias", status);
|
||||
|
||||
SYS_HANDLE grandchild = SYS_HANDLE_INVALID;
|
||||
status = derive_handle(child, SYS_QUEUE_RIGHT_RECEIVE, &grandchild);
|
||||
if (!KSUCCESS(status)) fail_status("derive grandchild", status);
|
||||
|
||||
SYS_HANDLE ignored = SYS_HANDLE_INVALID;
|
||||
status = derive_handle(child, SYS_QUEUE_RIGHT_SEND, &ignored);
|
||||
expect_status("derive cannot amplify rights", status, NTLSTATUS_ACCESS_DENIED);
|
||||
|
||||
status = SysRevokeHandle(grandchild);
|
||||
expect_status("revoke without revoke right", status, NTLSTATUS_ACCESS_DENIED);
|
||||
|
||||
TEST_QUEUE_MESSAGE msg;
|
||||
status = send_message(queue, 20, 200);
|
||||
if (!KSUCCESS(status)) fail_status("send for grandchild", status);
|
||||
status = recv_message(grandchild, &msg);
|
||||
if (!KSUCCESS(status)) fail_status("receive grandchild", status);
|
||||
check_message(&msg, 20, 200);
|
||||
|
||||
status = SysRevokeHandle(child);
|
||||
if (!KSUCCESS(status)) fail_status("revoke child", status);
|
||||
|
||||
ignored = SYS_HANDLE_INVALID;
|
||||
status = duplicate_handle(childAlias, process, 0,
|
||||
SYS_DUPLICATE_HANDLE_FLAG_SAME_RIGHTS, &ignored);
|
||||
expect_status("duplicate revoked alias", status, NTLSTATUS_CAPABILITY_REVOKED);
|
||||
|
||||
status = derive_handle(childAlias, SYS_QUEUE_RIGHT_RECEIVE, &ignored);
|
||||
expect_status("derive revoked alias", status, NTLSTATUS_CAPABILITY_REVOKED);
|
||||
|
||||
status = recv_message(grandchild, &msg);
|
||||
expect_status("revoked grandchild receive", status, NTLSTATUS_CAPABILITY_REVOKED);
|
||||
|
||||
// Revoking a derived grant must not revoke its parent grant.
|
||||
status = send_message(queue, 21, 201);
|
||||
if (!KSUCCESS(status)) fail_status("parent send after child revoke", status);
|
||||
status = recv_message(queue, &msg);
|
||||
if (!KSUCCESS(status)) fail_status("parent receive after child revoke", status);
|
||||
check_message(&msg, 21, 201);
|
||||
|
||||
close_handle("close grandchild", grandchild);
|
||||
close_handle("close child alias", childAlias);
|
||||
close_handle("close child", child);
|
||||
}
|
||||
|
||||
// Verifies the bounded derivation chain used for revocation traversal.
|
||||
static void test_derivation_depth(SYS_HANDLE queue) {
|
||||
const SYS_RIGHTS rights = SYS_QUEUE_RIGHT_RECEIVE |
|
||||
SYS_RIGHT_DERIVE |
|
||||
SYS_RIGHT_REVOKE;
|
||||
SYS_HANDLE chain[DERIVATION_SUCCESS_COUNT];
|
||||
SYS_HANDLE parent = queue;
|
||||
|
||||
for (uint32_t i = 0; i < DERIVATION_SUCCESS_COUNT; ++i) {
|
||||
chain[i] = SYS_HANDLE_INVALID;
|
||||
KSTATUS status = derive_handle(parent, rights, &chain[i]);
|
||||
if (!KSUCCESS(status)) fail_status("derive bounded chain", status);
|
||||
parent = chain[i];
|
||||
}
|
||||
|
||||
SYS_HANDLE tooDeep = SYS_HANDLE_INVALID;
|
||||
KSTATUS status = derive_handle(parent, rights, &tooDeep);
|
||||
expect_status("derive beyond depth bound", status, NTLSTATUS_LIMIT_REACHED);
|
||||
|
||||
for (uint32_t i = DERIVATION_SUCCESS_COUNT; i != 0; --i)
|
||||
close_handle("close bounded derivation", chain[i - 1]);
|
||||
}
|
||||
|
||||
// Runs the native capability-handle smoke test.
|
||||
int main(void) {
|
||||
print("handle_dup_smoke: start\n");
|
||||
|
||||
test_monotonic_identity();
|
||||
test_dynamic_handle_capacity();
|
||||
|
||||
uint32_t currentPid = SysGetCurrentPid();
|
||||
SYS_HANDLE process = SYS_HANDLE_INVALID;
|
||||
KSTATUS status = SysOpenProcess(currentPid, SYS_PROCESS_RIGHT_INSERT_HANDLE | SYS_RIGHT_QUERY, &process);
|
||||
if (!KSUCCESS(status)) fail_status("open current process", status);
|
||||
|
||||
SYS_HANDLE queue = SYS_HANDLE_INVALID;
|
||||
status = SysCreateQueue(&queue);
|
||||
if (!KSUCCESS(status)) fail_status("create queue", status);
|
||||
|
||||
SYS_HANDLE sameRights = SYS_HANDLE_INVALID;
|
||||
SYS_HANDLE receiveOnly = SYS_HANDLE_INVALID;
|
||||
SYS_HANDLE sendOnly = SYS_HANDLE_INVALID;
|
||||
test_duplicate_rights(process, queue, &sameRights, &receiveOnly, &sendOnly);
|
||||
test_derived_revocation(process, queue);
|
||||
test_derivation_depth(queue);
|
||||
|
||||
// A duplicate is an alias of the same grant, so revocation through either
|
||||
// alias revokes the original grant as well.
|
||||
status = SysRevokeHandle(sameRights);
|
||||
if (!KSUCCESS(status)) fail_status("revoke duplicate alias", status);
|
||||
|
||||
SYS_HANDLE ignored = SYS_HANDLE_INVALID;
|
||||
status = duplicate_handle(queue, process, 0,
|
||||
SYS_DUPLICATE_HANDLE_FLAG_SAME_RIGHTS, &ignored);
|
||||
expect_status("duplicate root after alias revoke", status, NTLSTATUS_CAPABILITY_REVOKED);
|
||||
|
||||
close_handle("close same-rights", sameRights);
|
||||
close_handle("close send-only", sendOnly);
|
||||
close_handle("close receive-only", receiveOnly);
|
||||
close_handle("close revoked queue", queue);
|
||||
close_handle("close process", process);
|
||||
|
||||
print("handle_dup_smoke: PASS\n");
|
||||
exit_now(0);
|
||||
|
||||
Reference in new issue
Block a user