From 2acec63b2ed75bf4b71ad257db573c4b8f9639e7 Mon Sep 17 00:00:00 2001 From: tumagonx Date: Tue, 8 Aug 2017 10:54:53 +0700 Subject: initial commit --- learn.c | 1414 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1414 insertions(+) create mode 100644 learn.c (limited to 'learn.c') diff --git a/learn.c b/learn.c new file mode 100644 index 0000000..0bcdd53 --- /dev/null +++ b/learn.c @@ -0,0 +1,1414 @@ +/* + * Copyright (c) 2004 Security Architects Corporation. All rights reserved. + * + * Module Name: + * + * learn.c + * + * Abstract: + * + * This module implements various policy-auto-generation routines. + * Policy auto generation works by monitoring all system calls and remembering their + * argument values. These are then saved in a policy file. + * + * Author: + * + * Eugene Tsyrklevich 24-Feb-2004 + * + * Revision History: + * + * None. + */ + + +#include +#include "learn.h" +#include "accessmask.h" +#include "hookproc.h" +#include "procname.h" +#include "process.h" +#include "log.h" + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (INIT, InitLearningMode) +#endif + + +//XXX on a terminal server, global\* might need to be handled specially + +WCHAR ProcessToMonitor[MAX_PROCESS_NAME] = L""; + +BOOLEAN LearningMode = FALSE; +HANDLE hFile; +INT64 offset; + +BOOLEAN IsGuiThread = FALSE; /* does the process we are profiling contain any GUI threads? */ + +SECURITY_POLICY NewPolicy; + + + +/* + * InitLearningMode() + * + * Description: + * Initialize a learning/training mode. Training mode is used to create process policies that + * describe all the resources used by a process. + * + * Called during driver initialization (DriverEntry()) or from DriverDeviceControl(). + * + * Parameters: + * None. + * + * Returns: + * TRUE to indicate success, FALSE if failed. + */ + +BOOLEAN +InitLearningMode() +{ + LOG(LOG_SS_LEARN, LOG_PRIORITY_VERBOSE, ("InitLearningMode: Entered.\n")); + + + /* initialize the NewPolicy */ + RtlZeroMemory(&NewPolicy, sizeof(NewPolicy)); + + KeInitializeSpinLock(&NewPolicy.SpinLock); + + NewPolicy.ProtectionFlags = PROTECTION_ALL_ON; + + + /* + * Load an existing policy (if there is one) and use it as a template + */ + + if (FindAndLoadSecurityPolicy(&NewPolicy, ProcessToMonitor, NULL) == FALSE) + { + LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("InitLearningMode: Learning about '%S'. An existing policy not found.\n", ProcessToMonitor)); + + NewPolicy.DefaultPolicyAction = ACTION_LOG; + } + else + { + LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("InitLearningMode: Learning about '%S'. Using a pre-existing policy.\n", ProcessToMonitor)); + } + + + return TRUE; +} + + + +/************************************************************************************************* + * + * Path Filters + * Used to convert kernel object names into their userland representation + * (i.e. registry \REGISTRY\USER will be converted to HKEY_USERS + * + *************************************************************************************************/ + + + +/* + * FilterFilePath() + * + * Description: + * Convert kernel file paths to their userland representation (i.e. removing \??\, \DosDevices\, references). + * + * Parameters: + * path - Pointer to a source character file path. + * + * Returns: + * Pointer to a post-processed file path. + */ + +PCHAR +FilterFilePath(PCHAR path) +{ + CHAR buffer[MAX_PATH]; + + + if (path[0] != '\\' && path[0] != '%') + { +// KdPrint(("FilterFilePath: special filename %s\n", path)); +// return NULL; + } + + + if (_strnicmp(path, "\\??\\pipe", 8) == 0) + { + return path + 3; + } + + if (_strnicmp(path, "\\??\\", 4) == 0) + { + path += 4; + } + else if (_strnicmp(path, "\\DosDevices\\", 12) == 0) + { + path += 12; + } + else if (_strnicmp(path, CDrive, CDriveLength) == 0 && CDriveLength) + { + /* replace any possible \device\harddiskvolumeX references with a DOS C:\ name */ + //XXX what about d:\ and so on? + + path[CDriveLength-2] = 'C'; + path[CDriveLength-1] = ':'; + + path += CDriveLength - 2; + } + + + + if (_strnicmp(path, SystemRootDirectory, SystemRootDirectoryLength) == 0 && SystemRootDirectoryLength) + { + /* replace \windows (systemroot) references with SystemRoot */ + + strcpy(buffer, "%SystemRoot%"); + strcat(buffer, path + SystemRootDirectoryLength); + + path = buffer; + } + else if (_strnicmp(path, SystemRootUnresolved, SystemRootUnresolvedLength) == 0 && SystemRootUnresolvedLength) + { + /* replace c:\windows (systemroot) references with SystemRoot */ + + strcpy(buffer, "%SystemRoot%"); + strcat(buffer, path + SystemRootUnresolvedLength); + + path = buffer; + } + else if (_strnicmp(path, "\\SystemRoot\\", 12) == 0) + { + strcpy(buffer, "%SystemRoot%"); + strcat(buffer, path + 11); + + path = buffer; + } + else if ((path[0] == SystemDrive || path[0] == (CHAR) tolower(SystemDrive)) && path[1] == ':') + { + /* replace any system drive references with "SystemDrive" */ + strcpy(buffer, "%SystemDrive%"); + strcat(buffer, path + 1); + + path = buffer; + } + + + return path; +} + + + +/* + * FilterMailslotPath() + * + * Description: + * Convert kernel mailslot paths to their userland representation. + * + * Parameters: + * path - Pointer to a source character path. + * + * Returns: + * Pointer to a post-processed path. + */ + +PCHAR +FilterMailslotPath(PCHAR path) +{ + if (_strnicmp(path, "\\mailslot\\", 10) == 0) + return path + 10; + + if (_strnicmp(path, "\\??\\mailslot\\", 13) == 0) + return path + 13; + + if (_strnicmp(path, "\\device\\mailslot\\", 17) == 0) + return path + 17; + + return path; +} + + + +/* + * FilterNamedpipePath() + * + * Description: + * Convert kernel namedpipe paths to their userland representation. + * + * Parameters: + * path - Pointer to a source character path. + * + * Returns: + * Pointer to a post-processed path. + */ + +PCHAR +FilterNamedpipePath(PCHAR path) +{ + if (_strnicmp(path, "\\pipe\\", 6) == 0) + return path + 6; + + if (_strnicmp(path, "\\??\\pipe\\", 9) == 0) + return path + 9; + + if (_strnicmp(path, "\\device\\namedpipe\\", 18) == 0) + return path + 18; + + return path; +} + + + +/* + * FilterRegistryPath() + * + * Description: + * Convert kernel registry paths to their userland equivalents + * (i.e. replacing \REGISTRY\USER\ kernel path with its userland HKEY_USERS\ representation). + * + * Parameters: + * path - Pointer to a source character registry path. + * + * Returns: + * Pointer to a post-processed registry path. + */ + +PCHAR +FilterRegistryPath(PCHAR path) +{ + static char buffer[MAX_PATH]; + + +//XXX use reverse symlink lookup for this?!?!? + + if (_strnicmp(path, "\\REGISTRY\\", 10) == 0) + { + /* replace \Registry\User\ with HKEY_USERS\ */ + if (_strnicmp(path + 10, "USER\\", 5) == 0) + { + strcpy(path + 4, "HKEY_USERS"); + path[14] = '\\'; + return path + 4; + } + + /* replace \Registry\Machine\ with HKEY_LOCAL_MACHINE\ */ + if (_strnicmp(path + 10, "MACHINE\\", 8) == 0) + { + strcpy(buffer, "HKEY_LOCAL_MACHINE\\"); + strncat(buffer, path + 18, MAX_PATH - 20); + + return buffer; + } + } + + + return path; +} + + + +/* + * FilterBaseNamedObjectsPath() + * + * Description: + * Convert kernel paths to their userland representation (by removing \BaseNamedObjects\ kernel reference). + * + * Parameters: + * path - Pointer to a source character event or semaphore path. + * + * Returns: + * Pointer to a post-processed path. + */ + +PCHAR +FilterBaseNamedObjectsPath(PCHAR path) +{ + if (_strnicmp(path, "\\BaseNamedObjects\\", 18) == 0) + { + return path + 18; + } + + return path; +} + + + +/* + * FilterDll() + * + * Description: + * Convert kernel DLL path to its userland representation + * (i.e. removing \KnownDlls\ kernel reference). + * + * Parameters: + * path - Pointer to a source character DLL path. + * + * Returns: + * Pointer to a post-processed DLL path. + */ + +PCHAR +FilterDll(PCHAR path) +{ + if (_strnicmp(path, "\\KnownDlls\\", 11) == 0) + { + return path + 11; + } + + return path; +} + + + +/* + * FilterPath() + * + * Description: + * Filter stub. + * + * Parameters: + * path - Pointer to a source character path. + * + * Returns: + * Pointer to an unmodified path. + */ + +PCHAR +FilterPath(PCHAR path) +{ + return path; +} + + + +/************************************************************************************************* + * + * Operation Filters + * Convert operations (such as OP_READ, OP_WRITE) into their ASCII representation. + * (i.e. file OP_READ will be translated to "read" while atom OP_READ will become "find" + * + *************************************************************************************************/ + + + +/* + * FilterOperation() + * + * Description: + * Convert operations (such as OP_READ, OP_WRITE) into their ASCII representation. + * + * Parameters: + * OperationType - operation type. + * + * Returns: + * Pointer to an ASCII string. + */ + +PCHAR +FilterOperation(UCHAR OperationType) +{ + if (IS_BIT_SET(OperationType, OP_READ_WRITE) && + (IS_BIT_SET(OperationType, OP_DELETE) || IS_BIT_SET(OperationType, OP_EXECUTE))) + + return "all"; + + + if (IS_BIT_SET(OperationType, OP_DELETE)) + return "delete"; + + if (IS_BIT_SET(OperationType, OP_READ_WRITE)) + return "rw"; + + if (IS_BIT_SET(OperationType, OP_READ)) + return "read"; + + if (IS_BIT_SET(OperationType, OP_WRITE)) + return "write"; + + if (IS_BIT_SET(OperationType, OP_EXECUTE)) + return "execute"; + + + //XXX what about when multiple bits are set? read + delete? + LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("FilterOperation: invalid operation type %d\n", OperationType)); + + + return "all"; +} + + + +/* + * FilterSimpleOperation() + * + * Description: + * Convert operations (such as OP_READ, OP_WRITE) into their ASCII representation. + * + * Parameters: + * OperationType - operation type. + * + * Returns: + * Pointer to an ASCII string. + */ + +PCHAR +FilterSimpleOperation(UCHAR OperationType) +{ + if (IS_BIT_SET(OperationType, OP_READ_WRITE)) + return "all"; + + if (IS_BIT_SET(OperationType, OP_READ)) + return "read"; + + if (IS_BIT_SET(OperationType, OP_WRITE)) + return "write"; + + LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("FilterSimpleOperation: invalid operation type %d\n", OperationType)); + + + return "all"; +} + + + +/* + * FilterCreateOpenOperation() + * + * Description: + * Convert OP_CREATE and OP_OPEN) into their ASCII representation. + * + * Parameters: + * OperationType - operation type. + * + * Returns: + * Pointer to an ASCII string. + */ + +PCHAR +FilterCreateOpenOperation(UCHAR OperationType) +{ + if (IS_BIT_SET(OperationType, OP_CREATE) && + IS_BIT_SET(OperationType, OP_OPEN)) + + return "all"; + + if (IS_BIT_SET(OperationType, OP_CREATE)) + return "create"; + + if (IS_BIT_SET(OperationType, OP_OPEN)) + return "open"; + + + LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("FilterCreateOpenOperation: invalid operation type %d\n", OperationType)); + + + return "all"; +} + + + +/* + * FilterDirectoryOperation() + * + * Description: + * Convert operations (such as OP_DIR_CREATE) into their ASCII representation. + * + * Parameters: + * OperationType - operation type. + * + * Returns: + * Pointer to an ASCII string. + */ + +PCHAR +FilterDirectoryOperation(UCHAR OperationType) +{ + if (IS_BIT_SET(OperationType, OP_DIR_CREATE)) + return "create"; + + return "all"; +} + + + +/* + * FilterProcessOperation() + * + * Description: + * Convert operations (such as OP_PROC_OPEN) into their ASCII representation. + * + * Parameters: + * OperationType - operation type. + * + * Returns: + * Pointer to an ASCII string. + */ + +PCHAR +FilterProcessOperation(UCHAR OperationType) +{ + if (IS_BIT_SET(OperationType, OP_PROC_OPEN) && + IS_BIT_SET(OperationType, OP_PROC_EXECUTE)) + + return "all"; + + + if (IS_BIT_SET(OperationType, OP_PROC_OPEN)) + return "open"; + + if (IS_BIT_SET(OperationType, OP_PROC_EXECUTE)) + return "execute"; + + + return "all"; +} + + + +/* + * FilterNetworkOperation() + * + * Description: + * Convert operations (such as OP_CONNECT) into their ASCII representation. + * + * Parameters: + * OperationType - operation type. + * + * Returns: + * Pointer to an ASCII string. + */ + +PCHAR +FilterNetworkOperation(UCHAR OperationType) +{ + if (IS_BIT_SET(OperationType, OP_TCPCONNECT)) + return "tcpconnect"; + + if (IS_BIT_SET(OperationType, OP_UDPCONNECT)) + return "udpconnect"; + + if (IS_BIT_SET(OperationType, OP_CONNECT)) + return "connect"; + + if (IS_BIT_SET(OperationType, OP_BIND)) + return "bind"; + + + LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("FilterNetworkOperation: invalid operation type %d\n", OperationType)); + + + return "all"; +} + + + +/* + * FilterPortOperation() + * + * Description: + * Convert port operations (such as OP_PORT_CONNECT) into their ASCII representation. + * + * Parameters: + * OperationType - operation type. + * + * Returns: + * Pointer to an ASCII string. + */ + +PCHAR +FilterPortOperation(UCHAR OperationType) +{ + if (IS_BIT_SET(OperationType, OP_PORT_CREATE) && + IS_BIT_SET(OperationType, OP_PORT_CONNECT)) + + return "all"; + + + if (IS_BIT_SET(OperationType, OP_PORT_CREATE)) + return "create"; + + if (IS_BIT_SET(OperationType, OP_PORT_CONNECT)) + return "connect"; + + + LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("FilterPortOperation: invalid operation type %d\n", OperationType)); + + + return "all"; +} + + + +/* + * FilterAtomOperation() + * + * Description: + * Convert atom operations (such as OP_READ, OP_WRITE) into their ASCII representation. + * + * Parameters: + * OperationType - operation type. + * + * Returns: + * Pointer to an ASCII string. + */ + +PCHAR +FilterAtomOperation(UCHAR OperationType) +{ + if (IS_BIT_SET(OperationType, OP_ADD) && + IS_BIT_SET(OperationType, OP_FIND)) + + return "all"; + + if (IS_BIT_SET(OperationType, OP_ADD)) + return "add"; + + if (IS_BIT_SET(OperationType, OP_FIND)) + return "find"; + + + LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("FilterAtomOperation: invalid operation type %d\n", OperationType)); + + + return "all"; +} + + + +/* + * FilterDriverOperation() + * + * Description: + * Convert driver object operations (such as OP_READ, OP_WRITE) into their ASCII representation. + * + * Parameters: + * OperationType - operation type. + * + * Returns: + * Pointer to an ASCII string. + */ + +PCHAR +FilterDriverOperation(UCHAR OperationType) +{ + if (IS_BIT_SET(OperationType, OP_LOAD)) + return "load"; + + if (IS_BIT_SET(OperationType, OP_REGLOAD)) + return "regload"; + + LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("FilterDriverOperation: invalid operation type %d\n", OperationType)); + + return "load"; +} + + + +/* + * FilterDllOperation() + * + * Description: + * Convert DLL operations (such as OP_READ, OP_WRITE) into their ASCII representation. + * + * Parameters: + * OperationType - operation type. + * + * Returns: + * Pointer to an ASCII string. + */ + +PCHAR +FilterDllOperation(UCHAR OperationType) +{ + return "load"; +} + + + +/* + * FilterServiceOperation() + * + * Description: + * Convert service operations (such as OP_START, OP_WRITE) into their ASCII representation. + * + * Parameters: + * OperationType - operation type. + * + * Returns: + * Pointer to an ASCII string. + */ + +PCHAR +FilterServiceOperation(UCHAR OperationType) +{ + if (IS_BIT_SET(OperationType, OP_SERVICE_START)) + return "start"; + + if (IS_BIT_SET(OperationType, OP_SERVICE_STOP)) + return "stop"; + + if (IS_BIT_SET(OperationType, OP_SERVICE_CREATE)) + return "create"; + + if (IS_BIT_SET(OperationType, OP_SERVICE_DELETE)) + return "delete"; + + + LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("FilterServiceOperation: invalid operation type %d\n", OperationType)); + + + return "all"; +} + + + +/* + * FilterTimeOperation() + * + * Description: + * Convert time operations (such as OP_TIME_CHANGE) into their ASCII representation. + * + * Parameters: + * OperationType - operation type. + * + * Returns: + * Pointer to an ASCII string. + */ + +PCHAR +FilterTimeOperation(UCHAR OperationType) +{ + if (IS_BIT_SET(OperationType, OP_TIME_CHANGE)) + return "change"; + + + LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("FilterTimeOperation: invalid operation type %d\n", OperationType)); + + + return "all"; +} + + + +/* + * FilterTokenOperation() + * + * Description: + * Convert token operations (such as OP_TOKEN_MODIFY) into their ASCII representation. + * + * Parameters: + * OperationType - operation type. + * + * Returns: + * Pointer to an ASCII string. + */ + +PCHAR +FilterTokenOperation(UCHAR OperationType) +{ + if (IS_BIT_SET(OperationType, OP_TOKEN_MODIFY)) + return "modify"; + + + LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("FilterTokenOperation: invalid operation type %d\n", OperationType)); + + + return "all"; +} + + + +/* + * FilterSyscallOperation() + * + * Description: + * This function is never supposed to be called. + * + * Parameters: + * OperationType - operation type. + * + * Returns: + * An error. + */ + +PCHAR +FilterSyscallOperation(UCHAR OperationType) +{ + LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("FilterSyscallOperation: this function is not supposed to be called.\n")); + + return "error"; +} + + + +typedef PCHAR (*fpFilterObject) (PCHAR path); +typedef PCHAR (*fpFilterOperation) (UCHAR OperationType); + + +/* in C++ these would be member methods */ + +struct +{ + PCHAR Prefix; + fpFilterObject FilterObjectProc; + fpFilterOperation FilterOperationProc; + +} RuleTypeData[] = +{ + { "file", FilterFilePath, FilterOperation }, + { "directory", FilterFilePath, FilterDirectoryOperation }, + { "mailslot", FilterMailslotPath, FilterSimpleOperation }, + { "namedpipe", FilterNamedpipePath, FilterSimpleOperation }, + { "registry", FilterRegistryPath, FilterOperation }, + { "section", FilterBaseNamedObjectsPath, FilterOperation }, + { "dll", FilterDll, FilterDllOperation }, + { "event", FilterBaseNamedObjectsPath, FilterCreateOpenOperation }, + { "semaphore", FilterBaseNamedObjectsPath, FilterCreateOpenOperation }, + { "job", FilterBaseNamedObjectsPath, FilterCreateOpenOperation }, + { "mutex", FilterBaseNamedObjectsPath, FilterCreateOpenOperation }, + { "port", FilterPath, FilterPortOperation }, + { "symlink", FilterPath, FilterCreateOpenOperation }, + { "timer", FilterBaseNamedObjectsPath, FilterCreateOpenOperation }, + { "process", FilterFilePath, FilterProcessOperation }, + { "driver", FilterFilePath, FilterDriverOperation }, + { "dirobj", FilterPath, FilterCreateOpenOperation }, + { "atom", FilterPath, FilterAtomOperation }, + + { "network", FilterPath, FilterNetworkOperation }, + { "service", FilterPath, FilterServiceOperation }, + { "time", FilterPath, FilterTimeOperation }, + { "token", FilterPath, FilterTokenOperation }, + { "syscall", FilterPath, FilterSyscallOperation }, +}; + + + +/* + * DecodeAction() + * + * Description: + * . + * + * Parameters: + * . + * + * Returns: + * . + */ + +PCHAR +DecodeAction(UCHAR ActionType) +{ + switch (ActionType) + { + case ACTION_ASK: + case ACTION_ASK_DEFAULT: + return "ask"; + + case ACTION_PERMIT: + case ACTION_ASK_PERMIT: + case ACTION_PERMIT_DEFAULT: + return "permit"; + + case ACTION_DENY: + case ACTION_ASK_DENY: + case ACTION_DENY_DEFAULT: + return "deny"; + + case ACTION_LOG: + case ACTION_ASK_LOG: + case ACTION_LOG_DEFAULT: + return "log"; + + case ACTION_QUIETDENY: + case ACTION_QUIETDENY_DEFAULT: + return "quietdeny"; + + case ACTION_TERMINATE: + case ACTION_ASK_TERMINATE: + return "log"; + + default: + return "unknown"; + } +} + + + +/* + * CreateRule() + * + * Description: + * Generate an ASCII rule for rule 'r' of type RuleType. + * + * Parameters: + * RuleType - rule type. + * r - rule itself. + * buffer - output buffer. + * + * Returns: + * TRUE if a rule was created, FALSE otherwise. + */ + +BOOLEAN +CreateRule(RULE_TYPE RuleType, PPOLICY_RULE r, PCHAR buffer) +{ + PCHAR name; + + + ASSERT(r); + ASSERT(buffer); + + + if (r->MatchType != MATCH_ALL) + { + name = RuleTypeData[ RuleType ].FilterObjectProc(r->Name); + + /* if name is NULL there is no need to remember this rule */ + if (name == NULL) + return FALSE; + + if (strlen(name) > MAX_PATH) + { + LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("CreateRule: name '%s' is too long\n", name)); + return FALSE; + } + + } + + + /* + * construct the "objecttype_operation: " part first + */ + + strcpy(buffer, RuleTypeData[ RuleType ].Prefix); + + strcat(buffer, "_"); + + strcat(buffer, RuleTypeData[ RuleType ].FilterOperationProc(r->OperationType)); + + strcat(buffer, ": "); + + + /* + * now construct the action part + */ + + if (r->MatchType != MATCH_ALL) + { + strcat(buffer, "name "); + + if (r->MatchType == MATCH_WILDCARD) + strcat(buffer, "match \""); + else + strcat(buffer, "eq \""); + + strcat(buffer, name); + + strcat(buffer, "\" then "); + } + + strcat(buffer, DecodeAction(r->ActionType)); + + + /* add optional rule clause */ + if (r->RuleNumber != 0) + { + CHAR rule[16]; + + sprintf(rule, " [rule %d]", r->RuleNumber); + + strcat(buffer, rule); + } + + + return TRUE; +} + + + +/* + * CreateServiceRule() + * + * Description: + * . + * + * Parameters: + * . + * + * Returns: + * . + */ + +BOOLEAN +CreateServiceRule(PPOLICY_RULE r, PCHAR buffer) +{ + strcpy(buffer, "service_"); + strcat(buffer, r->Name + 2); + strcat(buffer, ": permit"); + + return TRUE; +} + + + +BOOLEAN WriteRule(PCHAR rule); +BOOLEAN WritePolicyFile(PCHAR buffer); + + +/* + * FlushPolicy() + * + * Description: + * . + * + * Parameters: + * . + * + * Returns: + * Nothing. + */ + +void +FlushPolicy() +{ + PPOLICY_RULE r; + KIRQL irql; + char buffer[MAX_PATH*2]; + UCHAR i; + BOOLEAN ValidRule; + + + // cannot write to files while holding spinlock (irql != PASSIVE_LEVEL) +// KeAcquireSpinLock(&NewPolicy.SpinLock, &irql); + + sprintf(buffer, "\r\n# %S Default Process Policy\r\n", ProcessToMonitor); + WriteRule(buffer); + + sprintf(buffer, "policy_default: %s\r\n", DecodeAction(NewPolicy.DefaultPolicyAction)); + WriteRule(buffer); + + if (! IS_OVERFLOW_PROTECTION_ON(NewPolicy)) + WriteRule("protection_overflow: off"); + + if (! IS_USERLAND_PROTECTION_ON(NewPolicy)) + WriteRule("protection_userland: off"); + + if (! IS_EXTENSION_PROTECTION_ON(NewPolicy)) + WriteRule("protection_extension: off"); + + if (! IS_DEBUGGING_PROTECTION_ON(NewPolicy)) + WriteRule("protection_debugging: off"); + + if (! IS_VDM_PROTECTION_ON(NewPolicy)) + WriteRule("protection_dos16: off"); + + +// KdPrint(("%s process\n", IsGuiThread ? "GUI" : "NON GUI")); + + + for (i = 0; i < RULE_LASTONE; i++) + { + r = NewPolicy.RuleList[i]; + + if (r) + { + WritePolicyFile("\r\n\r\n# "); + WritePolicyFile(RuleTypeData[i].Prefix); + WritePolicyFile(" related operations\r\n\r\n"); + } + + while (r) + { + if (i != RULE_SYSCALL) + ValidRule = CreateRule(i, r, buffer); + else + ValidRule = CreateServiceRule(r, buffer); + + if (ValidRule == TRUE) + WriteRule(buffer); + + r = (PPOLICY_RULE) r->Next; + } + } + + +// KeReleaseSpinLock(&NewPolicy.SpinLock, irql); +} + + + +/* + * ShutdownLearningMode() + * + * Description: + * . + * + * Parameters: + * . + * + * Returns: + * Nothing. + */ + +BOOLEAN +ShutdownLearningMode() +{ + UNICODE_STRING pathname; + OBJECT_ATTRIBUTES oa; + IO_STATUS_BLOCK isb; + WCHAR PolicyPath[MAX_PATH]; + + + /* now open a file where the new policy will be written, possibly clobbering the old policy */ + //XXX should really copy an existing policy to a .bak file + +// _snwprintf(PolicyPath, MAX_PATH, L"\\??\\c:\\policy\\%s.policy", ProcessToMonitor); + _snwprintf(PolicyPath, MAX_PATH, L"\\??\\%s\\policy\\%s.policy", OzoneInstallPath, ProcessToMonitor); + PolicyPath[MAX_PATH - 1] = 0; + + + LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("ShutdownLearningMode: Writing policy to %S\n", PolicyPath)); + + + RtlInitUnicodeString(&pathname, PolicyPath); + + InitializeObjectAttributes(&oa, &pathname, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); + + if (!NT_SUCCESS(ZwCreateFile(&hFile, GENERIC_WRITE, &oa, &isb, + NULL, 0, 0, FILE_SUPERSEDE, + FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0))) + { + LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("ShutdownLearningMode: Failed to open file %S\n", pathname.Buffer)); + return FALSE; + } + + offset = 0; + + FlushPolicy(); + + PolicyDelete(&NewPolicy); + + ZwClose(hFile); + hFile = 0; + + + return TRUE; +} + + + +/* + * WritePolicyFile() + * + * Description: + * . + * + * Parameters: + * . + * + * Returns: + * Nothing. + */ + +BOOLEAN +WritePolicyFile(PCHAR buffer) +{ + int len = strlen(buffer); + IO_STATUS_BLOCK isb; + + + if (!NT_SUCCESS(ZwWriteFile(hFile, NULL, NULL, NULL, &isb, (PVOID) buffer, len, (PLARGE_INTEGER) &offset, NULL))) + { + LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("WritePolicyFile(): ZwReadFile failed\n")); + return FALSE; + } + + if (isb.Information != len) + { + LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("WritePolicyFile(): Asked to write %d bytes. Wrote only %d\n", len, isb.Information)); + } + + offset += isb.Information; + + + return TRUE; +} + + + +/* + * WriteRule() + * + * Description: + * . + * + * Parameters: + * . + * + * Returns: + * Nothing. + */ + +BOOLEAN +WriteRule(PCHAR rule) +{ + BOOLEAN ret, ret2; + + ret = WritePolicyFile(rule); + ret2 = WritePolicyFile("\r\n"); + + return ret && ret2; +} + + + +/* + * RememberRule() + * + * Description: + * Create a new rule. + * + * Parameters: + * RuleType - rule type. + * ObjectName - name of an object associated with the current rule. + * OperationType - operation type. + * + * Returns: + * TRUE to indicate success, FALSE if failed. + */ + +BOOLEAN +RememberRule(RULE_TYPE RuleType, PCHAR ObjectName, UCHAR OperationType) +{ + PPOLICY_RULE rule = NewPolicy.RuleList[RuleType]; + KIRQL irql; + int len = 0; + + + if (ObjectName) + len = strlen(ObjectName); + + + KeAcquireSpinLock(&NewPolicy.SpinLock, &irql); + + + /* + * don't save duplicate rules + */ + + while (rule != NULL) + { + if ( (rule->MatchType == MATCH_ALL) || + (rule->MatchType == MATCH_SINGLE && len == rule->NameLength && _stricmp(ObjectName, rule->Name) == 0) || + (rule->MatchType == MATCH_WILDCARD && WildcardMatch(ObjectName, rule->Name) == WILDCARD_MATCH) ) + { + rule->OperationType |= OperationType; + + KeReleaseSpinLock(&NewPolicy.SpinLock, irql); + + return TRUE; + } + + rule = (PPOLICY_RULE) rule->Next; + } + + + rule = ExAllocatePoolWithTag(NonPagedPool, sizeof(POLICY_RULE) + len, _POOL_TAG); + if (rule == NULL) + { + LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("RememberRule: out of memory\n")); + return FALSE; + } + + RtlZeroMemory(rule, sizeof(POLICY_RULE)); + + rule->ActionType = ACTION_PERMIT; + rule->OperationType = OperationType; + + if (ObjectName) + { + rule->NameLength = (USHORT) len; + strcpy(rule->Name, ObjectName); + rule->MatchType = MATCH_SINGLE; + } + else + { + rule->MatchType = MATCH_ALL; + } + + rule->Next = NewPolicy.RuleList[RuleType]; + NewPolicy.RuleList[RuleType] = rule; + + + KeReleaseSpinLock(&NewPolicy.SpinLock, irql); + + + return TRUE; +} + + + +/* + * DetermineThreadType() + * + * Description: + * Determine whether a thread is GUI enabled or not. Done by checking which + * system call table the thread is using. + * + * Parameters: + * None. + * + * Returns: + * Nothing. + */ + +void +DetermineThreadType() +{ + if (ThreadServiceTableOffset == 0) + return; + + if (* (PULONG) ((PCHAR) PsGetCurrentThread() + ThreadServiceTableOffset) != (ULONG) &KeServiceDescriptorTable[0]) + IsGuiThread = TRUE; +} + + + +/* + * AddRule() + * + * Description: + * Create a new rule for a particular rule type, operation type and object. + * + * Parameters: + * RuleType - rule type. + * str - optional character object name. + * OperationType - operation taking place. + * + * Returns: + * Nothing. + */ + +BOOLEAN +AddRule(RULE_TYPE RuleType, PCHAR str, UCHAR OperationType) +{ + PWSTR filename; + + + filename = wcsrchr(GetCurrentProcessName(), L'\\'); + if (filename == NULL) + filename = GetCurrentProcessName(); + else + ++filename; + + if (_wcsicmp(filename, ProcessToMonitor) != 0) + return TRUE; + +// DetermineThreadType(); + + return RememberRule(RuleType, str, OperationType); +} -- cgit v1.3