// Init service-configuration parser. Malformed or ambiguous service policy is rejected at boot. #include "service_config.h" #include #include #include #include #define INIT_SERVICE_KEY_IMAGE 0x00000002u #define INIT_SERVICE_KEY_START 0x00000004u #define INIT_SERVICE_KEY_CRITICAL 0x00000008u #define INIT_SERVICE_KEY_RESTART 0x00000010u #define INIT_SERVICE_KEY_READY_TIMEOUT 0x00000020u #define INIT_SERVICE_KEY_STOP_TIMEOUT 0x00000040u #define INIT_SERVICE_KEY_REQUIRES 0x00000080u #define INIT_SERVICE_KEY_GRANTS 0x00000100u #define INIT_SERVICE_KEY_EXPORTS 0x00000200u #define INIT_SERVICE_REQUIRED_KEYS 0x000003FEu typedef struct INIT_PARSED_SERVICE { INIT_SERVICE_DESCRIPTOR Descriptor; char DependencyIds[INIT_SERVICE_DEPENDENCY_MAX][INIT_SERVICE_ID_MAX + 1u]; uint32_t DependencyCount; uint32_t PresentKeys; uint32_t SectionLine; } INIT_PARSED_SERVICE; static char gServicesIniBuffer[INIT_SERVICES_MAX_FILE_BYTES + 1u]; static INIT_PARSED_SERVICE gParsedServices[INIT_SERVICE_MAX_COUNT]; // Returns whether one byte is horizontal configuration whitespace. static bool is_space(char c) { return c == ' ' || c == '\t' || c == '\r'; } // Trims leading horizontal whitespace in place by returning the first content byte. static char* trim_left(char* text) { while (*text && is_space(*text)) ++text; return text; } // Trims trailing horizontal whitespace from one mutable string. static void trim_right(char* text) { char* end = text + strlen(text); while (end > text && is_space(end[-1])) *--end = '\0'; } // Returns whether one service identifier byte belongs to the deliberately small grammar. static bool is_service_id_char(char c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '-' || c == '.'; } // Validates a case-sensitive service identifier used by sections and dependencies. static bool validate_service_id(const char* id) { size_t length = id ? strlen(id) : 0; if (length == 0 || length > INIT_SERVICE_ID_MAX) return false; for (size_t i = 0; i < length; ++i) if (!is_service_id_char(id[i])) return false; return true; } // Validates the capability-relative native image path accepted by the process loader. static bool validate_image_path(const char* path) { size_t length = path ? strlen(path) : 0; if (length == 0 || length >= SYS_PATH_MAX || path[0] == '/' || path[length - 1u] == '/' || !SysSvIsUtf8Text(SysSvFromParts(path, length))) return false; const char* component = path; for (size_t i = 0; i <= length; ++i) { char c = path[i]; if (c == '\\' || c == ':') return false; if (c != '/' && c != '\0') continue; size_t componentLength = (size_t)(&path[i] - component); if (componentLength == 0 || (componentLength == 1 && component[0] == '.') || (componentLength == 2 && component[0] == '.' && component[1] == '.')) return false; component = &path[i + 1u]; } return true; } // Copies one bounded configuration string into fixed init-owned storage. static bool copy_bounded(char* destination, size_t capacity, const char* source) { size_t length = source ? strlen(source) : 0; if (!destination || capacity == 0 || length >= capacity) return false; memcpy(destination, source, length + 1u); return true; } // Parses one strict lower-case boolean. static bool parse_bool(const char* text, bool* valueOut) { if (!text || !valueOut) return false; if (strcmp(text, "true") == 0) { *valueOut = true; return true; } if (strcmp(text, "false") == 0) { *valueOut = false; return true; } return false; } // Parses one bounded unsigned decimal integer without signs or suffixes. static bool parse_u32(const char* text, uint32_t minimum, uint32_t maximum, uint32_t* valueOut) { if (!text || !*text || !valueOut) return false; uint64_t value = 0; for (const char* p = text; *p; ++p) { if (*p < '0' || *p > '9') return false; value = value * 10u + (uint32_t)(*p - '0'); if (value > maximum) return false; } if (value < minimum) return false; *valueOut = (uint32_t)value; return true; } // Looks up a parsed service by its case-sensitive identifier. static int32_t find_parsed_service(const INIT_PARSED_SERVICE* services, uint32_t serviceCount, const char* id) { for (uint32_t i = 0; i < serviceCount; ++i) if (strcmp(services[i].Descriptor.Id, id) == 0) return (int32_t)i; return -1; } // Parses the comma-separated hard dependency list for one service. static bool parse_requires(char* value, INIT_PARSED_SERVICE* service) { service->DependencyCount = 0; if (!*value) return true; char* cursor = value; for (;;) { char* comma = strchr(cursor, ','); if (comma) *comma = '\0'; char* id = trim_left(cursor); trim_right(id); if (!validate_service_id(id) || service->DependencyCount >= INIT_SERVICE_DEPENDENCY_MAX) return false; for (uint32_t i = 0; i < service->DependencyCount; ++i) if (strcmp(service->DependencyIds[i], id) == 0) return false; if (!copy_bounded(service->DependencyIds[service->DependencyCount], sizeof(service->DependencyIds[0]), id)) return false; ++service->DependencyCount; if (!comma) break; cursor = comma + 1; if (!*cursor) return false; } return true; } // Parses explicit capability-source names without associating them with service roles. static bool parse_grants(char* value, INIT_PARSED_SERVICE* service) { service->Descriptor.GrantCount = 0; if (!*value) return true; char* cursor = value; for (;;) { char* comma = strchr(cursor, ','); if (comma) *comma = '\0'; char* name = trim_left(cursor); trim_right(name); size_t length = strlen(name); if (length == 0 || length > INIT_SERVICE_GRANT_NAME_MAX || service->Descriptor.GrantCount >= INIT_SERVICE_GRANT_MAX) return false; for (size_t i = 0; i < length; ++i) if (!is_service_id_char(name[i])) return false; if (!strchr(name, '.') || name[0] == '.' || name[length - 1u] == '.') return false; if (strcmp(name, "service.control") == 0 || strncmp(name, "publish.", 8u) == 0) return false; for (uint32_t i = 0; i < service->Descriptor.GrantCount; ++i) if (strcmp(service->Descriptor.Grants[i], name) == 0) return false; if (!copy_bounded(service->Descriptor.Grants[service->Descriptor.GrantCount], sizeof(service->Descriptor.Grants[0]), name)) return false; ++service->Descriptor.GrantCount; if (!comma) break; cursor = comma + 1; if (!*cursor) return false; } return true; } // Reads the declared READY export names, which are an exact startup contract. static bool parse_exports(char* value, INIT_PARSED_SERVICE* service) { service->Descriptor.ExportCount = 0; if (!*value) return true; char* cursor = value; for (;;) { char* comma = strchr(cursor, ','); if (comma) *comma = '\0'; char* name = trim_left(cursor); trim_right(name); if (!NtlServiceExportNameValid(name) || service->Descriptor.ExportCount >= INIT_SERVICE_EXPORT_MAX) return false; for (uint32_t i = 0; i < service->Descriptor.ExportCount; ++i) if (strcmp(name, service->Descriptor.Exports[i]) == 0) return false; if (!copy_bounded(service->Descriptor.Exports[service->Descriptor.ExportCount], sizeof(service->Descriptor.Exports[0]), name)) return false; ++service->Descriptor.ExportCount; if (!comma) break; cursor = comma + 1; if (!*cursor) return false; } return true; } // Applies one known key to the current service and rejects duplicates or invalid values. static bool parse_service_key(INIT_PARSED_SERVICE* service, char* key, char* value) { uint32_t bit = 0; if (strcmp(key, "image") == 0) { bit = INIT_SERVICE_KEY_IMAGE; if (!validate_image_path(value) || !copy_bounded(service->Descriptor.ImagePath, sizeof(service->Descriptor.ImagePath), value)) return false; } else if (strcmp(key, "start") == 0) { bit = INIT_SERVICE_KEY_START; if (strcmp(value, "auto") == 0) service->Descriptor.StartPolicy = InitServiceStartAuto; else if (strcmp(value, "disabled") == 0) service->Descriptor.StartPolicy = InitServiceStartDisabled; else return false; } else if (strcmp(key, "critical") == 0) { bit = INIT_SERVICE_KEY_CRITICAL; if (!parse_bool(value, &service->Descriptor.Critical)) return false; } else if (strcmp(key, "restart") == 0) { bit = INIT_SERVICE_KEY_RESTART; if (strcmp(value, "never") == 0) service->Descriptor.RestartPolicy = InitServiceRestartNever; else if (strcmp(value, "on-failure") == 0) service->Descriptor.RestartPolicy = InitServiceRestartOnFailure; else return false; } else if (strcmp(key, "ready_timeout_ms") == 0) { bit = INIT_SERVICE_KEY_READY_TIMEOUT; if (!parse_u32(value, 1u, 600000u, &service->Descriptor.ReadyTimeoutMilliseconds)) return false; } else if (strcmp(key, "stop_timeout_ms") == 0) { bit = INIT_SERVICE_KEY_STOP_TIMEOUT; if (!parse_u32(value, 1u, 600000u, &service->Descriptor.StopTimeoutMilliseconds)) return false; } else if (strcmp(key, "requires") == 0) { bit = INIT_SERVICE_KEY_REQUIRES; if (!parse_requires(value, service)) return false; } else if (strcmp(key, "grants") == 0) { bit = INIT_SERVICE_KEY_GRANTS; if (!parse_grants(value, service)) return false; } else if (strcmp(key, "exports") == 0) { bit = INIT_SERVICE_KEY_EXPORTS; if (!parse_exports(value, service)) return false; } else { return false; } if (service->PresentKeys & bit) return false; service->PresentKeys |= bit; return true; } // Parses the strict services.ini grammar into temporary fixed storage. static KSTATUS parse_services_ini(char* buffer, uint32_t* serviceCountOut, uint32_t* errorLineOut) { uint32_t serviceCount = 0; INIT_PARSED_SERVICE* current = NULL; uint32_t lineNumber = 0; char* line = buffer; while (*line) { ++lineNumber; char* end = strchr(line, '\n'); if (!end) end = line + strlen(line); char saved = *end; *end = '\0'; char* text = trim_left(line); trim_right(text); bool valid = true; if (!*text || *text == ';' || *text == '#') { // Blank and whole-line comments are the only ignored line forms. } else if (*text == '[') { size_t length = strlen(text); if (length < 11u || text[length - 1u] != ']' || strchr(text + 1, ']') != &text[length - 1u]) { valid = false; } else { text[length - 1u] = '\0'; const char prefix[] = "service."; if (strncmp(text + 1, prefix, sizeof(prefix) - 1u) != 0) { valid = false; } else { char* id = text + 1u + sizeof(prefix) - 1u; if (!validate_service_id(id) || serviceCount >= INIT_SERVICE_MAX_COUNT || find_parsed_service(gParsedServices, serviceCount, id) >= 0) { valid = false; } else { current = &gParsedServices[serviceCount++]; memset(current, 0, sizeof(*current)); current->SectionLine = lineNumber; if (!copy_bounded(current->Descriptor.Id, sizeof(current->Descriptor.Id), id)) valid = false; } } } } else { if (!current) { valid = false; } else { char* equals = strchr(text, '='); if (!equals || strchr(equals + 1, '=')) { valid = false; } else { *equals = '\0'; char* key = text; char* value = trim_left(equals + 1); trim_right(key); trim_right(value); if (!*key || !parse_service_key(current, key, value)) valid = false; } } } *end = saved; if (!valid) { if (errorLineOut) *errorLineOut = lineNumber; return NTLSTATUS_INVALID_PARAMETER; } line = saved ? end + 1u : end; } if (serviceCount == 0) return NTLSTATUS_INVALID_PARAMETER; *serviceCountOut = serviceCount; return NTLSTATUS_SUCCESS; } // Resolves dependency identifiers, validates invariants, and computes dependency-first order. static KSTATUS validate_services(uint32_t serviceCount, INIT_SERVICE_CONFIG* configOut, uint32_t* errorLineOut) { memset(configOut, 0, sizeof(*configOut)); static const char* const bootGrants[] = { NTL_BOOT_CAP_NAMESPACE_ROOT, NTL_BOOT_CAP_VOLUME_MANAGER, NTL_BOOT_CAP_INPUT_MANAGER, NTL_BOOT_CAP_DISPLAY_POLICY, NTL_BOOT_CAP_DISPLAY_PRESENT, NTL_BOOT_CAP_RESOURCE_REGISTRATION }; for (uint32_t i = 0; i < serviceCount; ++i) { INIT_SERVICE_DESCRIPTOR* descriptor = &gParsedServices[i].Descriptor; for (uint32_t g = 0; g < descriptor->GrantCount; ++g) { const char* name = descriptor->Grants[g]; bool known = false; for (uint32_t b = 0; b < sizeof(bootGrants) / sizeof(bootGrants[0]); ++b) if (strcmp(name, bootGrants[b]) == 0) known = true; if (known) continue; if (strncmp(name, "boot.", 5u) == 0) { if (errorLineOut) *errorLineOut = gParsedServices[i].SectionLine; return NTLSTATUS_INVALID_PARAMETER; } // Service export sources require an explicit dependency; the longest // matching service ID owns a qualified export name. int32_t provider = -1; size_t prefixLength = 0; for (uint32_t j = 0; j < serviceCount; ++j) { const char* id = gParsedServices[j].Descriptor.Id; size_t length = strlen(id); if (length > prefixLength && strncmp(name, id, length) == 0 && name[length] == '.' && name[length + 1u] != '\0') { provider = (int32_t)j; prefixLength = length; } } bool declaredDependency = false; if (provider >= 0 && (uint32_t)provider != i && gParsedServices[provider].Descriptor.StartPolicy == InitServiceStartAuto) { for (uint32_t d = 0; d < gParsedServices[i].DependencyCount; ++d) if (strcmp(gParsedServices[i].DependencyIds[d], gParsedServices[provider].Descriptor.Id) == 0) declaredDependency = true; } if (declaredDependency) { const char* exportName = name + prefixLength + 1u; bool declaredExport = false; const INIT_SERVICE_DESCRIPTOR* source = &gParsedServices[provider].Descriptor; for (uint32_t e = 0; e < source->ExportCount; ++e) if (strcmp(source->Exports[e], exportName) == 0) declaredExport = true; if (!declaredExport) declaredDependency = false; } if (!declaredDependency) { if (errorLineOut) *errorLineOut = gParsedServices[i].SectionLine; return NTLSTATUS_INVALID_PARAMETER; } } } for (uint32_t i = 0; i < serviceCount; ++i) { INIT_PARSED_SERVICE* parsed = &gParsedServices[i]; if (parsed->PresentKeys != INIT_SERVICE_REQUIRED_KEYS) { if (errorLineOut) *errorLineOut = parsed->SectionLine; return NTLSTATUS_INVALID_PARAMETER; } INIT_SERVICE_DESCRIPTOR* descriptor = &configOut->Services[i]; *descriptor = parsed->Descriptor; for (uint32_t e = 0; e < descriptor->ExportCount; ++e) { if (strlen(descriptor->Id) + 1u + strlen(descriptor->Exports[e]) > INIT_SERVICE_GRANT_NAME_MAX) { if (errorLineOut) *errorLineOut = parsed->SectionLine; return NTLSTATUS_NAME_TOO_LONG; } } descriptor->DependencyCount = parsed->DependencyCount; for (uint32_t d = 0; d < parsed->DependencyCount; ++d) { int32_t dependency = find_parsed_service(gParsedServices, serviceCount, parsed->DependencyIds[d]); if (dependency < 0 || (uint32_t)dependency == i) { if (errorLineOut) *errorLineOut = parsed->SectionLine; return NTLSTATUS_INVALID_PARAMETER; } descriptor->Dependencies[d] = (uint16_t)dependency; } } for (uint32_t i = 0; i < serviceCount; ++i) { INIT_SERVICE_DESCRIPTOR* descriptor = &configOut->Services[i]; if (descriptor->StartPolicy != InitServiceStartAuto) continue; for (uint32_t d = 0; d < descriptor->DependencyCount; ++d) { INIT_SERVICE_DESCRIPTOR* dependency = &configOut->Services[descriptor->Dependencies[d]]; if (dependency->StartPolicy == InitServiceStartDisabled) { if (errorLineOut) *errorLineOut = gParsedServices[i].SectionLine; return NTLSTATUS_INVALID_PARAMETER; } } } uint32_t indegree[INIT_SERVICE_MAX_COUNT] = {0}; bool emitted[INIT_SERVICE_MAX_COUNT] = {0}; for (uint32_t i = 0; i < serviceCount; ++i) indegree[i] = configOut->Services[i].DependencyCount; uint32_t emittedCount = 0; while (emittedCount < serviceCount) { int32_t next = -1; for (uint32_t i = 0; i < serviceCount; ++i) { if (!emitted[i] && indegree[i] == 0u) { next = (int32_t)i; break; } } if (next < 0) { if (errorLineOut) { for (uint32_t i = 0; i < serviceCount; ++i) { if (!emitted[i]) { *errorLineOut = gParsedServices[i].SectionLine; break; } } } return NTLSTATUS_DEADLOCK; } emitted[next] = true; if (configOut->Services[next].StartPolicy == InitServiceStartAuto) configOut->StartupOrder[configOut->StartupCount++] = (uint16_t)next; ++emittedCount; for (uint32_t i = 0; i < serviceCount; ++i) { if (emitted[i]) continue; INIT_SERVICE_DESCRIPTOR* descriptor = &configOut->Services[i]; for (uint32_t d = 0; d < descriptor->DependencyCount; ++d) { if (descriptor->Dependencies[d] == (uint16_t)next) { --indegree[i]; break; } } } } configOut->ServiceCount = serviceCount; if (configOut->StartupCount + 2u > SYS_WAIT_MANY_MAX_HANDLES) return NTLSTATUS_LIMIT_REACHED; return NTLSTATUS_SUCCESS; } // Reads the mandatory services.ini file from the bootstrap system volume. static KSTATUS read_services_ini(SYS_HANDLE systemVolume, size_t* sizeOut) { SYS_HANDLE file = SYS_HANDLE_INVALID; SYS_OPEN_FILE_AT_REQUEST open = SysMakeOpenFileAtRequest(systemVolume, SYS_SV_LITERAL(INIT_SERVICES_PATH), SYS_FILE_ACCESS_READ | SYS_FILE_ACCESS_QUERY, SYS_FILE_OPEN_EXISTING, SYS_FILE_FLAG_NONE, &file); KSTATUS status = SysOpenFileAt(&open); if (!KSUCCESS(status)) return status; uint64_t fileSize = 0; status = SysGetFileSize(file, &fileSize); if (!KSUCCESS(status)) { (void)SysCloseHandle(file); return status; } if (fileSize == 0u || fileSize > INIT_SERVICES_MAX_FILE_BYTES) { (void)SysCloseHandle(file); return fileSize > INIT_SERVICES_MAX_FILE_BYTES ? NTLSTATUS_LIMIT_REACHED : NTLSTATUS_INVALID_PARAMETER; } size_t total = 0; while (total < (size_t)fileSize) { size_t transferred = 0; SYS_FILE_IO_REQUEST read = SysMakeFileIoRequest(file, gServicesIniBuffer + total, (size_t)fileSize - total, &transferred); status = SysReadFile(&read); if (!KSUCCESS(status) || transferred == 0u) { (void)SysCloseHandle(file); return KSUCCESS(status) ? NTLSTATUS_FAILURE : status; } total += transferred; } (void)SysCloseHandle(file); for (size_t i = 0; i < total; ++i) if (gServicesIniBuffer[i] == '\0') return NTLSTATUS_INVALID_PARAMETER; gServicesIniBuffer[total] = '\0'; *sizeOut = total; return NTLSTATUS_SUCCESS; } // Loads, strictly parses, and validates services.ini beneath the bootstrap system volume. KSTATUS InitLoadServiceConfig(SYS_HANDLE systemVolume, INIT_SERVICE_CONFIG* configOut, uint32_t* errorLineOut) { if (systemVolume == SYS_HANDLE_INVALID || !configOut) return NTLSTATUS_INVALID_PARAMETER; if (errorLineOut) *errorLineOut = 0; memset(gParsedServices, 0, sizeof(gParsedServices)); size_t size = 0; KSTATUS status = read_services_ini(systemVolume, &size); if (!KSUCCESS(status)) return status; (void)size; uint32_t serviceCount = 0; status = parse_services_ini(gServicesIniBuffer, &serviceCount, errorLineOut); if (!KSUCCESS(status)) return status; return validate_services(serviceCount, configOut, errorLineOut); }