// Native SCM boundary host. No Chromium/Electron changes; installation is // separate. #define WIN32_LEAN_AND_MEAN #include "service-pins.h" #include "wfp-topology.h" #include #include #include #include #include #include #include #include #include #include #include #include #pragma comment(lib, "advapi32.lib") #pragma comment(lib, "bcrypt.lib") static constexpr wchar_t SERVICE_NAME[] = L"SafetyNetNetworkBroker"; static constexpr wchar_t PIPE_NAME[] = L"\\\\.\\pipe\\SafetyNet.Broker.v1"; struct Handle { HANDLE h = nullptr; explicit Handle(HANDLE v = nullptr) : h(v) {} ~Handle() { if (h && h != INVALID_HANDLE_VALUE) CloseHandle(h); } Handle(const Handle &) = delete; Handle &operator=(const Handle &) = delete; operator HANDLE() const { return h; } }; static HANDLE stopEvent; static SERVICE_STATUS_HANDLE statusHandle; static bool hashFile(const std::wstring &file, const char *expected) { Handle input(CreateFileW(file.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT, nullptr)); if (input.h == INVALID_HANDLE_VALUE) return false; FILE_ATTRIBUTE_TAG_INFO info{}; if (!GetFileInformationByHandleEx(input, FileAttributeTagInfo, &info, sizeof(info)) || (info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) return false; BCRYPT_ALG_HANDLE algorithm = nullptr; BCRYPT_HASH_HANDLE hash = nullptr; bool good = false; if (BCryptOpenAlgorithmProvider(&algorithm, BCRYPT_SHA256_ALGORITHM, nullptr, 0) < 0) return false; if (BCryptCreateHash(algorithm, &hash, nullptr, 0, nullptr, 0, 0) >= 0) { std::array buffer; DWORD read = 0; bool okay = true; while (true) { if (!ReadFile(input, buffer.data(), DWORD(buffer.size()), &read, nullptr)) { okay = false; break; } if (!read) break; if (BCryptHashData(hash, buffer.data(), read, 0) < 0) { okay = false; break; } } std::array digest{}; if (okay && BCryptFinishHash(hash, digest.data(), 32, 0) >= 0) { char hex[65]{}; for (size_t i = 0; i < 32; i++) sprintf_s(hex + i * 2, 3, "%02x", digest[i]); good = strcmp(hex, expected) == 0; } BCryptDestroyHash(hash); } BCryptCloseAlgorithmProvider(algorithm, 0); return good; } static std::vector tokenInfo(HANDLE token, TOKEN_INFORMATION_CLASS kind) { DWORD size = 0; GetTokenInformation(token, kind, nullptr, 0, &size); if (!size || size > 65536) return {}; std::vector value(size); if (!GetTokenInformation(token, kind, value.data(), size, &size)) return {}; return value; } static bool serviceIdentity(HANDLE process = GetCurrentProcess()) { Handle token; if (!OpenProcessToken(process, TOKEN_QUERY, &token.h)) return false; auto groups = tokenInfo(token, TokenGroups); if (groups.empty()) return false; DWORD sidBytes = 0, domainBytes = 0; SID_NAME_USE use; LookupAccountNameW(nullptr, L"NT SERVICE\\SafetyNetNetworkBroker", nullptr, &sidBytes, nullptr, &domainBytes, &use); if (!sidBytes || sidBytes > 65536) return false; std::vector sid(sidBytes); std::vector domain(domainBytes); if (!LookupAccountNameW(nullptr, L"NT SERVICE\\SafetyNetNetworkBroker", sid.data(), &sidBytes, domain.data(), &domainBytes, &use)) return false; auto list = reinterpret_cast(groups.data()); for (DWORD i = 0; i < list->GroupCount; i++) if (EqualSid(list->Groups[i].Sid, sid.data()) && (list->Groups[i].Attributes & SE_GROUP_ENABLED) && !(list->Groups[i].Attributes & SE_GROUP_USE_FOR_DENY_ONLY)) return true; return false; } static std::vector serviceSid() { DWORD size = 0, domainSize = 0; SID_NAME_USE use; LookupAccountNameW(nullptr, L"NT SERVICE\\SafetyNetNetworkBroker", nullptr, &size, nullptr, &domainSize, &use); if (!size || size > 65536 || domainSize > 32768) return {}; std::vector sid(size); std::vector domain(domainSize); if (!LookupAccountNameW(nullptr, L"NT SERVICE\\SafetyNetNetworkBroker", sid.data(), &size, domain.data(), &domainSize, &use)) return {}; return sid; } static bool protectedPath(const std::wstring &file) { // Resources may be readable by employees, but only SYSTEM/Administrators may // modify code. Unknown write trustees fail closed; inheritable-only ACEs are // checked on their descendants rather than treated as effective on the // parent. PSECURITY_DESCRIPTOR descriptor = nullptr; PACL dacl = nullptr; PSID owner = nullptr; DWORD code = GetNamedSecurityInfoW( file.c_str(), SE_FILE_OBJECT, DACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION, &owner, nullptr, &dacl, nullptr, &descriptor); if (code || !dacl) return false; BYTE system[SECURITY_MAX_SID_SIZE], admins[SECURITY_MAX_SID_SIZE]; DWORD ss = sizeof(system), as = sizeof(admins); CreateWellKnownSid(WinLocalSystemSid, nullptr, system, &ss); CreateWellKnownSid(WinBuiltinAdministratorsSid, nullptr, admins, &as); bool good = owner && (EqualSid(owner, system) || EqualSid(owner, admins)); for (DWORD i = 0; i < dacl->AceCount; i++) { void *raw = nullptr; if (!GetAce(dacl, i, &raw)) { good = false; break; } auto header = static_cast(raw); if (header->AceFlags & INHERIT_ONLY_ACE) continue; if (header->AceType == ACCESS_ALLOWED_ACE_TYPE) { auto ace = static_cast(raw); DWORD write = FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES | DELETE | WRITE_DAC | WRITE_OWNER | FILE_DELETE_CHILD | GENERIC_WRITE | GENERIC_ALL; if ((ace->Mask & write) && !EqualSid(&ace->SidStart, system) && !EqualSid(&ace->SidStart, admins)) { good = false; break; } } else if (header->AceType != ACCESS_DENIED_ACE_TYPE) { good = false; break; } } LocalFree(descriptor); return good; } #include "acceptance-state.h" #include "management-credential.h" #include "signed-manifest.h" struct TrustFloor { ULONGLONG release = 0, deployment = 0; std::string releaseDigest, deploymentDigest, stateCanonical; }; static TrustFloor trustFloor() { HKEY key = nullptr; if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\SafetyNet\\Trust", 0, KEY_READ | READ_CONTROL | KEY_WOW64_64KEY, &key) != ERROR_SUCCESS) throw std::runtime_error("fixed-trust-unavailable"); // A writable counter store would turn signature checking into rollback. PSECURITY_DESCRIPTOR descriptor = nullptr; PACL dacl = nullptr; PSID owner = nullptr; DWORD status = GetSecurityInfo(key, SE_REGISTRY_KEY, DACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION, &owner, nullptr, &dacl, nullptr, &descriptor); BYTE system[SECURITY_MAX_SID_SIZE], admins[SECURITY_MAX_SID_SIZE]; DWORD ss = sizeof(system), as = sizeof(admins); CreateWellKnownSid(WinLocalSystemSid, nullptr, system, &ss); CreateWellKnownSid(WinBuiltinAdministratorsSid, nullptr, admins, &as); bool valid = !status && dacl && owner && (EqualSid(owner, system) || EqualSid(owner, admins)); auto service = serviceSid(); if (valid) for (DWORD i = 0; i < dacl->AceCount; i++) { void *raw = nullptr; if (!GetAce(dacl, i, &raw)) { valid = false; break; } auto header = static_cast(raw); if (header->AceFlags & INHERIT_ONLY_ACE) continue; if (header->AceType == ACCESS_ALLOWED_ACE_TYPE) { auto ace = static_cast(raw); if ((ace->Mask & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | DELETE | WRITE_DAC | WRITE_OWNER | GENERIC_WRITE | GENERIC_ALL)) && !EqualSid(&ace->SidStart, system) && !EqualSid(&ace->SidStart, admins) && !(service.size() && EqualSid(&ace->SidStart, service.data()) && !(ace->Mask & ~(KEY_QUERY_VALUE | KEY_SET_VALUE | READ_CONTROL | KEY_NOTIFY | KEY_ENUMERATE_SUB_KEYS | SYNCHRONIZE)))) { valid = false; break; } } else if (header->AceType != ACCESS_DENIED_ACE_TYPE) { valid = false; break; } } if (descriptor) LocalFree(descriptor); DWORD type = 0, size = 0; bool okay = valid && RegQueryValueExW(key, L"AcceptanceState", nullptr, &type, nullptr, &size) == ERROR_SUCCESS && type == REG_BINARY && size > 0 && size <= 2097152; std::string canonical(okay ? size : 0, '\0'); if (okay) okay = RegQueryValueExW(key, L"AcceptanceState", nullptr, &type, reinterpret_cast(canonical.data()), &size) == ERROR_SUCCESS && type == REG_BINARY && size == canonical.size(); RegCloseKey(key); if (!okay) throw std::runtime_error("fixed-trust-unavailable"); auto state = acceptance_contract::validate(canonical); TrustFloor floor; floor.release = release_contract::number( state.object.at("release").object.at("minimumSequence")); floor.deployment = release_contract::number( state.object.at("deployment").object.at("minimumSequence")); floor.releaseDigest = release_contract::str( state.object.at("release").object.at("acceptedDigest")); floor.deploymentDigest = release_contract::str( state.object.at("deployment").object.at("acceptedDigest")); floor.stateCanonical = canonical; return floor; } static release_contract::Release trustedRelease(const std::wstring &root) { auto floor = trustFloor(); auto release = release_contract::release( root, release_contract::unhex(RELEASE_ANCHOR_XY), floor.release, floor.releaseDigest); auto state = acceptance_contract::validate(floor.stateCanonical); if (release.tenant != release_contract::str(state.object.at("deployment").object.at("tenant"))) throw std::runtime_error("fixed-trust-unavailable"); return release; } static std::string currentSid(HANDLE process) { Handle token; if (!OpenProcessToken(process, TOKEN_QUERY, &token.h)) throw std::runtime_error("fixed-peer-invalid"); auto value = tokenInfo(token, TokenUser); if (value.empty()) throw std::runtime_error("fixed-peer-invalid"); LPSTR text = nullptr; if (!ConvertSidToStringSidA( reinterpret_cast(value.data())->User.Sid, &text)) throw std::runtime_error("fixed-peer-invalid"); std::string result = text; LocalFree(text); return result; } static Handle *parentProcess(HANDLE process) { // Called only with a retained actual process handle; no PID supplied by IPC. DWORD pid = GetProcessId(process); Handle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)); PROCESSENTRY32W item{}; item.dwSize = sizeof(item); if (snapshot.h == INVALID_HANDLE_VALUE || !Process32FirstW(snapshot, &item)) return nullptr; do { if (item.th32ProcessID == pid) { HANDLE parent = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION | SYNCHRONIZE, FALSE, item.th32ParentProcessID); if (!parent) return nullptr; FILETIME childCreated{}, parentCreated{}, exit{}, kernel{}, user{}; if (!GetProcessTimes(process, &childCreated, &exit, &kernel, &user) || !GetProcessTimes(parent, &parentCreated, &exit, &kernel, &user) || CompareFileTime(&parentCreated, &childCreated) > 0) { CloseHandle(parent); return nullptr; } return new Handle(parent); } } while (Process32NextW(snapshot, &item)); return nullptr; } static bool verifiedImage(HANDLE process, const std::wstring &root, const char *relative, const release_contract::Release &release) { std::array image{}; DWORD size = DWORD(image.size()); std::wstring required = root + L"\\" + std::wstring(relative, relative + strlen(relative)); auto found = release.hashes.find(relative); if (found == release.hashes.end() || WaitForSingleObject(process, 0) != WAIT_TIMEOUT || !QueryFullProcessImageNameW(process, 0, image.data(), &size) || CompareStringOrdinal(image.data(), int(size), required.c_str(), -1, TRUE) != CSTR_EQUAL || !protectedPath(required) || !protectedPath(root)) return false; return hashFile(required, found->second.c_str()); } static bool sameUserSession(HANDLE left, HANDLE right, bool service = false) { Handle lt, rt; if (!OpenProcessToken(left, TOKEN_QUERY, <.h) || !OpenProcessToken(right, TOKEN_QUERY, &rt.h)) return false; auto lu = tokenInfo(lt, TokenUser), ru = tokenInfo(rt, TokenUser), ls = tokenInfo(lt, TokenSessionId), rs = tokenInfo(rt, TokenSessionId), lc = tokenInfo(lt, TokenIsAppContainer), rc = tokenInfo(rt, TokenIsAppContainer), li = tokenInfo(lt, TokenIntegrityLevel), ri = tokenInfo(rt, TokenIntegrityLevel); if (lu.empty() || ru.empty() || ls.empty() || rs.empty() || lc.empty() || rc.empty() || li.empty() || ri.empty() || *reinterpret_cast(lc.data()) || *reinterpret_cast(rc.data())) return false; for (const auto *item : {&li, &ri}) { auto label = reinterpret_cast(item->data()); DWORD level = *GetSidSubAuthority( label->Label.Sid, *GetSidSubAuthorityCount(label->Label.Sid) - 1); if (level < SECURITY_MANDATORY_MEDIUM_RID || level > DWORD(service ? SECURITY_MANDATORY_SYSTEM_RID : SECURITY_MANDATORY_HIGH_RID)) return false; } return EqualSid(reinterpret_cast(lu.data())->User.Sid, reinterpret_cast(ru.data())->User.Sid) && *reinterpret_cast(ls.data()) == *reinterpret_cast(rs.data()); } static bool pipeClient(HANDLE pipe, const std::wstring &root, HANDLE *retained = nullptr) { ULONG pid = 0; if (!GetNamedPipeClientProcessId(pipe, &pid) || !pid) return false; Handle process( OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION | SYNCHRONIZE, FALSE, pid)); if (!process.h || WaitForSingleObject(process, 0) != WAIT_TIMEOUT) return false; try { auto release = trustedRelease(root); std::unique_ptr parent(parentProcess(process)); if (!parent || !verifiedImage(process, root, "safetynet-service-host.exe", release) || !verifiedImage(*parent, root, "SafetyNet.exe", release) || !sameUserSession(process, *parent)) return false; } catch (...) { return false; } Handle actual; if (!OpenProcessToken(process, TOKEN_QUERY, &actual.h)) return false; auto user = tokenInfo(actual, TokenUser), session = tokenInfo(actual, TokenSessionId), container = tokenInfo(actual, TokenIsAppContainer), integrity = tokenInfo(actual, TokenIntegrityLevel); if (user.empty() || session.empty() || container.empty() || integrity.empty() || *reinterpret_cast(container.data())) return false; auto label = reinterpret_cast(integrity.data()); DWORD level = *GetSidSubAuthority( label->Label.Sid, *GetSidSubAuthorityCount(label->Label.Sid) - 1); if (level < SECURITY_MANDATORY_MEDIUM_RID || level > SECURITY_MANDATORY_HIGH_RID) return false; if (!ImpersonateNamedPipeClient(pipe)) return false; Handle peer; bool opened = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &peer.h) != FALSE; bool reverted = RevertToSelf() != FALSE; if (!reverted) { TerminateProcess(GetCurrentProcess(), ERROR_ACCESS_DENIED); return false; } if (!opened) return false; auto peerUser = tokenInfo(peer, TokenUser), peerSession = tokenInfo(peer, TokenSessionId); if (peerUser.empty() || peerSession.empty()) return false; bool authenticated = EqualSid(reinterpret_cast(user.data())->User.Sid, reinterpret_cast(peerUser.data())->User.Sid) && *reinterpret_cast(session.data()) == *reinterpret_cast(peerSession.data()) && WaitForSingleObject(process, 0) == WAIT_TIMEOUT; if (authenticated && retained) { *retained = process.h; process.h = nullptr; } return authenticated; } static bool transfer(HANDLE pipe, bool write, void *bytes, DWORD length, DWORD timeout, ULONGLONG *firstByteAt = nullptr) { auto cursor = static_cast(bytes); ULONGLONG started = GetTickCount64(); while (length) { Handle event(CreateEventW(nullptr, TRUE, FALSE, nullptr)); OVERLAPPED ov{}; ov.hEvent = event; DWORD done = 0; BOOL result = write ? WriteFile(pipe, cursor, length, &done, &ov) : ReadFile(pipe, cursor, length, &done, &ov); if (!result) { if (GetLastError() != ERROR_IO_PENDING) return false; HANDLE waits[] = {event.h, stopEvent}; ULONGLONG elapsed = GetTickCount64() - started; DWORD remaining = timeout == INFINITE ? INFINITE : (elapsed >= timeout ? 0 : timeout - DWORD(elapsed)); DWORD status = WaitForMultipleObjects(2, waits, FALSE, remaining); if (status != WAIT_OBJECT_0) { CancelIoEx(pipe, &ov); WaitForSingleObject(event, INFINITE); return false; } if (!GetOverlappedResult(pipe, &ov, &done, FALSE)) return false; } if (!done) return false; if (firstByteAt && !*firstByteAt) *firstByteAt = GetTickCount64(); if (timeout == INFINITE && done < length) { timeout = 15000; started = GetTickCount64(); } cursor += done; length -= done; } return true; } static bool frame(HANDLE pipe, bool write, std::vector &value, DWORD maximum, DWORD headerTimeout = 15000) { ULONGLONG started = GetTickCount64(); ULONGLONG firstByteAt = 0; DWORD size = write ? DWORD(value.size()) : 0; if (!transfer(pipe, write, &size, 4, headerTimeout, &firstByteAt) || !size || size > maximum) return false; if (headerTimeout == INFINITE) started = firstByteAt; DWORD budget = headerTimeout == INFINITE ? 15000 : headerTimeout; ULONGLONG elapsed = GetTickCount64() - started; if (elapsed >= budget) return false; if (!write) value.resize(size); return transfer(pipe, write, value.data(), size, budget - DWORD(elapsed)); } static std::wstring rootPath() { std::array image{}; DWORD size = GetModuleFileNameW(nullptr, image.data(), DWORD(image.size())); if (!size || size >= image.size()) return {}; std::wstring root(image.data(), size); return root.substr(0, root.find_last_of(L'\\')); } static bool resources(const std::wstring &root) { try { if (root.empty() || !protectedPath(root) || !protectedPath(root + L"\\release-envelope.json") || !protectedPath(root + L"\\deployment-envelope.json")) return false; auto release = trustedRelease(root); for (const auto &pin : release.hashes) { std::wstring relative(pin.first.begin(), pin.first.end()); std::replace(relative.begin(), relative.end(), L'/', L'\\'); std::wstring file = root + std::wstring(1, wchar_t(92)) + relative, ancestor = file; while (ancestor.size() > root.size()) { if (GetFileAttributesW(ancestor.c_str()) & FILE_ATTRIBUTE_REPARSE_POINT || !protectedPath(ancestor)) return false; ancestor = ancestor.substr(0, ancestor.find_last_of(L'\\')); } if (!hashFile(file, pin.second.c_str())) return false; } return true; } catch (...) { return false; } } static std::wstring environment(const std::string &sid) { std::wstring result; for (const wchar_t *name : {L"SystemRoot", L"WINDIR", L"TEMP", L"TMP", L"USERPROFILE", L"LOCALAPPDATA", L"APPDATA"}) { DWORD size = GetEnvironmentVariableW(name, nullptr, 0); if (size && size < 32768) { std::vector value(size); GetEnvironmentVariableW(name, value.data(), size); result += name; result += L'='; result += value.data(); result += L'\0'; } } result += L"SAFETYNET_SERVICE_CLIENT_SID="; result += std::wstring(sid.begin(), sid.end()); result += L'\0'; result += L'\0'; return result; } static bool writeChildFrame(HANDLE pipe, const std::vector &value, std::atomic &deadline, DWORD budget = 15000) { deadline = GetTickCount64() + budget; DWORD size = DWORD(value.size()); auto exact = [&](const BYTE *bytes, DWORD length) { while (length) { DWORD done = 0; if (!WriteFile(pipe, bytes, length, &done, nullptr) || !done) return false; bytes += done; length -= done; } return true; }; if (!exact(reinterpret_cast(&size), 4) || !exact(value.data(), size)) return false; deadline = 0; return true; } static bool verifiedServer(HANDLE pipe, const std::wstring &root, const release_contract::Release &release, HANDLE *retained, const char *role = "safetynet-service-host.exe") { ULONG pid = 0; if (!GetNamedPipeServerProcessId(pipe, &pid) || !pid) return false; Handle process( OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION | SYNCHRONIZE, FALSE, pid)); if (!process.h || !verifiedImage(process, root, role, release) || !serviceIdentity(process)) return false; *retained = process.h; process.h = nullptr; return true; } static bool boundedStdioWrite(const std::string &text); static int topologySnapshot() { try { const auto root = rootPath(); if (!serviceIdentity()) return ERROR_ACCESS_DENIED; auto release = trustedRelease(root); std::unique_ptr parent(parentProcess(GetCurrentProcess())); if (!parent || !serviceIdentity(*parent) || !verifiedImage(GetCurrentProcess(), root, "safetynet-service-host.exe", release) || !verifiedImage(*parent, root, "resources/broker/node.exe", release) || !sameUserSession(GetCurrentProcess(), *parent, true)) return ERROR_ACCESS_DENIED; DWORD userLength = GetEnvironmentVariableA("SAFETYNET_SERVICE_CLIENT_SID", nullptr, 0); if (!userLength || userLength > 256) return ERROR_ACCESS_DENIED; std::string userSid(userLength, '\0'); if (!GetEnvironmentVariableA("SAFETYNET_SERVICE_CLIENT_SID", userSid.data(), userLength)) return ERROR_ACCESS_DENIED; userSid.resize(userLength - 1); auto assignmentFloor = trustFloor(); release_contract::deployment(root, release, userSid, assignmentFloor.deployment, assignmentFloor.deploymentDigest); auto sid = serviceSid(); LPWSTR text = nullptr; if (sid.empty() || !ConvertSidToStringSidW(sid.data(), &text)) return ERROR_ACCESS_DENIED; std::wstring serviceText = text; LocalFree(text); auto result = topology_contract::inspect(root, serviceText); const std::string json = "{\"version\":1,\"brokerPort\":43120,\"accessibleFilters\":" + std::to_string(result.accessibleFilters) + ",\"ownedFilters\":" + std::to_string(result.ownedFilters) + ",\"ownedVerified\":" + (result.ownedVerified ? "true" : "false") + ",\"collision\":" + (result.collision ? "true" : "false") + ",\"bfeRunning\":" + (result.bfeRunning ? "true" : "false") + ",\"allObjectsReadable\":false,\"code\":" + std::to_string(result.code) + "}"; return boundedStdioWrite(json) ? 0 : ERROR_ACCESS_DENIED; } catch (...) { return ERROR_ACCESS_DENIED; } } static int trustSnapshot() { try { const auto root = rootPath(); if (!serviceIdentity()) return ERROR_ACCESS_DENIED; auto release = trustedRelease(root); std::unique_ptr parent(parentProcess(GetCurrentProcess())); if (!parent || !serviceIdentity(*parent) || !verifiedImage(GetCurrentProcess(), root, "safetynet-service-host.exe", release) || !verifiedImage(*parent, root, "resources/broker/node.exe", release) || !sameUserSession(GetCurrentProcess(), *parent, true)) return ERROR_ACCESS_DENIED; DWORD length = GetEnvironmentVariableA("SAFETYNET_SERVICE_CLIENT_SID", nullptr, 0); if (!length || length > 256) return ERROR_ACCESS_DENIED; std::string sid(length, '\0'); if (!GetEnvironmentVariableA("SAFETYNET_SERVICE_CLIENT_SID", sid.data(), length)) return ERROR_ACCESS_DENIED; sid.resize(length - 1); auto floor = trustFloor(); release_contract::deployment(root, release, sid, floor.deployment, floor.deploymentDigest); auto xy = release_contract::unhex(RELEASE_ANCHOR_XY); auto der = release_contract::unhex( "3059301306072a8648ce3d020106082a8648ce3d03010703420004"); der.insert(der.end(), xy.begin(), xy.end()); std::string encoded = release_contract::base64url(der); std::replace(encoded.begin(), encoded.end(), '-', '+'); std::replace(encoded.begin(), encoded.end(), '_', '/'); while (encoded.size() % 4) encoded += '='; std::string anchor = "-----BEGIN PUBLIC KEY-----\n"; for (size_t offset = 0; offset < encoded.size(); offset += 64) anchor += encoded.substr(offset, 64) + '\n'; anchor += "-----END PUBLIC KEY-----\n"; // All values originate in immutable code/protected Windows state. No // registry selector, key, SID or path is accepted from command arguments. std::string json = "{\"acceptanceState\":" + floor.stateCanonical + ",\"authenticatedSid\":" + release_contract::escaped(sid) + ",\"releaseAnchor\":" + release_contract::escaped(anchor) + ",\"version\":1}"; return boundedStdioWrite(json) ? 0 : ERROR_ACCESS_DENIED; } catch (...) { return ERROR_ACCESS_DENIED; } } static bool readStdioFrame(HANDLE input, std::vector &value, DWORD maximum, std::atomic &deadline) { DWORD size = 0, done = 0; if (!ReadFile(input, &size, 4, &done, nullptr) || !done) return false; deadline = GetTickCount64() + 15000; DWORD offset = done; while (offset < 4) { if (!ReadFile(input, reinterpret_cast(&size) + offset, 4 - offset, &done, nullptr) || !done) return false; offset += done; } if (!size || size > maximum) return false; value.resize(size); offset = 0; while (offset < size) { if (!ReadFile(input, value.data() + offset, size - offset, &done, nullptr) || !done) return false; offset += done; } deadline = 0; return true; } static int clientStdio() { try { const auto root = rootPath(); auto release = trustedRelease(root); std::unique_ptr parent(parentProcess(GetCurrentProcess())); if (!parent || !verifiedImage(GetCurrentProcess(), root, "safetynet-service-host.exe", release) || !verifiedImage(*parent, root, "SafetyNet.exe", release) || !sameUserSession(GetCurrentProcess(), *parent)) return ERROR_ACCESS_DENIED; auto floor = trustFloor(); release_contract::deployment(root, release, currentSid(GetCurrentProcess()), floor.deployment, floor.deploymentDigest); HANDLE input = GetStdHandle(STD_INPUT_HANDLE), output = GetStdHandle(STD_OUTPUT_HANDLE); if (GetFileType(input) != FILE_TYPE_PIPE || GetFileType(output) != FILE_TYPE_PIPE) return ERROR_ACCESS_DENIED; // Connect exactly once, then authenticate THIS handle's server. No probe // and reconnect, retry, alternate endpoint, service startup or command // selector. Handle pipe(CreateFileW(PIPE_NAME, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, nullptr)); if (pipe.h == INVALID_HANDLE_VALUE) return ERROR_ACCESS_DENIED; Handle server; if (!verifiedServer(pipe, root, release, &server.h)) return ERROR_ACCESS_DENIED; Handle stop(CreateEventW(nullptr, TRUE, FALSE, nullptr)); stopEvent = stop; Handle reader; if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &reader.h, THREAD_TERMINATE, FALSE, 0)) return ERROR_ACCESS_DENIED; std::atomic good{true}; std::atomic readDeadline{0}, writeDeadline{0}; std::thread outputPump([&] { while (good) { std::vector value; if (!frame(pipe, false, value, 65536, INFINITE) || !writeChildFrame(output, value, writeDeadline)) { good = false; break; } } CancelSynchronousIo(reader); SetEvent(stopEvent); }); std::thread watcher([&] { while (good) { if (WaitForSingleObject(stopEvent, 50) == WAIT_OBJECT_0 || WaitForSingleObject(*parent, 0) != WAIT_TIMEOUT || WaitForSingleObject(server, 0) != WAIT_TIMEOUT || (readDeadline.load() && GetTickCount64() >= readDeadline.load()) || (writeDeadline.load() && GetTickCount64() >= writeDeadline.load())) { good = false; SetEvent(stopEvent); CancelSynchronousIo(reader); CancelSynchronousIo(outputPump.native_handle()); CancelIoEx(pipe, nullptr); break; } } }); bool first = true; while (good) { std::vector value; if (!readStdioFrame(input, value, first ? 2097152 : 65536, readDeadline) || !frame(pipe, true, value, first ? 2097152 : 65536)) break; first = false; } good = false; SetEvent(stopEvent); CancelIoEx(pipe, nullptr); CancelSynchronousIo(outputPump.native_handle()); outputPump.join(); watcher.join(); return 0; } catch (...) { return ERROR_ACCESS_DENIED; } } static bool boundedStdioRead(HANDLE input, std::vector &value, DWORD maximum) { if (GetFileType(input) != FILE_TYPE_PIPE) return false; Handle ownThread; if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &ownThread.h, THREAD_TERMINATE, FALSE, 0)) return false; std::atomic finished{false}; std::atomic deadline{GetTickCount64() + 15000}; const ULONGLONG expires = GetTickCount64() + 15000; std::thread watchdog([&] { while (!finished) { if (GetTickCount64() >= expires) { CancelSynchronousIo(ownThread); break; } Sleep(10); } }); bool okay = readStdioFrame(input, value, maximum, deadline); finished = true; watchdog.join(); return okay; } static bool boundedStdioWrite(const std::string &text) { HANDLE output = GetStdHandle(STD_OUTPUT_HANDLE); if (GetFileType(output) != FILE_TYPE_PIPE || text.size() > 2097152) return false; Handle ownThread; if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &ownThread.h, THREAD_TERMINATE, FALSE, 0)) return false; std::atomic finished{false}; std::atomic deadline{0}; const ULONGLONG expires = GetTickCount64() + 15000; std::thread watchdog([&] { while (!finished) { if (GetTickCount64() >= expires) { CancelSynchronousIo(ownThread); break; } Sleep(10); } }); std::vector bytes(text.begin(), text.end()); bool okay = writeChildFrame(output, bytes, deadline); finished = true; watchdog.join(); if (!bytes.empty()) SecureZeroMemory(bytes.data(), bytes.size()); return okay; } static bool ownedAcceptanceMutex(HANDLE mutex, const std::vector &service) { PSECURITY_DESCRIPTOR descriptor = nullptr; PACL dacl = nullptr; PSID owner = nullptr; DWORD result = GetSecurityInfo(mutex, SE_KERNEL_OBJECT, OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, &owner, nullptr, &dacl, nullptr, &descriptor); BYTE system[SECURITY_MAX_SID_SIZE], admins[SECURITY_MAX_SID_SIZE], localService[SECURITY_MAX_SID_SIZE]; DWORD ss = sizeof(system), as = sizeof(admins), ls = sizeof(localService); CreateWellKnownSid(WinLocalSystemSid, nullptr, system, &ss); CreateWellKnownSid(WinBuiltinAdministratorsSid, nullptr, admins, &as); CreateWellKnownSid(WinLocalServiceSid, nullptr, localService, &ls); PSID ownerRights = nullptr; if (!ConvertStringSidToSidW(L"S-1-3-4", &ownerRights)) { if (descriptor) LocalFree(descriptor); return false; } bool valid = result == ERROR_SUCCESS && owner && dacl && service.size() && (EqualSid(owner, localService) || EqualSid(owner, const_cast(service.data()))); unsigned ownerRightsCount = 0; if (valid) for (DWORD index = 0; index < dacl->AceCount; index++) { void *raw = nullptr; if (!GetAce(dacl, index, &raw)) { valid = false; break; } auto header = static_cast(raw); if (header->AceFlags & INHERIT_ONLY_ACE) continue; if (header->AceType == ACCESS_ALLOWED_ACE_TYPE) { auto ace = static_cast(raw); if (EqualSid(&ace->SidStart, ownerRights)) { if (ace->Mask != READ_CONTROL) { valid = false; break; } ownerRightsCount++; continue; } if (!EqualSid(&ace->SidStart, system) && !EqualSid(&ace->SidStart, admins) && !EqualSid(&ace->SidStart, const_cast(service.data()))) { valid = false; break; } } else if (header->AceType != ACCESS_DENIED_ACE_TYPE) { valid = false; break; } } if (descriptor) LocalFree(descriptor); LocalFree(ownerRights); return valid && ownerRightsCount == 1; } static bool protectedCredentialKey(HKEY key, const std::vector &service) { PSECURITY_DESCRIPTOR descriptor = nullptr; PACL dacl = nullptr; PSID owner = nullptr; DWORD status = GetSecurityInfo(key, SE_REGISTRY_KEY, DACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION, &owner, nullptr, &dacl, nullptr, &descriptor); BYTE system[SECURITY_MAX_SID_SIZE], admins[SECURITY_MAX_SID_SIZE]; DWORD ss = sizeof(system), as = sizeof(admins); CreateWellKnownSid(WinLocalSystemSid, nullptr, system, &ss); CreateWellKnownSid(WinBuiltinAdministratorsSid, nullptr, admins, &as); SECURITY_DESCRIPTOR_CONTROL control{}; DWORD revision = 0; bool okay = !status && dacl && owner && (EqualSid(owner, system) || EqualSid(owner, admins)) && GetSecurityDescriptorControl(descriptor, &control, &revision) && (control & SE_DACL_PROTECTED); if (okay) for (DWORD i = 0; i < dacl->AceCount; ++i) { void *raw = nullptr; if (!GetAce(dacl, i, &raw)) { okay = false; break; } auto header = static_cast(raw); if (header->AceFlags & INHERIT_ONLY_ACE) continue; if (header->AceType == ACCESS_ALLOWED_ACE_TYPE) { auto ace = static_cast(raw); if (!EqualSid(&ace->SidStart, system) && !EqualSid(&ace->SidStart, admins) && (!EqualSid(&ace->SidStart, const_cast(service.data())) || (ace->Mask & ~(KEY_QUERY_VALUE | KEY_SET_VALUE | READ_CONTROL)))) { okay = false; break; } } else if (header->AceType != ACCESS_DENIED_ACE_TYPE) { okay = false; break; } } if (descriptor) LocalFree(descriptor); return okay; } static int managementCredential(bool provision) { try { const auto root = rootPath(); if (!serviceIdentity()) return ERROR_ACCESS_DENIED; auto release = trustedRelease(root); std::unique_ptr parent(parentProcess(GetCurrentProcess())); if (!parent || !serviceIdentity(*parent) || !verifiedImage(GetCurrentProcess(), root, "safetynet-service-host.exe", release) || !verifiedImage(*parent, root, "resources/broker/node.exe", release) || !sameUserSession(GetCurrentProcess(), *parent, true)) return ERROR_ACCESS_DENIED; DWORD sidLength = GetEnvironmentVariableA("SAFETYNET_SERVICE_CLIENT_SID", nullptr, 0); if (!sidLength || sidLength > 256) return ERROR_ACCESS_DENIED; std::string sid(sidLength, '\0'); if (!GetEnvironmentVariableA("SAFETYNET_SERVICE_CLIENT_SID", sid.data(), sidLength)) return ERROR_ACCESS_DENIED; sid.resize(sidLength - 1); credential_contract::Wipe frame; if (!boundedStdioRead(GetStdHandle(STD_INPUT_HANDLE), frame.bytes, provision ? 16384 : 4096)) return ERROR_ACCESS_DENIED; std::string requestText(frame.bytes.begin(), frame.bytes.end()); credential_contract::WipeText wipeRequest{requestText}; auto request = credential_contract::parse(requestText); SecureZeroMemory(requestText.data(), requestText.size()); struct SecretCleanup { release_contract::Json &value; ~SecretCleanup() { auto found = value.object.find("token"); if (found != value.object.end() && !found->second.string.empty()) SecureZeroMemory(found->second.string.data(), found->second.string.size()); } } secretCleanup{request}; if (provision ? !release_contract::exact( request, {"deviceId", "origin", "policyVersion", "policyKeySha256", "policyDigest", "expectedPreviousSHA", "token"}) : !release_contract::exact( request, {"deviceId", "origin", "policyVersion", "policyKeySha256", "policyDigest"})) return ERROR_ACCESS_DENIED; auto service = serviceSid(); LPWSTR serviceText = nullptr; if (service.empty() || !ConvertSidToStringSidW(service.data(), &serviceText)) return ERROR_ACCESS_DENIED; std::wstring security = L"D:P(A;;RC;;;OW)(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;" + std::wstring(serviceText) + L")"; LocalFree(serviceText); PSECURITY_DESCRIPTOR descriptor = nullptr; if (!ConvertStringSecurityDescriptorToSecurityDescriptorW( security.c_str(), SDDL_REVISION_1, &descriptor, nullptr)) return ERROR_ACCESS_DENIED; SECURITY_ATTRIBUTES attributes{sizeof(attributes), descriptor, FALSE}; Handle mutex( CreateMutexW(&attributes, FALSE, L"Global\\SafetyNet.Acceptance.v1")); LocalFree(descriptor); if (!mutex.h || !ownedAcceptanceMutex(mutex, service) || WaitForSingleObject(mutex, 15000) != WAIT_OBJECT_0) return ERROR_ACCESS_DENIED; struct Unlock { HANDLE h; ~Unlock() { ReleaseMutex(h); } } unlock{mutex.h}; auto floor = trustFloor(); release = trustedRelease(root); auto assignment = release_contract::deployment( root, release, sid, floor.deployment, floor.deploymentDigest); const auto metadata = credential_contract::binding( request, assignment, acceptance_contract::validate(floor.stateCanonical)); HKEY key = nullptr; if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\SafetyNet\\ManagementCredentials", 0, KEY_QUERY_VALUE | READ_CONTROL | KEY_WOW64_64KEY | (provision ? KEY_SET_VALUE : 0), &key)) return ERROR_ACCESS_DENIED; struct CloseKey { HKEY h; ~CloseKey() { RegCloseKey(h); } } closeKey{key}; if (!protectedCredentialKey(key, service)) return ERROR_ACCESS_DENIED; const auto previous = credential_contract::load(key); auto store = credential_contract::validateStore(previous); auto &records = store.object.at("records").array; const auto selected = credential_contract::selectRecord(metadata, records); if (provision) { if (!acceptance_contract::sha(release_contract::str( request.object.at("expectedPreviousSHA"))) || release_contract::digest(previous) != release_contract::str(request.object.at("expectedPreviousSHA"))) return ERROR_ACCESS_DENIED; auto record = metadata; release_contract::Json cipher; cipher.kind = release_contract::Json::String; cipher.string = credential_contract::protect( request.object.at("token").string, metadata); record.object["protectedToken"] = cipher; credential_contract::replaceRecord(records, record); const auto candidate = release_contract::canonical(store); credential_contract::validateStore(candidate); if (RegSetValueExW(key, L"ManagementCredentials", 0, REG_BINARY, reinterpret_cast(candidate.data()), static_cast(candidate.size())) || RegFlushKey(key) || credential_contract::load(key) != candidate) return ERROR_ACCESS_DENIED; return boundedStdioWrite("{\"persisted\":true,\"stateSha256\":" + release_contract::escaped( release_contract::digest(candidate)) + "}") ? 0 : ERROR_ACCESS_DENIED; } if (selected) { const auto &record = *selected; auto bound = record; bound.object.erase("protectedToken"); std::string token = credential_contract::unprotect( release_contract::str(record.object.at("protectedToken")), bound); auto response = request; release_contract::Json secret; secret.kind = release_contract::Json::String; secret.string = token; response.object["token"] = secret; std::string reply = release_contract::canonical(response); SecureZeroMemory(token.data(), token.size()); SecureZeroMemory(secret.string.data(), secret.string.size()); SecureZeroMemory(response.object.at("token").string.data(), response.object.at("token").string.size()); bool okay = reply.size() <= 8192 && boundedStdioWrite(reply); SecureZeroMemory(reply.data(), reply.size()); return okay ? 0 : ERROR_ACCESS_DENIED; } return ERROR_ACCESS_DENIED; } catch (...) { return ERROR_ACCESS_DENIED; } } static int commitAcceptance() { try { const auto root = rootPath(); if (!serviceIdentity()) return ERROR_ACCESS_DENIED; auto release = trustedRelease(root); std::unique_ptr parent(parentProcess(GetCurrentProcess())); if (!parent || !serviceIdentity(*parent) || !verifiedImage(GetCurrentProcess(), root, "safetynet-service-host.exe", release) || !verifiedImage(*parent, root, "resources/broker/node.exe", release) || !sameUserSession(GetCurrentProcess(), *parent, true)) return ERROR_ACCESS_DENIED; DWORD size = GetEnvironmentVariableA("SAFETYNET_SERVICE_CLIENT_SID", nullptr, 0); if (!size || size > 256) return ERROR_ACCESS_DENIED; std::string sid(size, '\0'); if (!GetEnvironmentVariableA("SAFETYNET_SERVICE_CLIENT_SID", sid.data(), size)) return ERROR_ACCESS_DENIED; sid.resize(size - 1); std::vector frameBytes; if (!boundedStdioRead(GetStdHandle(STD_INPUT_HANDLE), frameBytes, 2097152)) return ERROR_ACCESS_DENIED; std::string requestText(frameBytes.begin(), frameBytes.end()); release_contract::Parser parser{requestText}; auto request = parser.parse(); if (parser.offset != requestText.size() || !release_contract::exact(request, {"expectedPreviousSHA", "candidateState"}) || !acceptance_contract::sha( release_contract::str(request.object.at("expectedPreviousSHA")))) return ERROR_ACCESS_DENIED; auto candidateText = release_contract::canonical(request.object.at("candidateState")); auto candidate = acceptance_contract::validate(candidateText); auto service = serviceSid(); if (service.empty()) return ERROR_ACCESS_DENIED; LPWSTR serviceText = nullptr; if (!ConvertSidToStringSidW(service.data(), &serviceText)) return ERROR_ACCESS_DENIED; std::wstring security = L"D:P(A;;RC;;;OW)(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;" + std::wstring(serviceText) + L")"; LocalFree(serviceText); PSECURITY_DESCRIPTOR descriptor = nullptr; if (!ConvertStringSecurityDescriptorToSecurityDescriptorW( security.c_str(), SDDL_REVISION_1, &descriptor, nullptr)) return ERROR_ACCESS_DENIED; SECURITY_ATTRIBUTES attributes{sizeof(attributes), descriptor, FALSE}; Handle mutex( CreateMutexW(&attributes, FALSE, L"Global\\SafetyNet.Acceptance.v1")); LocalFree(descriptor); if (!mutex.h || !ownedAcceptanceMutex(mutex, service) || WaitForSingleObject(mutex, 15000) != WAIT_OBJECT_0) return ERROR_ACCESS_DENIED; // No commit is attempted on an abandoned mutex: a prior writer may have // completed its value write without returning a durable receipt. struct Unlock { HANDLE value; ~Unlock() { ReleaseMutex(value); } } unlock{mutex.h}; auto floor = trustFloor(); auto old = acceptance_contract::validate(floor.stateCanonical); if (release_contract::digest(floor.stateCanonical) != release_contract::str(request.object.at("expectedPreviousSHA")) || !acceptance_contract::transition(old, candidate)) return ERROR_ACCESS_DENIED; release = trustedRelease(root); auto assignment = release_contract::deployment( root, release, sid, floor.deployment, floor.deploymentDigest); auto releaseJson = release_contract::signedPayload( root + L"\\release-envelope.json", release_contract::unhex(RELEASE_ANCHOR_XY), std::string("SafetyNet Windows release v1\0", sizeof("SafetyNet Windows release v1\0") - 1)); auto deploymentJson = release_contract::signedPayload( root + L"\\deployment-envelope.json", release_contract::customerKey(release.customerPem), std::string("SafetyNet Windows deployment v1\0", sizeof("SafetyNet Windows deployment v1\0") - 1), 262144); if (release_contract::number(candidate.object.at("release").object.at( "minimumSequence")) != release.sequence || release_contract::str( candidate.object.at("release").object.at("acceptedDigest")) != release_contract::digest( release_contract::canonical(releaseJson)) || release_contract::number( candidate.object.at("deployment").object.at("minimumSequence")) != assignment.deploymentSequence || release_contract::str( candidate.object.at("deployment").object.at("acceptedDigest")) != release_contract::digest( release_contract::canonical(deploymentJson))) return ERROR_ACCESS_DENIED; auto key = release_contract::pemDer(assignment.policyPem); std::string policyKeyHash = release_contract::digest(std::string(key.begin(), key.end())); const std::string ownId = sid + "|" + assignment.deviceId + "|" + policyKeyHash; std::map previous; for (const auto &record : old.object.at("policies").array) previous.emplace(acceptance_contract::identity(record), &record); bool hasOwn = false; for (const auto &record : candidate.object.at("policies").array) { auto id = acceptance_contract::identity(record); if (id == ownId) { hasOwn = true; if (release_contract::number(record.object.at("minimumVersion")) < assignment.minimumVersion) return ERROR_ACCESS_DENIED; } else { auto found = previous.find(id); if (found == previous.end() || release_contract::canonical(*found->second) != release_contract::canonical(record)) return ERROR_ACCESS_DENIED; } } if (!hasOwn) return ERROR_ACCESS_DENIED; HKEY registry = nullptr; if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\SafetyNet\\Trust", 0, KEY_SET_VALUE | KEY_QUERY_VALUE | KEY_WOW64_64KEY, ®istry) != ERROR_SUCCESS) return ERROR_ACCESS_DENIED; // One canonical value, flushed before acknowledgment. These APIs are NOT // exercised by the uninstalled tests. Caller must have verified the actual // signed policy through service-acceptance before asking to commit. DWORD result = RegSetValueExW(registry, L"AcceptanceState", 0, REG_BINARY, reinterpret_cast(candidateText.data()), DWORD(candidateText.size())); if (result == ERROR_SUCCESS) result = RegFlushKey(registry); RegCloseKey(registry); if (result != ERROR_SUCCESS) return ERROR_ACCESS_DENIED; auto committed = trustFloor(); if (committed.stateCanonical != candidateText) return ERROR_ACCESS_DENIED; return boundedStdioWrite("{\"persisted\":true,\"stateSha256\":" + release_contract::escaped( release_contract::digest(candidateText)) + "}") ? 0 : ERROR_ACCESS_DENIED; } catch (...) { return ERROR_ACCESS_DENIED; } } static bool serve(HANDLE pipe, const std::wstring &root) { Handle clientProcess; if (!pipeClient(pipe, root, &clientProcess.h) || !resources(root) || !serviceIdentity()) return false; try { auto release = trustedRelease(root); auto floor = trustFloor(); release_contract::deployment(root, release, currentSid(clientProcess), floor.deployment, floor.deploymentDigest); } catch (...) { return false; } Handle job(CreateJobObjectW(nullptr, nullptr)); JOBOBJECT_EXTENDED_LIMIT_INFORMATION limits{}; limits.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; if (!job.h || !SetInformationJobObject(job, JobObjectExtendedLimitInformation, &limits, sizeof(limits))) return false; SECURITY_ATTRIBUTES sa{sizeof(sa), nullptr, TRUE}; Handle inputRead, inputWrite, outputRead, outputWrite, nul(CreateFileW(L"NUL", GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, OPEN_EXISTING, 0, nullptr)); if (!CreatePipe(&inputRead.h, &inputWrite.h, &sa, 0) || !CreatePipe(&outputRead.h, &outputWrite.h, &sa, 0) || nul.h == INVALID_HANDLE_VALUE) return false; SetHandleInformation(inputWrite, HANDLE_FLAG_INHERIT, 0); SetHandleInformation(outputRead, HANDLE_FLAG_INHERIT, 0); SIZE_T bytes = 0; InitializeProcThreadAttributeList(nullptr, 1, 0, &bytes); std::vector attributes(bytes); STARTUPINFOEXW startup{}; startup.StartupInfo.cb = sizeof(startup); startup.lpAttributeList = reinterpret_cast(attributes.data()); if (!InitializeProcThreadAttributeList(startup.lpAttributeList, 1, 0, &bytes)) return false; HANDLE inherited[] = {inputRead.h, outputWrite.h, nul.h}; bool configured = UpdateProcThreadAttribute(startup.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, inherited, sizeof(inherited), nullptr, nullptr) != FALSE; startup.StartupInfo.dwFlags = STARTF_USESTDHANDLES; startup.StartupInfo.hStdInput = inputRead; startup.StartupInfo.hStdOutput = outputWrite; startup.StartupInfo.hStdError = nul; std::wstring executable = root + L"\\resources\\broker\\node.exe", command = L"\"" + executable + L"\" \"" + root + L"\\resources\\broker\\apps\\network-" L"broker\\service-entry.cjs\" --service-stdio", env = environment(currentSid(clientProcess)); PROCESS_INFORMATION information{}; BOOL launched = configured && CreateProcessW( executable.c_str(), command.data(), nullptr, nullptr, TRUE, CREATE_SUSPENDED | CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT | EXTENDED_STARTUPINFO_PRESENT, env.data(), root.c_str(), &startup.StartupInfo, &information); DeleteProcThreadAttributeList(startup.lpAttributeList); if (!launched) return false; Handle process(information.hProcess), thread(information.hThread); if (!AssignProcessToJobObject(job, process)) { TerminateProcess(process, 1); WaitForSingleObject(process, 5000); return false; } CloseHandle(inputRead.h); inputRead.h = nullptr; CloseHandle(outputWrite.h); outputWrite.h = nullptr; if (ResumeThread(thread) == DWORD(-1)) { TerminateJobObject(job, 1); WaitForSingleObject(process, 5000); return false; } // Native relay carries framed data only. Typed START and v1 sequence/receipt // validation belongs to the reviewed constant Node service-stdio adapter. Handle serveThread; if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &serveThread.h, THREAD_TERMINATE, FALSE, 0)) { TerminateJobObject(job, 1); return false; } std::atomic writeDeadline{0}, readDeadline{0}; std::atomic good{true}; std::thread watchdog([&] { while (good) { if (WaitForSingleObject(stopEvent, 50) == WAIT_OBJECT_0 || WaitForSingleObject(clientProcess, 0) != WAIT_TIMEOUT || (writeDeadline.load() != 0 && GetTickCount64() >= writeDeadline.load()) || (readDeadline.load() != 0 && GetTickCount64() >= readDeadline.load())) { good = false; TerminateJobObject(job, 1); CancelSynchronousIo(serveThread); CancelIoEx(pipe, nullptr); break; } } }); std::thread outgoing([&] { while (good) { DWORD size = 0, done = 0; if (!ReadFile(outputRead, &size, 4, &done, nullptr) || !done) { good = false; break; } readDeadline = GetTickCount64() + 15000; DWORD headerOffset = done; while (headerOffset < 4) { if (!ReadFile(outputRead, reinterpret_cast(&size) + headerOffset, 4 - headerOffset, &done, nullptr) || !done) { good = false; break; } headerOffset += done; } if (!good || !size || size > 65536) { good = false; break; } std::vector value(size); DWORD offset = 0; while (offset < size) { if (!ReadFile(outputRead, value.data() + offset, size - offset, &done, nullptr) || !done) { good = false; break; } offset += done; } if (!good || !frame(pipe, true, value, 65536)) { good = false; break; } readDeadline = 0; } CancelIoEx(pipe, nullptr); }); bool first = true; while (good && WaitForSingleObject(stopEvent, 0) == WAIT_TIMEOUT) { std::vector value; if (!frame(pipe, false, value, first ? 2097152 : 65536, first ? 15000 : INFINITE)) break; first = false; if (!writeChildFrame(inputWrite, value, writeDeadline)) break; } good = false; TerminateJobObject(job, 1); CancelSynchronousIo(outgoing.native_handle()); CancelIoEx(pipe, nullptr); outgoing.join(); watchdog.join(); return WaitForSingleObject(process, 5000) == WAIT_OBJECT_0; } static void report(DWORD state, DWORD error = 0) { SERVICE_STATUS status{}; status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; status.dwCurrentState = state; status.dwWin32ExitCode = error; status.dwControlsAccepted = state == SERVICE_RUNNING ? SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN : 0; status.dwWaitHint = state == SERVICE_STOP_PENDING ? 5000 : 0; SetServiceStatus(statusHandle, &status); } static DWORD WINAPI control(DWORD code, DWORD, void *, void *) { if (code == SERVICE_CONTROL_STOP || code == SERVICE_CONTROL_SHUTDOWN) { report(SERVICE_STOP_PENDING); SetEvent(stopEvent); } return NO_ERROR; } static void WINAPI serviceMain(DWORD, wchar_t **) { statusHandle = RegisterServiceCtrlHandlerExW(SERVICE_NAME, control, nullptr); if (!statusHandle) return; report(SERVICE_START_PENDING); Handle stop(CreateEventW(nullptr, TRUE, FALSE, nullptr)); stopEvent = stop; std::wstring root = rootPath(); if (!stop.h || !serviceIdentity() || !resources(root)) { report(SERVICE_STOPPED, ERROR_ACCESS_DENIED); return; } PSECURITY_DESCRIPTOR security = nullptr; if (!ConvertStringSecurityDescriptorToSecurityDescriptorW( L"D:P(A;;GA;;;SY)(A;;0x0012019b;;;AU)", SDDL_REVISION_1, &security, nullptr)) { report(SERVICE_STOPPED, ERROR_ACCESS_DENIED); return; } SECURITY_ATTRIBUTES sa{sizeof(sa), security, FALSE}; Handle pipe(CreateNamedPipeW(PIPE_NAME, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS, 1, 65536, 65536, 15000, &sa)); LocalFree(security); if (pipe.h == INVALID_HANDLE_VALUE) { report(SERVICE_STOPPED, ERROR_ACCESS_DENIED); return; } report(SERVICE_RUNNING); while (WaitForSingleObject(stopEvent, 0) == WAIT_TIMEOUT) { Handle event(CreateEventW(nullptr, TRUE, FALSE, nullptr)); OVERLAPPED ov{}; ov.hEvent = event; BOOL connected = ConnectNamedPipe(pipe, &ov); DWORD code = connected ? ERROR_SUCCESS : GetLastError(); if (code == ERROR_IO_PENDING) { HANDLE events[] = {event.h, stopEvent}; if (WaitForMultipleObjects(2, events, FALSE, INFINITE) != WAIT_OBJECT_0) { CancelIoEx(pipe, &ov); WaitForSingleObject(event, INFINITE); break; } DWORD bytes = 0; connected = GetOverlappedResult(pipe, &ov, &bytes, FALSE); } else connected = code == ERROR_PIPE_CONNECTED; if (connected) serve(pipe, root); DisconnectNamedPipe(pipe); } report(SERVICE_STOPPED); } #ifdef SAFETYNET_NATIVE_SELF_TEST static bool ownerRightsTest() { auto user = currentSid(GetCurrentProcess()); std::wstring sid(user.begin(), user.end()); std::wstring security = L"D:P(A;;0x00120001;;;" + sid + L")(A;;RC;;;OW)"; PSECURITY_DESCRIPTOR descriptor = nullptr; if (!ConvertStringSecurityDescriptorToSecurityDescriptorW( security.c_str(), SDDL_REVISION_1, &descriptor, nullptr)) return false; SECURITY_ATTRIBUTES attributes{sizeof(attributes), descriptor, FALSE}; auto name = L"Local\\SafetyNet.OwnerRights.Proof." + std::to_wstring(GetCurrentProcessId()); Handle mutex(CreateMutexW(&attributes, FALSE, name.c_str())); LocalFree(descriptor); if (!mutex.h) return false; Handle denied(OpenMutexW(WRITE_DAC, FALSE, name.c_str())); DWORD deniedCode = GetLastError(); if (denied.h || deniedCode != ERROR_ACCESS_DENIED) return false; Handle allowed(OpenMutexW(SYNCHRONIZE | MUTEX_MODIFY_STATE | READ_CONTROL, FALSE, name.c_str())); if (!allowed.h) return false; PSECURITY_DESCRIPTOR actual = nullptr; PSID owner = nullptr; PACL dacl = nullptr; if (GetSecurityInfo(allowed, SE_KERNEL_OBJECT, OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, &owner, nullptr, &dacl, nullptr, &actual) != ERROR_SUCCESS) return false; PSID expected = nullptr; ConvertStringSidToSidA(user.c_str(), &expected); PSID ownerRights = nullptr; ConvertStringSidToSidW(L"S-1-3-4", &ownerRights); bool valid = owner && expected && EqualSid(owner, expected); unsigned count = 0; if (valid && dacl) for (DWORD i = 0; i < dacl->AceCount; i++) { void *raw = nullptr; if (!GetAce(dacl, i, &raw)) { valid = false; break; } auto header = static_cast(raw); if (header->AceType == ACCESS_ALLOWED_ACE_TYPE) { auto ace = static_cast(raw); if (EqualSid(&ace->SidStart, ownerRights)) { count++; if (ace->Mask != READ_CONTROL) valid = false; } } } if (expected) LocalFree(expected); if (ownerRights) LocalFree(ownerRights); if (actual) LocalFree(actual); return valid && count == 1; } static bool writeDeadlineTest() { Handle read, write; if (!CreatePipe(&read.h, &write.h, nullptr, 4096)) return false; std::atomic deadline{0}; std::vector samplePayload(16, 42); if (!writeChildFrame(write, samplePayload, deadline, 30) || deadline.load() != 0) return false; DWORD done = 0; std::array consumed{}; if (!ReadFile(read, consumed.data(), 20, &done, nullptr) || done != 20) return false; Sleep(60); if (deadline.load() != 0) return false; // healthy idle exceeds test budget std::atomic result{true}; std::vector stalledPayload(262144, 43); std::thread blocked( [&] { result = writeChildFrame(write, stalledPayload, deadline, 30); }); for (int i = 0; i < 100 && deadline.load() == 0; i++) Sleep(1); Sleep(60); if (deadline.load() == 0) { CancelSynchronousIo(blocked.native_handle()); blocked.join(); return false; } if (!CancelSynchronousIo(blocked.native_handle())) { CloseHandle(read.h); read.h = nullptr; } blocked.join(); return !result && deadline.load() != 0; } static bool pipeNegativeTest() { std::wstring name = L"\\\\.\\pipe\\SafetyNet.NativeTest." + std::to_wstring(GetCurrentProcessId()); PSECURITY_DESCRIPTOR security = nullptr; if (!ConvertStringSecurityDescriptorToSecurityDescriptorW( L"D:P(A;;GA;;;SY)(A;;0x0012019b;;;AU)", SDDL_REVISION_1, &security, nullptr)) return false; SECURITY_ATTRIBUTES sa{sizeof(sa), security, FALSE}; Handle server(CreateNamedPipeW(name.c_str(), PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS, 2, 4096, 4096, 1000, &sa)); LocalFree(security); if (server.h == INVALID_HANDLE_VALUE) return false; // Attempt a second instance WITHOUT FIRST_PIPE_INSTANCE: DACL rather than // creation-flag coincidence must deny FILE_CREATE_PIPE_INSTANCE to this user. Handle attacker(CreateNamedPipeW(name.c_str(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT, 2, 4096, 4096, 1000, nullptr)); if (attacker.h != INVALID_HANDLE_VALUE || GetLastError() != ERROR_ACCESS_DENIED) return false; Handle client(CreateFileW(name.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr)); if (client.h == INVALID_HANDLE_VALUE) return false; ULONG actualServerPid = 0; if (!GetNamedPipeServerProcessId(client, &actualServerPid) || actualServerPid != GetCurrentProcessId()) return false; Handle actualServer(OpenProcess( PROCESS_QUERY_LIMITED_INFORMATION | SYNCHRONIZE, FALSE, actualServerPid)); if (!actualServer.h || serviceIdentity(actualServer)) return false; Handle event(CreateEventW(nullptr, TRUE, FALSE, nullptr)); OVERLAPPED ov{}; ov.hEvent = event; BOOL connected = ConnectNamedPipe(server, &ov); if (!connected && GetLastError() != ERROR_PIPE_CONNECTED) return false; if (pipeClient(server, rootPath())) return false; DWORD invalid = 0xffffffff, done = 0; if (!WriteFile(client, &invalid, 4, &done, nullptr) || done != 4) return false; std::vector frameBytes; return !frame(server, false, frameBytes, 65536, 1000); } static int selfTest() { Handle stop(CreateEventW(nullptr, TRUE, FALSE, nullptr)); stopEvent = stop; if (!ownerRightsTest()) return 84; if (!pipeNegativeTest()) return 89; if (!writeDeadlineTest()) return 88; if (serviceIdentity()) return 90; Handle job(CreateJobObjectW(nullptr, nullptr)); JOBOBJECT_EXTENDED_LIMIT_INFORMATION limits{}; limits.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; if (!SetInformationJobObject(job, JobObjectExtendedLimitInformation, &limits, sizeof(limits))) return 91; auto root = rootPath(); std::wstring command = L"\"" + root + L"\\safetynet-service-host-test.exe\" --job-child"; STARTUPINFOW startup{}; startup.cb = sizeof(startup); PROCESS_INFORMATION information{}; if (!CreateProcessW(nullptr, command.data(), nullptr, nullptr, FALSE, CREATE_SUSPENDED | CREATE_NO_WINDOW, nullptr, root.c_str(), &startup, &information)) return 92; Handle process(information.hProcess), thread(information.hThread); if (!AssignProcessToJobObject(job, process)) return 93; BOOL member = FALSE; if (!IsProcessInJob(process, job, &member) || !member) return 94; ResumeThread(thread); Handle descendant; for (int attempt = 0; attempt < 100 && !descendant.h; attempt++) { Handle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)); PROCESSENTRY32W item{}; item.dwSize = sizeof(item); if (Process32FirstW(snapshot, &item)) do { if (item.th32ParentProcessID == information.dwProcessId) { descendant.h = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_LIMITED_INFORMATION, FALSE, item.th32ProcessID); break; } } while (Process32NextW(snapshot, &item)); if (!descendant.h) Sleep(20); } if (!descendant.h || !IsProcessInJob(descendant, job, &member) || !member) return 98; if (WaitForSingleObject(process, 50) != WAIT_TIMEOUT) return 95; CloseHandle(job.h); job.h = nullptr; if (WaitForSingleObject(process, 5000) != WAIT_OBJECT_0 || WaitForSingleObject(descendant, 5000) != WAIT_OBJECT_0) return 96; if (hashFile( root + L"\\safetynet-service-host-test.exe", "0000000000000000000000000000000000000000000000000000000000000000")) return 97; puts("{\"ownerWriteDacDenied\":true,\"ownerReadSyncModifyAllowed\":true," "\"healthyIdleWriteDeadlineCleared\":true,\"stalledWriteCancelled\":" "true,\"sameConnectedHandleServerIdentified\":true," "\"wrongServerServiceIdentityDenied\":true,\"pipeSecondInstanceDenied\":" "true,\"unauthorizedClientDenied\":true,\"oversizedFrameDenied\":true," "\"serviceIdentityRejected\":true,\"jobMembership\":true," "\"descendantJobMembership\":true,\"killOnCloseTerminal\":true," "\"wrongHashRejected\":true}"); return 0; } #endif int wmain(int argc, wchar_t **argv) { #ifdef SAFETYNET_NATIVE_SELF_TEST if (argc == 2 && !wcscmp(argv[1], L"--verify-credential-selection")) return credential_contract::selectionSelfTest() ? 0 : 86; if (argc == 2 && !wcscmp(argv[1], L"--verify-state-fixture")) { try { auto old = acceptance_contract::validate( release_contract::read(rootPath() + L"\\acceptance-old.json")); auto next = acceptance_contract::validate( release_contract::read(rootPath() + L"\\acceptance-candidate.json")); return acceptance_contract::transition(old, next) ? 0 : 86; } catch (...) { return 86; } } if (argc == 2 && !wcscmp(argv[1], L"--verify-equivocation")) { try { release_contract::release(rootPath(), release_contract::unhex(RELEASE_ANCHOR_XY), 2, std::string(64, '0')); return 85; } catch (...) { return 86; } } if (argc == 2 && !wcscmp(argv[1], L"--verify-fixture")) { try { auto manifest = release_contract::release( rootPath(), release_contract::unhex(RELEASE_ANCHOR_XY), 1); auto assignment = release_contract::deployment(rootPath(), manifest, "S-1-5-21-1-2-3-1001", 1); if (assignment.minimumVersion != 3 || !hashFile( rootPath() + L"\\safetynet-service-host-test.exe", manifest.hashes.at("safetynet-service-host-test.exe").c_str())) return 87; puts("{\"nativeVendorSignatureVerified\":true," "\"nativeDelegatedCustomerSignatureVerified\":true," "\"nativeSidAssignmentVerified\":true}"); return 0; } catch (...) { return 86; } } if (argc == 2 && !wcscmp(argv[1], L"--self-test")) return selfTest(); if (argc == 2 && !wcscmp(argv[1], L"--job-grandchild")) { Sleep(INFINITE); return 0; } if (argc == 2 && !wcscmp(argv[1], L"--job-child")) { std::wstring command = L"\"" + rootPath() + L"\\safetynet-service-host-test.exe\" --job-grandchild"; STARTUPINFOW startup{}; startup.cb = sizeof(startup); PROCESS_INFORMATION info{}; if (!CreateProcessW(nullptr, command.data(), nullptr, nullptr, FALSE, CREATE_NO_WINDOW, nullptr, nullptr, &startup, &info)) return 99; CloseHandle(info.hProcess); CloseHandle(info.hThread); Sleep(INFINITE); return 0; } #endif if (argc == 2 && !wcscmp(argv[1], L"--client-stdio")) return clientStdio(); if (argc == 2 && !wcscmp(argv[1], L"--trust-snapshot")) return trustSnapshot(); if (argc == 2 && !wcscmp(argv[1], L"--topology-snapshot")) return topologySnapshot(); if (argc == 2 && !wcscmp(argv[1], L"--commit-acceptance")) return commitAcceptance(); if (argc == 2 && !wcscmp(argv[1], L"--management-credential")) return managementCredential(false); if (argc == 2 && !wcscmp(argv[1], L"--provision-management-credential")) return managementCredential(true); if (argc != 1) return ERROR_INVALID_PARAMETER; SERVICE_TABLE_ENTRYW table[] = { {const_cast(SERVICE_NAME), serviceMain}, {nullptr, nullptr}}; return StartServiceCtrlDispatcherW(table) ? 0 : int(GetLastError()); }