From c42f32722447cc52810b25decee634210f09d70e Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Wed, 27 Oct 2021 22:34:41 -0700 Subject: fixes #1346 windows ipc winsec fails frequently in CI/CD --- src/platform/windows/CMakeLists.txt | 5 +- src/platform/windows/win_ipc_sec_test.c | 190 ++++++++++++++++++++++++++++++++ src/platform/windows/win_thread.c | 3 +- 3 files changed, 196 insertions(+), 2 deletions(-) create mode 100644 src/platform/windows/win_ipc_sec_test.c (limited to 'src/platform/windows') diff --git a/src/platform/windows/CMakeLists.txt b/src/platform/windows/CMakeLists.txt index 174e77f8..d1d158e0 100644 --- a/src/platform/windows/CMakeLists.txt +++ b/src/platform/windows/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2020 Staysail Systems, Inc. +# Copyright 2021 Staysail Systems, Inc. # # This software is supplied under the terms of the MIT License, a # copy of which should be located in the distribution where this @@ -46,4 +46,7 @@ if (NNG_PLATFORM_WINDOWS) win_thread.c win_udp.c ) + + nng_test(win_ipc_sec_test) + endif () \ No newline at end of file diff --git a/src/platform/windows/win_ipc_sec_test.c b/src/platform/windows/win_ipc_sec_test.c new file mode 100644 index 00000000..ab65533b --- /dev/null +++ b/src/platform/windows/win_ipc_sec_test.c @@ -0,0 +1,190 @@ +// +// Copyright 2021 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +#include +#include + +// Microsoft prefers CamelCase header names, but relies on case-insensitive +// file systems to make that work. The rest of the world (min-gw64 included) +// uses case-sensitive names and lowercase. + +#include +#include + +SECURITY_DESCRIPTOR * +sdescAuthUsers(PSID sid, PACL *aclp) +{ + SECURITY_DESCRIPTOR *sdesc; + EXPLICIT_ACCESS xa; + ACL *acl; + + sdesc = calloc(SECURITY_DESCRIPTOR_MIN_LENGTH, 1); + NUTS_ASSERT(sdesc != NULL); + + InitializeSecurityDescriptor(sdesc, SECURITY_DESCRIPTOR_REVISION); + + xa.grfAccessPermissions = GENERIC_READ | GENERIC_WRITE; + xa.grfAccessMode = SET_ACCESS; + xa.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT; + xa.Trustee.TrusteeForm = TRUSTEE_IS_SID; + xa.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; + xa.Trustee.ptstrName = (LPSTR) sid; + + SetEntriesInAcl(1, &xa, NULL, &acl); + *aclp = acl; + + SetSecurityDescriptorDacl(sdesc, TRUE, acl, FALSE); + return (sdesc); +} + +void +test_ipc_security_descriptor(void) +{ + nng_stream_listener *l; + char address[64]; + char pipe[64]; + SECURITY_DESCRIPTOR *sd; + SID users; + DWORD size; + PACL acl = NULL; + PACL dacl; + PSECURITY_DESCRIPTOR psd; + PACE_HEADER ace; + PSID psid; + PACCESS_ALLOWED_ACE allowed; + nng_aio *aio; + + nuts_scratch_addr("ipc", sizeof(address), address); + + NUTS_PASS(nng_stream_listener_alloc(&l, address)); + size = sizeof(users); + CreateWellKnownSid(WinAuthenticatedUserSid, NULL, &users, &size); + sd = sdescAuthUsers(&users, &acl); + + NUTS_ASSERT(sd != NULL); + NUTS_ASSERT(acl != NULL); + NUTS_PASS(nng_aio_alloc(&aio, NULL, NULL)); + + NUTS_PASS(nng_stream_listener_set_ptr( + l, NNG_OPT_IPC_SECURITY_DESCRIPTOR, sd)); + NUTS_PASS(nng_stream_listener_listen(l)); + nng_stream_listener_accept(l, aio); + + (void) snprintf(pipe, sizeof(pipe), "\\\\.\\pipe\\%s", address+strlen("ipc://")); + HANDLE ph = CreateFileA(pipe, READ_CONTROL, 0, NULL, OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, NULL); + + nng_aio_wait(aio); + NUTS_PASS(nng_aio_result(aio)); + HANDLE pd = (HANDLE) nng_aio_get_output(aio, 0); + + NUTS_ASSERT(ph != INVALID_HANDLE_VALUE); + NUTS_ASSERT(pd != INVALID_HANDLE_VALUE); + + NUTS_ASSERT( + GetSecurityInfo(ph, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, + NULL, NULL, &dacl, NULL, &psd) == ERROR_SUCCESS); + + NUTS_ASSERT(dacl->AceCount == 1); + NUTS_ASSERT(GetAce(dacl, 0, (void **) &ace) == TRUE); + allowed = (PACCESS_ALLOWED_ACE) ace; + psid = (PSID) &allowed->SidStart; + NUTS_ASSERT(IsValidSid(psid)); + NUTS_ASSERT(EqualSid(psid, &users) == TRUE); + + CloseHandle(pd); + CloseHandle(ph); + free(sd); + LocalFree(acl); + LocalFree(psd); + nng_stream_listener_close(l); + nng_stream_listener_free(l); +} + +void +test_ipc_security_descriptor_busy(void) +{ + // This test ensures that the descriptor can only be set before + // the listener is started. + nng_stream_listener *l; + char address[64]; + SECURITY_DESCRIPTOR *sd; + SID users; + DWORD size; + PACL acl = NULL; + + nuts_scratch_addr("ipc", sizeof(address), address); + + NUTS_PASS(nng_stream_listener_alloc(&l, address)); + size = sizeof(users); + CreateWellKnownSid(WinAuthenticatedUserSid, NULL, &users, &size); + sd = sdescAuthUsers(&users, &acl); + + NUTS_ASSERT(sd != NULL); + NUTS_ASSERT(acl != NULL); + + NUTS_PASS(nng_stream_listener_listen(l)); + + NUTS_FAIL(nng_stream_listener_set_ptr( + l, NNG_OPT_IPC_SECURITY_DESCRIPTOR, sd), + NNG_EBUSY); + + free(sd); + nng_stream_listener_close(l); + nng_stream_listener_free(l); +} + +void +test_ipc_security_descriptor_bogus(void) +{ + nng_stream_listener *l; + char address[64]; + + nuts_scratch_addr("ipc", sizeof(address), address); + + NUTS_PASS(nng_stream_listener_alloc(&l, address)); + + NUTS_FAIL(nng_stream_listener_set_ptr( + l, NNG_OPT_IPC_SECURITY_DESCRIPTOR, NULL), + NNG_EINVAL); + + nng_stream_listener_close(l); + nng_stream_listener_free(l); +} + +void +test_ipc_security_descriptor_dialer(void) +{ + nng_stream_dialer *d; + char address[64]; + SECURITY_DESCRIPTOR *sdesc; + + nuts_scratch_addr("ipc", sizeof(address), address); + NUTS_PASS(nng_stream_dialer_alloc(&d, address)); + + sdesc = calloc(SECURITY_DESCRIPTOR_MIN_LENGTH, 1); + NUTS_ASSERT(sdesc != NULL); + InitializeSecurityDescriptor(sdesc, SECURITY_DESCRIPTOR_REVISION); + NUTS_FAIL(nng_stream_dialer_set_ptr( + d, NNG_OPT_IPC_SECURITY_DESCRIPTOR, sdesc), + NNG_ENOTSUP); + free(sdesc); + nng_stream_dialer_free(d); +} + +NUTS_TESTS = { + { "ipc security descriptor", test_ipc_security_descriptor }, + { "ipc security descriptor busy", test_ipc_security_descriptor_busy }, + { "ipc security descriptor bogus", + test_ipc_security_descriptor_bogus }, + { "ipc security descriptor dialer", + test_ipc_security_descriptor_dialer }, + { NULL, NULL }, +}; diff --git a/src/platform/windows/win_thread.c b/src/platform/windows/win_thread.c index dc9ed12a..9c7c09d3 100644 --- a/src/platform/windows/win_thread.c +++ b/src/platform/windows/win_thread.c @@ -381,7 +381,8 @@ nni_plat_thr_set_name(nni_plat_thr *thr, const char *name) if ((wcs = nni_alloc(len * 2)) == NULL) { return; } - (void) MultiByteToWideChar(CP_UTF8, 0, name, len, wcs, len); + (void) MultiByteToWideChar( + CP_UTF8, 0, name, (int) len, wcs, (int) len); set_thread_desc(h, wcs); nni_free(wcs, len * 2); } -- cgit v1.2.3-70-g09d2