fort/src/driver/fortps.c
2023-07-09 17:59:28 +03:00

741 lines
21 KiB
C

/* Fort Firewall Process Tree */
#include "fortps.h"
#include "fortcb.h"
#include "fortdbg.h"
#include "fortdev.h"
#include "forttrace.h"
#include "fortutl.h"
#define FORT_PSTREE_POOL_TAG 'PwfF'
#define FORT_SVCHOST_PREFIX L"\\svchost\\"
#define FORT_SVCHOST_PREFIX_SIZE \
(sizeof(FORT_SVCHOST_PREFIX) - sizeof(WCHAR)) /* skip terminating zero */
#define FORT_SVCHOST_EXE L"svchost.exe"
#define FORT_PSTREE_NAME_LEN_MAX 120
#define FORT_PSTREE_NAME_LEN_MAX_SIZE (FORT_PSTREE_NAME_LEN_MAX * sizeof(WCHAR))
#define FORT_PSTREE_NAMES_POOL_SIZE (4 * 1024)
#define FORT_PSNAME_DATA_OFF offsetof(FORT_PSNAME, data)
typedef struct fort_psname
{
UINT16 refcount;
UINT16 size;
WCHAR data[1];
} FORT_PSNAME, *PFORT_PSNAME;
#define FORT_PSNODE_NAME_INHERIT 0x0001
#define FORT_PSNODE_NAME_INHERITED 0x0002
#define FORT_PSNODE_NAME_CUSTOM 0x0004
#define FORT_PSNODE_KILL_PROCESS 0x0008
#define FORT_PSNODE_IS_SVCHOST 0x0010
/* Synchronize with tommy_hashdyn_node! */
typedef struct fort_psnode
{
struct fort_psnode *next;
struct fort_psnode *prev;
PFORT_PSNAME ps_name; /* tommy_hashdyn_node::data */
tommy_key_t pid_hash; /* tommy_hashdyn_node::index */
UINT32 process_id;
UINT16 volatile flags;
} FORT_PSNODE, *PFORT_PSNODE;
typedef struct _SYSTEM_PROCESSES
{
ULONG NextEntryOffset;
ULONG NumberOfThreads;
ULONG Reserved1[6];
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ImageName;
KPRIORITY BasePriority;
SIZE_T ProcessId;
SIZE_T ParentProcessId;
ULONG HandleCount;
ULONG SessionId;
} SYSTEM_PROCESSES, *PSYSTEM_PROCESSES;
#if !defined(SystemProcessInformation)
# define SystemProcessInformation 5
#endif
#if defined(FORT_DRIVER)
NTSTATUS NTAPI ZwQuerySystemInformation(ULONG systemInformationClass, PVOID systemInformation,
ULONG systemInformationLength, PULONG returnLength);
NTSTATUS NTAPI ZwQueryInformationProcess(HANDLE processHandle, ULONG processInformationClass,
PVOID processInformation, ULONG processInformationLength, PULONG returnLength);
#endif
#define FORT_COMMAND_LINE_LEN 512
#define FORT_COMMAND_LINE_SIZE (FORT_COMMAND_LINE_LEN * sizeof(WCHAR))
typedef struct fort_path_buffer
{
UNICODE_STRING path;
WCHAR buffer[FORT_CONF_APP_PATH_MAX];
} FORT_PATH_BUFFER, *PFORT_PATH_BUFFER;
typedef struct fort_psinfo_hash
{
tommy_key_t pid_hash;
HANDLE processHandle;
DWORD processId;
DWORD parentProcessId;
PCUNICODE_STRING path;
PCUNICODE_STRING commandLine;
} FORT_PSINFO_HASH, *PFORT_PSINFO_HASH;
typedef const FORT_PSINFO_HASH *PCFORT_PSINFO_HASH;
typedef struct fort_pstree_notify_arg
{
PEPROCESS process;
HANDLE processId;
PPS_CREATE_NOTIFY_INFO createInfo;
} FORT_PSTREE_NOTIFY_ARG, *PFORT_PSTREE_NOTIFY_ARG;
typedef const FORT_PSTREE_NOTIFY_ARG *PCFORT_PSTREE_NOTIFY_ARG;
#define fort_pstree_proc_hash(process_id) tommy_inthash_u32((UINT32) (process_id))
#define fort_pstree_get_proc(ps_tree, index) \
((PFORT_PSNODE) tommy_arrayof_ref(&(ps_tree)->procs, (index)))
inline static BOOL fort_is_system_process(DWORD processId, DWORD parentProcessId)
{
/* System (sub)processes */
return (processId == 0 || processId == 4 || parentProcessId == 4);
}
static NTSTATUS GetProcessImageName(HANDLE processHandle, PFORT_PATH_BUFFER pb)
{
NTSTATUS status;
ULONG outLength;
status = ZwQueryInformationProcess(
processHandle, ProcessImageFileName, pb, sizeof(FORT_PATH_BUFFER), &outLength);
if (!NT_SUCCESS(status))
return status;
if (outLength == 0 || pb->path.Length == 0)
return STATUS_OBJECT_NAME_NOT_FOUND;
RtlDowncaseUnicodeString(&pb->path, &pb->path, FALSE);
pb->buffer[pb->path.Length / sizeof(WCHAR)] = L'\0';
return STATUS_SUCCESS;
}
static HANDLE OpenProcessById(DWORD processId)
{
NTSTATUS status;
PEPROCESS peProcess;
status = PsLookupProcessByProcessId((HANDLE) (ptrdiff_t) processId, &peProcess);
if (!NT_SUCCESS(status)) {
LOG("PsTree: Lookup Process Error: pid=%d %x\n", processId, status);
return NULL;
}
HANDLE processHandle;
status = ObOpenObjectByPointer(
peProcess, OBJ_KERNEL_HANDLE, NULL, 0, 0, KernelMode, &processHandle);
ObDereferenceObject(peProcess);
if (!NT_SUCCESS(status)) {
LOG("PsTree: Open Process Object Error: pid=%d %x\n", processId, status);
return NULL;
}
return processHandle;
}
UCHAR fort_pstree_flags_set(PFORT_PSTREE ps_tree, UCHAR flags, BOOL on)
{
return on ? InterlockedOr8(&ps_tree->flags, flags) : InterlockedAnd8(&ps_tree->flags, ~flags);
}
UCHAR fort_pstree_flags(PFORT_PSTREE ps_tree)
{
return fort_pstree_flags_set(ps_tree, 0, TRUE);
}
static PFORT_PSNAME fort_pstree_name_new(PFORT_PSTREE ps_tree, UINT16 name_size)
{
PFORT_PSNAME ps_name = fort_pool_malloc(&ps_tree->pool_list,
FORT_PSNAME_DATA_OFF + name_size + sizeof(WCHAR)); /* include terminating zero */
if (ps_name != NULL) {
ps_name->refcount = 1;
ps_name->size = name_size;
ps_name->data[name_size / sizeof(WCHAR)] = L'\0';
}
return ps_name;
}
static void fort_pstree_name_del(PFORT_PSTREE ps_tree, PFORT_PSNAME ps_name)
{
if (ps_name != NULL && --ps_name->refcount == 0) {
fort_pool_free(&ps_tree->pool_list, ps_name);
}
}
static BOOL fort_pstree_svchost_path_check(PCUNICODE_STRING path)
{
const USHORT svchostSize = sizeof(FORT_SVCHOST_EXE) - sizeof(WCHAR); /* skip terminating zero */
const USHORT pathLength = path->Length;
const PCHAR pathBuffer = (PCHAR) path->Buffer;
PCUNICODE_STRING sysDrivePath = fort_system_drive_path();
PCUNICODE_STRING sys32Path = fort_system32_path();
const USHORT sys32DrivePrefixSize = 2 * sizeof(WCHAR); /* C: */
const USHORT sys32PathSize = sys32Path->Length - sys32DrivePrefixSize;
/* Check the total path length */
if (pathLength != sysDrivePath->Length + sys32PathSize + svchostSize)
return FALSE;
/* Check the file name */
if (RtlCompareMemory(pathBuffer + (pathLength - svchostSize), FORT_SVCHOST_EXE, svchostSize)
!= svchostSize)
return FALSE;
/* Check the drive */
if (RtlCompareMemory(pathBuffer, sysDrivePath->Buffer, sysDrivePath->Length)
!= sysDrivePath->Length)
return FALSE;
/* Check the path */
if (RtlCompareMemory(pathBuffer + sysDrivePath->Length,
(PCHAR) sys32Path->Buffer + sys32DrivePrefixSize, sys32PathSize)
!= sys32PathSize)
return FALSE;
return TRUE;
}
static BOOL fort_pstree_svchost_check(PCUNICODE_STRING commandLine, PUNICODE_STRING serviceName)
{
PWCHAR argp = wcsstr(commandLine->Buffer, L"-s ");
if (argp == NULL)
return FALSE;
argp += (sizeof(L"-s ") - sizeof(WCHAR)) / sizeof(WCHAR); /* skip terminating zero */
PCWCHAR endp = wcschr(argp, L' ');
if (endp == NULL) {
endp = (PCWCHAR) ((PCHAR) commandLine->Buffer + commandLine->Length);
}
const USHORT nameLen = (USHORT) ((PCHAR) endp - (PCHAR) argp);
if (nameLen >= FORT_PSTREE_NAME_LEN_MAX_SIZE)
return FALSE;
serviceName->Length = nameLen;
serviceName->MaximumLength = nameLen;
serviceName->Buffer = argp;
return TRUE;
}
static PFORT_PSNAME fort_pstree_create_service_name(
PFORT_PSTREE ps_tree, PCUNICODE_STRING serviceName)
{
const USHORT nameLen = serviceName->Length;
PFORT_PSNAME ps_name = fort_pstree_name_new(ps_tree, FORT_SVCHOST_PREFIX_SIZE + nameLen);
if (ps_name != NULL) {
PCHAR data = (PCHAR) &ps_name->data;
RtlCopyMemory(data, FORT_SVCHOST_PREFIX, FORT_SVCHOST_PREFIX_SIZE);
UNICODE_STRING nameString;
nameString.Length = nameLen;
nameString.MaximumLength = nameLen;
nameString.Buffer = (PWSTR) (data + FORT_SVCHOST_PREFIX_SIZE);
/* RtlDowncaseUnicodeString() must be called in <DISPATCH level only! */
fort_ascii_downcase(&nameString, serviceName);
}
return ps_name;
}
static void fort_pstree_proc_set_service_name(PFORT_PSNODE proc, PFORT_PSNAME ps_name)
{
assert(proc->ps_name == NULL);
proc->ps_name = ps_name;
if (ps_name != NULL) {
/* Service can't inherit parent's name */
proc->flags |= FORT_PSNODE_NAME_CUSTOM;
}
}
static void fort_pstree_proc_check_svchost(
PFORT_PSTREE ps_tree, PCFORT_PSINFO_HASH psi, PFORT_PSNODE proc)
{
if (psi->path == NULL || psi->commandLine == NULL)
return;
if (!fort_pstree_svchost_path_check(psi->path))
return;
proc->flags |= FORT_PSNODE_IS_SVCHOST;
UNICODE_STRING serviceName;
if (!fort_pstree_svchost_check(psi->commandLine, &serviceName))
return;
PFORT_PSNAME ps_name = fort_pstree_create_service_name(ps_tree, &serviceName);
fort_pstree_proc_set_service_name(proc, ps_name);
}
static PFORT_PSNODE fort_pstree_proc_new(PFORT_PSTREE ps_tree, tommy_key_t pid_hash)
{
tommy_hashdyn_node *proc_node = tommy_list_tail(&ps_tree->free_procs);
if (proc_node != NULL) {
tommy_list_remove_existing(&ps_tree->free_procs, proc_node);
} else {
tommy_arrayof *procs = &ps_tree->procs;
const UINT16 index = ps_tree->procs_n;
tommy_arrayof_grow(procs, index + 1);
proc_node = tommy_arrayof_ref(procs, index);
}
tommy_hashdyn_insert(&ps_tree->procs_map, proc_node, /*ps_name=*/NULL, pid_hash);
++ps_tree->procs_n;
return (PFORT_PSNODE) proc_node;
}
static void fort_pstree_proc_del(PFORT_PSTREE ps_tree, PFORT_PSNODE proc)
{
--ps_tree->procs_n;
/* Delete from pool */
fort_pstree_name_del(ps_tree, proc->ps_name);
proc->ps_name = NULL;
proc->process_id = 0;
/* Delete from procs map */
tommy_hashdyn_remove_existing(&ps_tree->procs_map, (tommy_hashdyn_node *) proc);
tommy_list_insert_tail_check(&ps_tree->free_procs, (tommy_node *) proc);
}
static PFORT_PSNODE fort_pstree_find_proc_hash(
PFORT_PSTREE ps_tree, DWORD processId, tommy_key_t pid_hash)
{
PFORT_PSNODE node = (PFORT_PSNODE) tommy_hashdyn_bucket(&ps_tree->procs_map, pid_hash);
while (node != NULL) {
if (node->process_id == processId)
return node;
node = node->next;
}
return NULL;
}
static PFORT_PSNODE fort_pstree_find_proc(PFORT_PSTREE ps_tree, DWORD processId)
{
if (processId == 0)
return NULL;
const tommy_key_t pid_hash = fort_pstree_proc_hash(processId);
return fort_pstree_find_proc_hash(ps_tree, processId, pid_hash);
}
inline static void fort_pstree_check_proc_conf(
PFORT_PSTREE ps_tree, PFORT_CONF_REF conf_ref, PFORT_PSNODE proc, PCUNICODE_STRING path)
{
const BOOL has_ps_name = (proc->ps_name != NULL);
const PVOID path_buf = has_ps_name ? proc->ps_name->data : path->Buffer;
const UINT16 path_len = has_ps_name ? proc->ps_name->size : path->Length;
const PFORT_CONF conf = &conf_ref->conf;
const FORT_APP_FLAGS app_flags = conf->flags.group_apply_child
? fort_conf_app_find(conf, path_buf, path_len, fort_conf_exe_find, conf_ref)
: fort_conf_exe_find(conf, conf_ref, path_buf, path_len);
if (app_flags.kill_process) {
proc->flags |= FORT_PSNODE_KILL_PROCESS;
return;
}
if (!app_flags.apply_child)
return;
if (!has_ps_name) {
PFORT_PSNAME ps_name = fort_pstree_name_new(ps_tree, path_len);
if (ps_name == NULL)
return;
RtlCopyMemory(ps_name->data, path_buf, path_len);
proc->ps_name = ps_name;
}
proc->flags |= FORT_PSNODE_NAME_INHERIT;
}
inline static BOOL fort_pstree_check_proc_inherited(
PFORT_PSTREE ps_tree, PFORT_PSNODE proc, DWORD parentProcessId)
{
if (proc->ps_name != NULL)
return FALSE;
PFORT_PSNODE parent = fort_pstree_find_proc(ps_tree, parentProcessId);
if (parent == NULL)
return FALSE;
if ((parent->flags & (FORT_PSNODE_NAME_INHERIT | FORT_PSNODE_NAME_INHERITED)) == 0)
return FALSE;
PFORT_PSNAME ps_name = parent->ps_name;
assert(ps_name != NULL);
++ps_name->refcount;
proc->ps_name = ps_name;
proc->flags |= FORT_PSNODE_NAME_INHERITED;
return TRUE;
}
static void fort_pstree_check_proc_inheritance(
PFORT_PSTREE ps_tree, PCFORT_PSINFO_HASH psi, PFORT_PSNODE proc)
{
if (psi->path == NULL)
return;
PFORT_DEVICE_CONF device_conf = &fort_device()->conf;
PFORT_CONF_REF conf_ref = fort_conf_ref_take(device_conf);
if (conf_ref == NULL)
return;
if (!fort_pstree_check_proc_inherited(ps_tree, proc, psi->parentProcessId)) {
fort_pstree_check_proc_conf(ps_tree, conf_ref, proc, psi->path);
}
fort_conf_ref_put(device_conf, conf_ref);
}
static PFORT_PSNODE fort_pstree_handle_new_proc(PFORT_PSTREE ps_tree, PCFORT_PSINFO_HASH psi)
{
PFORT_PSNODE proc = fort_pstree_proc_new(ps_tree, psi->pid_hash);
if (proc == NULL)
return NULL;
proc->process_id = psi->processId;
proc->flags = 0;
fort_pstree_proc_check_svchost(ps_tree, psi, proc);
fort_pstree_check_proc_inheritance(ps_tree, psi, proc);
return proc;
}
inline static void fort_pstree_handle_created_proc(PFORT_PSTREE ps_tree,
PPS_CREATE_NOTIFY_INFO createInfo, PFORT_PSINFO_HASH psi, PFORT_PATH_BUFFER pb)
{
/* GetProcessImageName() must be called in PASSIVE level only! */
const NTSTATUS status = GetProcessImageName(psi->processHandle, pb);
if (!NT_SUCCESS(status)) {
LOG("PsTree: Image Name Error: %x\n", status);
return;
}
PFORT_PSNODE proc;
KLOCK_QUEUE_HANDLE lock_queue;
KeAcquireInStackQueuedSpinLock(&ps_tree->lock, &lock_queue);
{
proc = fort_pstree_handle_new_proc(ps_tree, psi);
}
KeReleaseInStackQueuedSpinLock(&lock_queue);
if (proc != NULL && (proc->flags & FORT_PSNODE_KILL_PROCESS) != 0) {
createInfo->CreationStatus = STATUS_ACCESS_DENIED;
}
}
inline static void fort_pstree_notify_process_created(
PFORT_PSTREE ps_tree, PPS_CREATE_NOTIFY_INFO createInfo, PFORT_PSINFO_HASH psi)
{
if (createInfo->ImageFileName == NULL || createInfo->CommandLine == NULL)
return;
if (fort_is_system_process(psi->processId, psi->parentProcessId))
return; /* skip System (sub)processes */
PFORT_PATH_BUFFER pb = fort_mem_alloc(sizeof(FORT_PATH_BUFFER), FORT_PSTREE_POOL_TAG);
if (pb == NULL)
return;
pb->path.Length = 0;
pb->path.MaximumLength = FORT_CONF_APP_PATH_MAX_SIZE;
pb->path.Buffer = pb->buffer;
psi->path = &pb->path;
const HANDLE processHandle = OpenProcessById(psi->processId);
if (processHandle != NULL) {
psi->processHandle = processHandle;
fort_pstree_handle_created_proc(ps_tree, createInfo, psi, pb);
ZwClose(processHandle);
}
fort_mem_free(pb, FORT_PSTREE_POOL_TAG);
}
inline static void fort_pstree_notify_process(PFORT_PSTREE ps_tree, PCFORT_PSTREE_NOTIFY_ARG pna)
{
const DWORD processId = (DWORD) (ptrdiff_t) pna->processId;
PPS_CREATE_NOTIFY_INFO createInfo = pna->createInfo;
const tommy_key_t pid_hash = fort_pstree_proc_hash(processId);
#ifdef FORT_DEBUG
if (createInfo == NULL) {
LOG("PsTree: CLOSED pid=%d\n", processId);
} else {
const DWORD parentProcessId = (DWORD) (ptrdiff_t) createInfo->ParentProcessId;
LOG("PsTree: NEW pid=%d ppid=%d IMG=[%wZ] CMD=[%wZ]\n", processId, parentProcessId,
createInfo->ImageFileName, createInfo->CommandLine);
}
#endif
KLOCK_QUEUE_HANDLE lock_queue;
KeAcquireInStackQueuedSpinLock(&ps_tree->lock, &lock_queue);
PFORT_PSNODE proc = fort_pstree_find_proc_hash(ps_tree, processId, pid_hash);
if (proc != NULL) {
fort_pstree_proc_del(ps_tree, proc);
}
KeReleaseInStackQueuedSpinLock(&lock_queue);
if (createInfo != NULL) {
FORT_PSINFO_HASH psi = {
.pid_hash = pid_hash,
.processId = processId,
.parentProcessId = (DWORD) (ptrdiff_t) createInfo->ParentProcessId,
.commandLine = createInfo->CommandLine,
};
fort_pstree_notify_process_created(ps_tree, createInfo, &psi);
}
}
static NTSTATUS fort_pstree_notify_expand(PVOID param)
{
PCFORT_PSTREE_NOTIFY_ARG pna = param;
PFORT_PSTREE ps_tree = &fort_device()->ps_tree;
fort_pstree_notify_process(ps_tree, pna);
return STATUS_SUCCESS;
}
static void NTAPI fort_pstree_notify(
PEPROCESS process, HANDLE processId, PPS_CREATE_NOTIFY_INFO createInfo)
{
FORT_PSTREE_NOTIFY_ARG pna = {
.process = process,
.processId = processId,
.createInfo = createInfo,
};
fort_expand_stack(&fort_pstree_notify_expand, &pna);
}
static void fort_pstree_update(PFORT_PSTREE ps_tree, BOOL active)
{
const UCHAR flags = fort_pstree_flags_set(ps_tree, FORT_PSTREE_ACTIVE, active);
const BOOL was_active = (flags & FORT_PSTREE_ACTIVE) != 0;
if (was_active == active)
return;
const NTSTATUS status = PsSetCreateProcessNotifyRoutineEx(
FORT_CALLBACK(FORT_CALLBACK_PSTREE_NOTIFY, PCREATE_PROCESS_NOTIFY_ROUTINE_EX,
&fort_pstree_notify),
/*remove=*/!active);
if (!NT_SUCCESS(status)) {
LOG("PsTree: Update Error: %x\n", status);
TRACE(FORT_PSTREE_UPDATE_ERROR, status, 0, 0);
}
}
FORT_API void fort_pstree_open(PFORT_PSTREE ps_tree)
{
fort_pool_list_init(&ps_tree->pool_list);
fort_pool_init(&ps_tree->pool_list, FORT_PSTREE_NAMES_POOL_SIZE);
tommy_list_init(&ps_tree->free_procs);
tommy_arrayof_init(&ps_tree->procs, sizeof(FORT_PSNODE));
tommy_hashdyn_init(&ps_tree->procs_map);
KeInitializeSpinLock(&ps_tree->lock);
fort_pstree_update(ps_tree, /*active=*/TRUE); /* Start process monitor */
}
FORT_API void fort_pstree_close(PFORT_PSTREE ps_tree)
{
fort_pstree_update(ps_tree, /*active=*/FALSE); /* Stop process monitor */
KLOCK_QUEUE_HANDLE lock_queue;
KeAcquireInStackQueuedSpinLock(&ps_tree->lock, &lock_queue);
{
fort_pool_done(&ps_tree->pool_list);
tommy_arrayof_done(&ps_tree->procs);
tommy_hashdyn_done(&ps_tree->procs_map);
}
KeReleaseInStackQueuedSpinLock(&lock_queue);
}
static BOOL fort_pstree_get_proc_name_locked(PFORT_PSTREE ps_tree, DWORD processId,
PUNICODE_STRING path, BOOL *isSvcHost, BOOL *inherited)
{
PFORT_PSNODE proc = fort_pstree_find_proc(ps_tree, processId);
if (proc == NULL)
return FALSE;
const UINT16 procFlags = proc->flags;
*isSvcHost = (procFlags & FORT_PSNODE_IS_SVCHOST) != 0;
PFORT_PSNAME ps_name = proc->ps_name;
if (ps_name == NULL)
return FALSE;
if ((procFlags & (FORT_PSNODE_NAME_INHERIT | FORT_PSNODE_NAME_CUSTOM))
== FORT_PSNODE_NAME_INHERIT)
return FALSE;
path->Length = ps_name->size;
path->MaximumLength = ps_name->size;
path->Buffer = ps_name->data;
*inherited = (procFlags & FORT_PSNODE_NAME_INHERITED) != 0;
return TRUE;
}
FORT_API BOOL fort_pstree_get_proc_name(PFORT_PSTREE ps_tree, DWORD processId, PUNICODE_STRING path,
BOOL *isSvcHost, BOOL *inherited)
{
BOOL res;
KLOCK_QUEUE_HANDLE lock_queue;
KeAcquireInStackQueuedSpinLock(&ps_tree->lock, &lock_queue);
{
res = fort_pstree_get_proc_name_locked(ps_tree, processId, path, isSvcHost, inherited);
}
KeReleaseInStackQueuedSpinLock(&lock_queue);
return res;
}
inline static void fort_pstree_update_service_proc(
PFORT_PSTREE ps_tree, PCUNICODE_STRING serviceName, DWORD processId)
{
const tommy_key_t pid_hash = fort_pstree_proc_hash(processId);
PFORT_PSNODE proc = fort_pstree_find_proc_hash(ps_tree, processId, pid_hash);
if (proc == NULL) {
proc = fort_pstree_proc_new(ps_tree, pid_hash);
proc->process_id = processId;
proc->flags = 0;
}
if (proc != NULL && proc->ps_name == NULL) {
PFORT_PSNAME ps_name = fort_pstree_create_service_name(ps_tree, serviceName);
fort_pstree_proc_set_service_name(proc, ps_name);
}
}
static int fort_pstree_update_service(
PFORT_PSTREE ps_tree, const PFORT_SERVICE_INFO service, const PCHAR end_data)
{
if ((PCHAR) service + FORT_SERVICE_INFO_NAME_OFF > end_data)
return 0;
UNICODE_STRING serviceName;
serviceName.Length = service->name_len;
serviceName.MaximumLength = serviceName.Length;
serviceName.Buffer = service->name;
if ((PCHAR) service + FORT_SERVICE_INFO_NAME_OFF + serviceName.Length > end_data)
return 0;
fort_pstree_update_service_proc(ps_tree, &serviceName, service->process_id);
return FORT_SERVICE_INFO_NAME_OFF + FORT_CONF_STR_DATA_SIZE(serviceName.Length);
}
FORT_API void fort_pstree_update_services(
PFORT_PSTREE ps_tree, const PFORT_SERVICE_INFO_LIST services, ULONG data_len)
{
KLOCK_QUEUE_HANDLE lock_queue;
KeAcquireInStackQueuedSpinLock(&ps_tree->lock, &lock_queue);
{
PCHAR data = (PCHAR) services->data;
const PCHAR end_data = data + data_len;
UINT16 n = services->services_n;
while (n-- > 0) {
const int size =
fort_pstree_update_service(ps_tree, (PFORT_SERVICE_INFO) data, end_data);
if (size == 0)
break;
data += size;
}
}
KeReleaseInStackQueuedSpinLock(&lock_queue);
}