// Strict drivers.ini v2 parsing, validation and dependency evaluation. #include #include #define DM_DRIVER_IMAGE_SET 1u #define DM_DRIVER_START_SET 2u #define DM_DRIVER_CLASS_SET 4u #define DM_DRIVER_CRITICAL_SET 8u #define DM_DRIVER_REQUIRES_SET 16u #define DM_DRIVER_AFTER_SET 32u #define DM_CLASS_REQUIRES_SET 1u #define DM_CLASS_AFTER_SET 2u static bool DmFail(char* error, size_t capacity, const char* message) { if (error && capacity) { size_t i = 0; while (message[i] && i + 1 < capacity) { error[i] = message[i]; ++i; } error[i] = '\0'; } return false; } static bool DmSpace(char c) { return c == ' ' || c == '\t' || c == '\r'; } static void DmTrim(const char** begin, const char** end) { while (*begin < *end && DmSpace(**begin)) ++*begin; while (*end > *begin && DmSpace((*end)[-1])) --*end; } static bool DmEqual(const char* begin, const char* end, const char* value) { while (begin < end && *value && *begin == *value) { ++begin; ++value; } return begin == end && !*value; } static bool DmIdentifier(const char* begin, const char* end) { if (begin == end || (size_t)(end - begin) >= DM_ID_MAX) return false; for (const char* p = begin; p < end; ++p) { char c = *p; if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '.' || c == '-' || c == '_')) return false; } return true; } // PE import module names are compared without ASCII case distinctions. static bool DmImageEqual(const char* a, const char* b) { while (*a && *b) { char x = *a++; char y = *b++; if (x >= 'A' && x <= 'Z') x = (char)(x + ('a' - 'A')); if (y >= 'A' && y <= 'Z') y = (char)(y + ('a' - 'A')); if (x != y) return false; } return !*a && !*b; } static bool DmCopy(char* out, size_t capacity, const char* begin, const char* end) { size_t size = (size_t)(end - begin); if (!size || size >= capacity) return false; memcpy(out, begin, size); out[size] = '\0'; return true; } static int DmFindDriver(const DM_CONFIG* config, const char* id) { for (uint32_t i = 0; i < config->DriverCount; ++i) if (!strcmp(config->Drivers[i].Id, id)) return (int)i; return -1; } static int DmFindClass(const DM_CONFIG* config, const char* id) { for (uint32_t i = 0; i < config->ClassCount; ++i) if (!strcmp(config->Classes[i].Id, id)) return (int)i; return -1; } static bool DmParseEdges(DM_EDGES* edges, const char* begin, const char* end, DM_DEPENDENCY_KIND kind) { if (begin == end) return true; while (begin < end) { const char* finish = begin; while (finish < end && *finish != ',') ++finish; const char* tokenEnd = finish; DmTrim(&begin, &tokenEnd); if (!DmIdentifier(begin, tokenEnd) || edges->Count == DM_MAX_EDGES) return false; for (uint32_t i = 0; i < edges->Count; ++i) { if (edges->Items[i].Kind == kind && DmEqual(begin, tokenEnd, edges->Items[i].Id)) return false; } DM_DEPENDENCY* edge = &edges->Items[edges->Count++]; edge->Kind = kind; if (!DmCopy(edge->Id, sizeof(edge->Id), begin, tokenEnd)) return false; if (finish == end) return true; begin = finish + 1; DmTrim(&begin, &end); if (begin == end) return false; } return true; } // Validates references and boot-phase satisfiability without flattening class alternatives. static bool DmValidateEdges(const DM_CONFIG* config, const DM_EDGES* edges, const DM_DRIVER_CONFIG* source, bool required) { for (uint32_t i = 0; i < edges->Count; ++i) { const DM_DEPENDENCY* edge = &edges->Items[i]; if (edge->Kind == DmDependencyDriver) { int target = DmFindDriver(config, edge->Id); if (target < 0) return false; if (source && source->Phase == DmStartBoot && config->Drivers[target].Phase != DmStartBoot) return false; } else { if (DmFindClass(config, edge->Id) < 0) return false; uint32_t bootProviders = 0; for (uint32_t j = 0; j < config->DriverCount; ++j) { if (strcmp(config->Drivers[j].Class, edge->Id)) continue; if (config->Drivers[j].Phase == DmStartBoot) ++bootProviders; } if (required && source && source->Phase == DmStartBoot && !bootProviders) return false; } } return true; } static bool DmEdgesOverlap(const DM_EDGES* requires, const DM_EDGES* after) { for (uint32_t i = 0; i < requires->Count; ++i) for (uint32_t j = 0; j < after->Count; ++j) if (requires->Items[i].Kind == after->Items[j].Kind && !strcmp(requires->Items[i].Id, after->Items[j].Id)) return true; return false; } static bool DmVisitClass(uint32_t index, uint32_t count, uint8_t color[DM_MAX_CLASSES], uint8_t graph[DM_MAX_CLASSES][DM_MAX_CLASSES]) { color[index] = 1; for (uint32_t j = 0; j < count; ++j) { if (!graph[index][j]) continue; if (color[j] == 1 || (color[j] == 0 && !DmVisitClass(j, count, color, graph))) return false; } color[index] = 2; return true; } bool DmConfigParse(DM_CONFIG* config, const char* bytes, size_t size, char* error, size_t errorCapacity) { if (!config || !bytes || size == 0 || size > DM_CONFIG_MAX_BYTES) return DmFail(error, errorCapacity, "invalid configuration size"); memset(config, 0, sizeof(*config)); DM_DRIVER_CONFIG* driver = NULL; DM_CLASS_CONFIG* cls = NULL; bool seenDriverSection = false; size_t pos = 0; while (pos < size) { size_t line = pos; while (pos < size && bytes[pos] != '\n') ++pos; const char* begin = bytes + line; const char* end = bytes + pos; if (pos < size) ++pos; DmTrim(&begin, &end); if (begin == end || *begin == ';' || *begin == '#') continue; if (*begin == '[') { if (end[-1] != ']' || (size_t)(end - begin) < 4) return DmFail(error, errorCapacity, "invalid section"); const char* name = begin + 1; const char* nameEnd = end - 1; driver = NULL; cls = NULL; if ((size_t)(nameEnd - name) > 7 && !memcmp(name, "driver.", 7)) { name += 7; if (!DmIdentifier(name, nameEnd) || config->DriverCount == DM_MAX_DRIVERS) return DmFail(error, errorCapacity, "invalid driver id or driver limit"); driver = &config->Drivers[config->DriverCount++]; seenDriverSection = true; if (!DmCopy(driver->Id, sizeof(driver->Id), name, nameEnd)) return false; for (uint32_t i = 0; i + 1 < config->DriverCount; ++i) if (!strcmp(config->Drivers[i].Id, driver->Id)) return DmFail(error, errorCapacity, "duplicate driver id"); } else if ((size_t)(nameEnd - name) > 6 && !memcmp(name, "class.", 6)) { name += 6; if (!DmIdentifier(name, nameEnd) || config->ClassCount == DM_MAX_CLASSES) return DmFail(error, errorCapacity, "invalid class id or class limit"); if (seenDriverSection) return DmFail(error, errorCapacity, "class declared after driver"); cls = &config->Classes[config->ClassCount++]; if (!DmCopy(cls->Id, sizeof(cls->Id), name, nameEnd)) return false; for (uint32_t i = 0; i + 1 < config->ClassCount; ++i) if (!strcmp(config->Classes[i].Id, cls->Id)) return DmFail(error, errorCapacity, "duplicate class id"); } else return DmFail(error, errorCapacity, "unknown section"); continue; } if (!driver && !cls) return DmFail(error, errorCapacity, "key outside section"); const char* equal = begin; while (equal < end && *equal != '=') ++equal; if (equal == end) return DmFail(error, errorCapacity, "missing equals"); const char* keyEnd = equal; const char* value = equal + 1; DmTrim(&begin, &keyEnd); DmTrim(&value, &end); for (const char* p = value; p < end; ++p) { if (*p == ';' || *p == '#') { end = p; DmTrim(&value, &end); break; } } uint8_t mask = 0; if (driver) { if (DmEqual(begin, keyEnd, "image")) { mask = DM_DRIVER_IMAGE_SET; if (!DmCopy(driver->Image, sizeof(driver->Image), value, end)) return DmFail(error, errorCapacity, "invalid image"); for (const char* p = value; p < end; ++p) if (!((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9') || *p == '-' || *p == '_' || *p == '.')) return DmFail(error, errorCapacity, "invalid image filename"); if (end - value < 5 || memcmp(end - 4, ".sys", 4)) return DmFail(error, errorCapacity, "image must be a .sys file"); } else if (DmEqual(begin, keyEnd, "start")) { mask = DM_DRIVER_START_SET; if (DmEqual(value, end, "boot")) driver->Phase = DmStartBoot; else if (DmEqual(value, end, "runtime")) driver->Phase = DmStartRuntime; else if (DmEqual(value, end, "disabled")) { driver->Phase = DmStartDisabled; driver->State = DmRunDisabled; } else return DmFail(error, errorCapacity, "invalid start phase"); } else if (DmEqual(begin, keyEnd, "class")) { mask = DM_DRIVER_CLASS_SET; if (value != end && (!DmIdentifier(value, end) || !DmCopy(driver->Class, sizeof(driver->Class), value, end))) return DmFail(error, errorCapacity, "invalid class"); } else if (DmEqual(begin, keyEnd, "requires")) { mask = DM_DRIVER_REQUIRES_SET; if (!DmParseEdges(&driver->Requires, value, end, DmDependencyDriver)) return DmFail(error, errorCapacity, "invalid requires"); } else if (DmEqual(begin, keyEnd, "after")) { mask = DM_DRIVER_AFTER_SET; if (!DmParseEdges(&driver->After, value, end, DmDependencyDriver)) return DmFail(error, errorCapacity, "invalid after"); } else if (DmEqual(begin, keyEnd, "critical")) { mask = DM_DRIVER_CRITICAL_SET; if (value == end) driver->Critical = false; else if (DmEqual(value, end, "true")) driver->Critical = true; else if (DmEqual(value, end, "false")) driver->Critical = false; else return DmFail(error, errorCapacity, "invalid critical value"); } else return DmFail(error, errorCapacity, "unknown driver key"); if (driver->Present & mask) return DmFail(error, errorCapacity, "duplicate driver key"); driver->Present |= mask; } else { if (DmEqual(begin, keyEnd, "requires")) { mask = DM_CLASS_REQUIRES_SET; if (!DmParseEdges(&cls->Requires, value, end, DmDependencyClass)) return DmFail(error, errorCapacity, "invalid class requires"); } else if (DmEqual(begin, keyEnd, "after")) { mask = DM_CLASS_AFTER_SET; if (!DmParseEdges(&cls->After, value, end, DmDependencyClass)) return DmFail(error, errorCapacity, "invalid class after"); } else return DmFail(error, errorCapacity, "unknown class key"); if (cls->Present & mask) return DmFail(error, errorCapacity, "duplicate class key"); cls->Present |= mask; } } if (!config->DriverCount) return DmFail(error, errorCapacity, "no drivers"); // Class graph is checked independently even when a class has no providers. uint8_t classGraph[DM_MAX_CLASSES][DM_MAX_CLASSES] = {{0}}; for (uint32_t i = 0; i < config->ClassCount; ++i) { const DM_CLASS_CONFIG* cls = &config->Classes[i]; if (DmEdgesOverlap(&cls->Requires, &cls->After)) return DmFail(error, errorCapacity, "conflicting class dependency"); const DM_EDGES* lists[] = { &cls->Requires, &cls->After }; for (uint32_t k = 0; k < 2; ++k) for (uint32_t j = 0; j < lists[k]->Count; ++j) { int index = DmFindClass(config, lists[k]->Items[j].Id); if (index < 0) return DmFail(error, errorCapacity, "unknown class dependency"); classGraph[i][index] = 1; } } uint8_t classColors[DM_MAX_CLASSES] = {0}; for (uint32_t i = 0; i < config->ClassCount; ++i) if (!classColors[i] && !DmVisitClass(i, config->ClassCount, classColors, classGraph)) return DmFail(error, errorCapacity, "class dependency cycle"); for (uint32_t i = 0; i < config->DriverCount; ++i) { DM_DRIVER_CONFIG* d = &config->Drivers[i]; if ((d->Present & (DM_DRIVER_IMAGE_SET | DM_DRIVER_START_SET)) != (DM_DRIVER_IMAGE_SET | DM_DRIVER_START_SET)) return DmFail(error, errorCapacity, "driver needs image and start"); for (uint32_t j = 0; j < i; ++j) if (d->Phase != DmStartDisabled && config->Drivers[j].Phase != DmStartDisabled && DmImageEqual(config->Drivers[j].Image, d->Image)) return DmFail(error, errorCapacity, "duplicate image"); if (d->Class[0] && DmFindClass(config, d->Class) < 0) return DmFail(error, errorCapacity, "undeclared driver class"); if (DmEdgesOverlap(&d->Requires, &d->After)) return DmFail(error, errorCapacity, "conflicting driver dependency"); if (!DmValidateEdges(config, &d->Requires, d, true) || !DmValidateEdges(config, &d->After, d, false)) return DmFail(error, errorCapacity, "invalid driver dependency or phase"); if (d->Class[0] && d->Phase != DmStartDisabled) { DM_CLASS_CONFIG* c = &config->Classes[DmFindClass(config, d->Class)]; if (!DmValidateEdges(config, &c->Requires, d, true) || !DmValidateEdges(config, &c->After, d, false)) return DmFail(error, errorCapacity, "invalid class dependency or phase"); } } // An optimistic dry run models requires= as an OR over class providers and // after= as a settlement barrier. It detects real combined deadlocks without // rejecting a class merely because one alternative provider depends on it. for (uint32_t phase = DmStartBoot; phase <= DmStartRuntime; ++phase) { config->ActivePhase = (DM_START_PHASE)phase; for (;;) { bool progress = false; for (uint32_t i = 0; i < config->DriverCount; ++i) { DM_DRIVER_CONFIG* d = &config->Drivers[i]; if (d->Phase != phase || d->State != DmRunWaiting) continue; if (DmDriverCanStart(config, i)) { d->State = DmRunStarted; progress = true; } else if (DmDriverIsBlocked(config, i)) { d->State = DmRunBlocked; progress = true; } } if (!progress) break; } for (uint32_t i = 0; i < config->DriverCount; ++i) if (config->Drivers[i].Phase == phase && config->Drivers[i].State == DmRunWaiting) return DmFail(error, errorCapacity, "unschedulable dependency cycle"); } for (uint32_t i = 0; i < config->DriverCount; ++i) if (config->Drivers[i].Phase != DmStartDisabled) config->Drivers[i].State = DmRunWaiting; config->ActivePhase = DmStartBoot; return true; } bool DmClassSettled(const DM_CONFIG* config, const char* classId) { for (uint32_t i = 0; i < config->DriverCount; ++i) { const DM_DRIVER_CONFIG* driver = &config->Drivers[i]; if (!strcmp(driver->Class, classId) && (config->ActivePhase == DmStartRuntime || driver->Phase == DmStartBoot) && driver->State == DmRunWaiting) return false; } return true; } bool DmClassAvailable(const DM_CONFIG* config, const char* classId) { for (uint32_t i = 0; i < config->DriverCount; ++i) { const DM_DRIVER_CONFIG* driver = &config->Drivers[i]; if (!strcmp(driver->Class, classId) && driver->State == DmRunStarted) return true; } return false; } static bool DmEdgesReady(const DM_CONFIG* config, const DM_EDGES* edges, bool required) { for (uint32_t i = 0; i < edges->Count; ++i) { const DM_DEPENDENCY* edge = &edges->Items[i]; if (edge->Kind == DmDependencyClass) { if (required ? !DmClassAvailable(config, edge->Id) : !DmClassSettled(config, edge->Id)) return false; } else { int index = DmFindDriver(config, edge->Id); if (index < 0) return false; DM_RUN_STATE state = config->Drivers[index].State; if (required ? state != DmRunStarted : state == DmRunWaiting) return false; } } return true; } bool DmDriverCanStart(const DM_CONFIG* config, uint32_t index) { if (!config || index >= config->DriverCount) return false; const DM_DRIVER_CONFIG* driver = &config->Drivers[index]; if (driver->State != DmRunWaiting || !DmEdgesReady(config, &driver->Requires, true) || !DmEdgesReady(config, &driver->After, false)) return false; if (!driver->Class[0]) return true; const DM_CLASS_CONFIG* cls = &config->Classes[DmFindClass(config, driver->Class)]; return DmEdgesReady(config, &cls->Requires, true) && DmEdgesReady(config, &cls->After, false); } static bool DmEdgesImpossible(const DM_CONFIG* config, const DM_EDGES* edges) { for (uint32_t i = 0; i < edges->Count; ++i) { const DM_DEPENDENCY* edge = &edges->Items[i]; if (edge->Kind == DmDependencyClass) { if (DmClassSettled(config, edge->Id) && !DmClassAvailable(config, edge->Id)) return true; } else { int index = DmFindDriver(config, edge->Id); if (index < 0 || config->Drivers[index].State == DmRunFailed || config->Drivers[index].State == DmRunBlocked || config->Drivers[index].State == DmRunDisabled) return true; } } return false; } bool DmDriverIsBlocked(const DM_CONFIG* config, uint32_t index) { if (!config || index >= config->DriverCount) return false; const DM_DRIVER_CONFIG* driver = &config->Drivers[index]; if (driver->State != DmRunWaiting) return false; if (DmEdgesImpossible(config, &driver->Requires)) return true; if (!driver->Class[0]) return false; return DmEdgesImpossible(config, &config->Classes[DmFindClass(config, driver->Class)].Requires); }