Driver: Handle accept/reject zones for programs

This commit is contained in:
Nodir Temirkhodjaev 2023-12-19 19:25:50 +03:00
parent 6884e34445
commit b62807ec94
15 changed files with 143 additions and 95 deletions

View File

@ -4,8 +4,8 @@
#include <assert.h>
#include "fortdef.h"
#include "fort_wildmatch.h"
#include "fortdef.h"
static_assert(sizeof(ip6_addr_t) == 16, "ip6_addr_t size mismatch");
@ -14,7 +14,7 @@ static_assert(sizeof(FORT_TRAF) == sizeof(UINT64), "FORT_TRAF size mismatch");
static_assert(sizeof(FORT_TIME) == sizeof(UINT16), "FORT_TIME size mismatch");
static_assert(sizeof(FORT_PERIOD) == sizeof(UINT32), "FORT_PERIOD size mismatch");
static_assert(sizeof(FORT_APP_FLAGS) == sizeof(UINT16), "FORT_APP_FLAGS size mismatch");
static_assert(sizeof(FORT_APP_ENTRY) == sizeof(UINT32), "FORT_APP_ENTRY size mismatch");
static_assert(sizeof(FORT_APP_ENTRY) == 2 * sizeof(UINT32), "FORT_APP_ENTRY size mismatch");
#ifndef FORT_DRIVER
# define fort_memcmp memcmp
@ -209,32 +209,30 @@ static BOOL fort_conf_app_wild_equal(
typedef BOOL fort_conf_app_equal_func(
const PFORT_APP_ENTRY app_entry, const PVOID path, UINT32 path_len);
static FORT_APP_FLAGS fort_conf_app_find_loop(const PFORT_CONF conf, const PVOID path,
static FORT_APP_ENTRY fort_conf_app_find_loop(const PFORT_CONF conf, const PVOID path,
UINT32 path_len, UINT32 apps_off, UINT16 apps_n, fort_conf_app_equal_func *app_equal_func)
{
FORT_APP_FLAGS app_flags;
app_flags.v = 0;
FORT_APP_ENTRY app_data;
app_data.flags.v = 0;
if (apps_n == 0)
return app_flags;
return app_data;
const char *app_entries = (const char *) (conf->data + apps_off);
do {
const PFORT_APP_ENTRY app_entry = (const PFORT_APP_ENTRY) app_entries;
if (app_equal_func(app_entry, path, path_len)) {
app_flags = app_entry->flags;
break;
}
if (app_equal_func(app_entry, path, path_len))
return *app_entry;
app_entries += FORT_CONF_APP_ENTRY_SIZE(app_entry->path_len);
} while (--apps_n != 0);
return app_flags;
return app_data;
}
FORT_API FORT_APP_FLAGS fort_conf_app_exe_find(
FORT_API FORT_APP_ENTRY fort_conf_app_exe_find(
const PFORT_CONF conf, PVOID context, const PVOID path, UINT32 path_len)
{
UNUSED(context);
@ -243,7 +241,7 @@ FORT_API FORT_APP_FLAGS fort_conf_app_exe_find(
conf, path, path_len, conf->exe_apps_off, conf->exe_apps_n, fort_conf_app_exe_equal);
}
static FORT_APP_FLAGS fort_conf_app_wild_find(
static FORT_APP_ENTRY fort_conf_app_wild_find(
const PFORT_CONF conf, const PVOID path, UINT32 path_len)
{
return fort_conf_app_find_loop(
@ -261,15 +259,15 @@ static int fort_conf_app_prefix_cmp(PFORT_APP_ENTRY app_entry, const PVOID path,
return fort_memcmp(path, app_path, path_len);
}
static FORT_APP_FLAGS fort_conf_app_prefix_find(
static FORT_APP_ENTRY fort_conf_app_prefix_find(
const PFORT_CONF conf, const PVOID path, UINT32 path_len)
{
FORT_APP_FLAGS app_flags;
app_flags.v = 0;
FORT_APP_ENTRY app_data;
app_data.flags.v = 0;
const UINT16 count = conf->prefix_apps_n;
if (count == 0)
return app_flags;
return app_data;
const char *data = conf->data;
const UINT32 *app_offsets = (const UINT32 *) (data + conf->prefix_apps_off);
@ -285,34 +283,34 @@ static FORT_APP_FLAGS fort_conf_app_prefix_find(
const int res = fort_conf_app_prefix_cmp(app_entry, path, path_len);
if (res < 0)
if (res < 0) {
high = mid - 1;
else if (res > 0)
} else if (res > 0) {
low = mid + 1;
else {
app_flags = app_entry->flags;
break;
} else {
return *app_entry;
}
} while (low <= high);
return app_flags;
return app_data;
}
FORT_API FORT_APP_FLAGS fort_conf_app_find(const PFORT_CONF conf, const PVOID path, UINT32 path_len,
FORT_API FORT_APP_ENTRY fort_conf_app_find(const PFORT_CONF conf, const PVOID path, UINT32 path_len,
fort_conf_app_exe_find_func *exe_find_func, PVOID exe_context)
{
FORT_APP_FLAGS app_flags;
FORT_APP_ENTRY app_entry;
app_flags = exe_find_func(conf, exe_context, path, path_len);
if (app_flags.v != 0)
return app_flags;
app_entry = exe_find_func(conf, exe_context, path, path_len);
if (app_entry.flags.v != 0)
return app_entry;
app_flags = fort_conf_app_wild_find(conf, path, path_len);
if (app_flags.v != 0)
return app_flags;
app_entry = fort_conf_app_wild_find(conf, path, path_len);
if (app_entry.flags.v != 0)
return app_entry;
app_flags = fort_conf_app_prefix_find(conf, path, path_len);
return app_flags;
app_entry = fort_conf_app_prefix_find(conf, path, path_len);
return app_entry;
}
static BOOL fort_conf_app_blocked_check(const PFORT_CONF conf, INT8 *block_reason, BOOL app_found,
@ -344,11 +342,6 @@ FORT_API BOOL fort_conf_app_blocked(
const BOOL app_found = (app_flags.v != 0);
if (app_found) {
if (app_flags.lan_only) {
*block_reason = FORT_BLOCK_REASON_LAN_ONLY;
return TRUE;
}
if (!app_flags.use_group_perm) {
*block_reason = FORT_BLOCK_REASON_PROGRAM;
return app_flags.blocked;

View File

@ -182,15 +182,10 @@ typedef struct fort_app_flags
typedef struct fort_app_entry
{
union {
UINT32 v;
struct
{
UINT16 path_len;
FORT_APP_FLAGS flags;
};
};
FORT_APP_FLAGS flags;
UINT16 path_len;
UINT16 accept_zones;
UINT16 reject_zones;
} FORT_APP_ENTRY, *PFORT_APP_ENTRY;
typedef struct fort_speed_limit
@ -268,7 +263,7 @@ typedef struct fort_conf_io
#define FORT_CONF_ADDR_LIST_SIZE(ip4_n, pair4_n, ip6_n, pair6_n) \
(FORT_CONF_ADDR4_LIST_SIZE(ip4_n, pair4_n) + FORT_CONF_ADDR6_LIST_SIZE(ip6_n, pair6_n))
typedef FORT_APP_FLAGS fort_conf_app_exe_find_func(
typedef FORT_APP_ENTRY fort_conf_app_exe_find_func(
const PFORT_CONF conf, PVOID context, const PVOID path, UINT32 path_len);
typedef BOOL fort_conf_zones_ip_included_func(
@ -307,10 +302,10 @@ FORT_API BOOL fort_conf_ip_included(const PFORT_CONF conf,
FORT_API BOOL fort_conf_app_exe_equal(
const PFORT_APP_ENTRY app_entry, const PVOID path, UINT32 path_len);
FORT_API FORT_APP_FLAGS fort_conf_app_exe_find(
FORT_API FORT_APP_ENTRY fort_conf_app_exe_find(
const PFORT_CONF conf, PVOID context, const PVOID path, UINT32 path_len);
FORT_API FORT_APP_FLAGS fort_conf_app_find(const PFORT_CONF conf, const PVOID path, UINT32 path_len,
FORT_API FORT_APP_ENTRY fort_conf_app_find(const PFORT_CONF conf, const PVOID path, UINT32 path_len,
fort_conf_app_exe_find_func *exe_find_func, PVOID exe_context);
FORT_API BOOL fort_conf_app_blocked(

View File

@ -25,6 +25,7 @@ enum FortBlockReason {
FORT_BLOCK_REASON_APP_GROUP_FOUND,
FORT_BLOCK_REASON_FILTER_MODE,
FORT_BLOCK_REASON_LAN_ONLY,
FORT_BLOCK_REASON_ZONE,
FORT_BLOCK_REASON_ASK_LIMIT,
FORT_BLOCK_REASON_ASK_PENDING = 15 /* must be last! */
};

View File

@ -68,23 +68,27 @@ static PFORT_CONF_EXE_NODE fort_conf_ref_exe_find_node(
return NULL;
}
FORT_API FORT_APP_FLAGS fort_conf_exe_find(
FORT_API FORT_APP_ENTRY fort_conf_exe_find(
const PFORT_CONF conf, PVOID context, const PVOID path, UINT32 path_len)
{
PFORT_CONF_REF conf_ref = context;
const tommy_key_t path_hash = (tommy_key_t) tommy_hash_u64(0, path, path_len);
FORT_APP_FLAGS app_flags;
FORT_APP_ENTRY app_data;
app_data.flags.v = 0;
KIRQL oldIrql = ExAcquireSpinLockShared(&conf_ref->conf_lock);
{
const PFORT_CONF_EXE_NODE node =
fort_conf_ref_exe_find_node(conf_ref, path, path_len, path_hash);
app_flags.v = node ? node->app_entry->flags.v : 0;
if (node != NULL) {
app_data = *node->app_entry;
}
}
ExReleaseSpinLockShared(&conf_ref->conf_lock, oldIrql);
return app_flags;
return app_data;
}
static void fort_conf_ref_exe_new_path(
@ -123,6 +127,8 @@ static NTSTATUS fort_conf_ref_exe_new_entry(PFORT_CONF_REF conf_ref, const PVOID
entry->flags = flags;
entry->path_len = (UINT16) path_len;
entry->accept_zones = 0;
entry->reject_zones = 0;
/* Copy path */
{

View File

@ -53,7 +53,7 @@ FORT_API UCHAR fort_device_flag_set(PFORT_DEVICE_CONF device_conf, UCHAR flag, B
FORT_API UCHAR fort_device_flag(PFORT_DEVICE_CONF device_conf, UCHAR flag);
FORT_API FORT_APP_FLAGS fort_conf_exe_find(
FORT_API FORT_APP_ENTRY fort_conf_exe_find(
const PFORT_CONF conf, PVOID context, const PVOID path, UINT32 path_len);
FORT_API NTSTATUS fort_conf_ref_exe_add_path(

View File

@ -47,24 +47,24 @@ static void fort_callout_classify_continue(FWPS_CLASSIFY_OUT0 *classifyOut)
}
inline static void fort_callout_ale_set_app_flags(
PFORT_CALLOUT_ALE_EXTRA cx, FORT_APP_FLAGS app_flags)
PFORT_CALLOUT_ALE_EXTRA cx, FORT_APP_ENTRY app_data)
{
cx->app_flags_found = TRUE;
cx->app_flags = app_flags;
cx->app_data_found = TRUE;
cx->app_data = app_data;
}
static FORT_APP_FLAGS fort_callout_ale_conf_app_flags(
static FORT_APP_ENTRY fort_callout_ale_conf_app_data(
PFORT_CALLOUT_ALE_EXTRA cx, PFORT_CONF_REF conf_ref)
{
if (cx->app_flags_found)
return cx->app_flags;
if (cx->app_data_found)
return cx->app_data;
const FORT_APP_FLAGS app_flags = fort_conf_app_find(
const FORT_APP_ENTRY app_data = fort_conf_app_find(
&conf_ref->conf, cx->path->Buffer, cx->path->Length, fort_conf_exe_find, conf_ref);
fort_callout_ale_set_app_flags(cx, app_flags);
fort_callout_ale_set_app_flags(cx, app_data);
return app_flags;
return app_data;
}
inline static BOOL fort_callout_ale_associate_flow(PCFORT_CALLOUT_ARG ca,
@ -110,22 +110,22 @@ inline static BOOL fort_callout_ale_log_app_path_check(
}
inline static void fort_callout_ale_log_app_path(PFORT_CALLOUT_ALE_EXTRA cx,
PFORT_CONF_REF conf_ref, FORT_CONF_FLAGS conf_flags, FORT_APP_FLAGS app_flags)
PFORT_CONF_REF conf_ref, FORT_CONF_FLAGS conf_flags, FORT_APP_ENTRY app_data)
{
if (!fort_callout_ale_log_app_path_check(conf_flags, app_flags))
if (!fort_callout_ale_log_app_path_check(conf_flags, app_data.flags))
return;
app_flags.log_blocked = TRUE;
app_flags.log_conn = TRUE;
app_flags.blocked = (UCHAR) cx->blocked;
app_flags.alerted = TRUE;
app_flags.is_new = TRUE;
app_data.flags.log_blocked = TRUE;
app_data.flags.log_conn = TRUE;
app_data.flags.blocked = (UCHAR) cx->blocked;
app_data.flags.alerted = TRUE;
app_data.flags.is_new = TRUE;
if (!NT_SUCCESS(fort_conf_ref_exe_add_path(
conf_ref, cx->path->Buffer, cx->path->Length, app_flags)))
conf_ref, cx->path->Buffer, cx->path->Length, app_data.flags)))
return;
fort_callout_ale_set_app_flags(cx, app_flags);
fort_callout_ale_set_app_flags(cx, app_data);
fort_buffer_blocked_write(&fort_device()->buffer, cx->blocked, cx->process_id,
cx->real_path->Length, cx->real_path->Buffer, &cx->irp, &cx->info);
@ -147,9 +147,9 @@ inline static BOOL fort_callout_ale_log_blocked_ip_check(
if (!(conf_flags.ask_to_connect || conf_flags.log_blocked_ip))
return FALSE;
const FORT_APP_FLAGS app_flags = fort_callout_ale_conf_app_flags(cx, conf_ref);
const FORT_APP_ENTRY app_data = fort_callout_ale_conf_app_data(cx, conf_ref);
return fort_callout_ale_log_blocked_ip_check_app(conf_flags, app_flags);
return fort_callout_ale_log_blocked_ip_check_app(conf_flags, app_data.flags);
}
inline static void fort_callout_ale_log_blocked_ip(PCFORT_CALLOUT_ARG ca,
@ -200,30 +200,70 @@ inline static BOOL fort_callout_ale_process_flow(PCFORT_CALLOUT_ARG ca, PFORT_CA
return fort_callout_ale_associate_flow(ca, cx, conf_ref, app_flags);
}
inline static BOOL fort_callout_ale_is_allowed(PFORT_CALLOUT_ALE_EXTRA cx, PFORT_CONF_REF conf_ref,
FORT_CONF_FLAGS conf_flags, FORT_APP_FLAGS app_flags)
static BOOL fort_callout_ale_is_zone_blocked(PCFORT_CALLOUT_ARG ca, PFORT_CALLOUT_ALE_EXTRA cx,
PFORT_CONF_REF conf_ref, FORT_APP_ENTRY app_data)
{
const BOOL app_found = (app_data.flags.v != 0);
if (!app_found)
return FALSE;
if (app_data.flags.lan_only) {
cx->block_reason = FORT_BLOCK_REASON_LAN_ONLY;
return TRUE;
}
if (app_data.reject_zones != 0
&& fort_conf_zones_ip_included(
&fort_device()->conf, app_data.reject_zones, cx->remote_ip, ca->isIPv6)) {
cx->blocked = TRUE; /* block Rejected Zone */
cx->block_reason = FORT_BLOCK_REASON_ZONE;
return TRUE;
}
if (app_data.accept_zones != 0
&& !fort_conf_zones_ip_included(
&fort_device()->conf, app_data.accept_zones, cx->remote_ip, ca->isIPv6)) {
cx->blocked = TRUE; /* block Not Accepted Zone */
cx->block_reason = FORT_BLOCK_REASON_ZONE;
return TRUE;
}
return FALSE;
}
inline static BOOL fort_callout_ale_is_new(FORT_CONF_FLAGS conf_flags, FORT_APP_ENTRY app_data)
{
const BOOL app_found = (app_data.flags.v != 0);
return !app_found && (conf_flags.allow_all_new || conf_flags.ask_to_connect);
}
inline static BOOL fort_callout_ale_is_allowed(PCFORT_CALLOUT_ARG ca, PFORT_CALLOUT_ALE_EXTRA cx,
PFORT_CONF_REF conf_ref, FORT_CONF_FLAGS conf_flags, FORT_APP_ENTRY app_data)
{
return !cx->blocked /* collect traffic, when Filter Disabled */
/* "Allow, if not blocked" or "Ask to Connect" */
|| (app_flags.v == 0 && (conf_flags.allow_all_new || conf_flags.ask_to_connect))
|| fort_callout_ale_is_new(conf_flags, app_data)
/* "Allow, if not blocked" or "Ask to Connect" */
|| !fort_callout_ale_is_zone_blocked(ca, cx, conf_ref, app_data)
/* check the conf for a blocked app */
|| !fort_conf_app_blocked(&conf_ref->conf, app_flags, &cx->block_reason);
|| !fort_conf_app_blocked(&conf_ref->conf, app_data.flags, &cx->block_reason);
}
inline static void fort_callout_ale_log(PCFORT_CALLOUT_ARG ca, PFORT_CALLOUT_ALE_EXTRA cx,
PFORT_CONF_REF conf_ref, FORT_CONF_FLAGS conf_flags)
{
const FORT_APP_FLAGS app_flags = fort_callout_ale_conf_app_flags(cx, conf_ref);
const FORT_APP_ENTRY app_data = fort_callout_ale_conf_app_data(cx, conf_ref);
if (fort_callout_ale_is_allowed(cx, conf_ref, conf_flags, app_flags)) {
if (fort_callout_ale_is_allowed(ca, cx, conf_ref, conf_flags, app_data)) {
if (fort_callout_ale_process_flow(ca, cx, conf_ref, conf_flags, app_flags))
if (fort_callout_ale_process_flow(ca, cx, conf_ref, conf_flags, app_data.flags))
return;
cx->blocked = FALSE; /* allow */
}
fort_callout_ale_log_app_path(cx, conf_ref, conf_flags, app_flags);
fort_callout_ale_log_app_path(cx, conf_ref, conf_flags, app_data);
}
inline static BOOL fort_callout_ale_check_filter_flags(PCFORT_CALLOUT_ARG ca,

View File

@ -41,13 +41,13 @@ typedef const FORT_CALLOUT_ARG *PCFORT_CALLOUT_ARG;
typedef struct fort_callout_ale_extra
{
UCHAR is_reauth : 1;
UCHAR app_flags_found : 1;
UCHAR app_data_found : 1;
UCHAR inherited : 1;
UCHAR drop_blocked : 1;
UCHAR blocked : 1;
INT8 block_reason;
FORT_APP_FLAGS app_flags;
FORT_APP_ENTRY app_data;
UINT32 process_id;

View File

@ -416,11 +416,13 @@ inline static void fort_pstree_check_proc_conf(
const PFORT_CONF conf = &conf_ref->conf;
const FORT_APP_FLAGS app_flags = conf->proc_wild
const FORT_APP_ENTRY app_data = conf->proc_wild
? 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);
fort_pstree_check_proc_app_flags(ps_tree, proc, path_buf, path_len, app_flags);
if (app_data.flags.v != 0) {
fort_pstree_check_proc_app_flags(ps_tree, proc, path_buf, path_len, app_data.flags);
}
}
inline static BOOL fort_pstree_check_proc_inherited(

View File

@ -224,10 +224,10 @@ quint16 confAppFind(const void *drvConf, const QString &kernelPath)
const quint32 len = quint32(kernelPathLower.size()) * sizeof(WCHAR);
const WCHAR *p = (PCWCHAR) kernelPathLower.utf16();
const FORT_APP_FLAGS app_flags = fort_conf_app_find(
const FORT_APP_ENTRY app_data = fort_conf_app_find(
conf, (const PVOID) p, len, fort_conf_app_exe_find, /*exe_context=*/nullptr);
return app_flags.v;
return app_data.flags.v;
}
quint8 confAppGroupIndex(quint16 appFlags)

View File

@ -146,7 +146,7 @@ void ZonesSelector::createZonesMenu()
{
auto zoneListModel = IoC<ZoneListModel>();
const int zoneCount = zoneListModel->rowCount();
const int zoneCount = qMin(zoneListModel->rowCount(), maxZoneCount());
for (int row = 0; row < zoneCount; ++row) {
const auto zoneRow = zoneListModel->zoneRowAt(row);

View File

@ -15,6 +15,9 @@ public:
bool isTristate() const { return m_isTristate; }
void setIsTristate(bool isTristate) { m_isTristate = isTristate; }
int maxZoneCount() const { return m_maxZoneCount; }
void setMaxZoneCount(int maxZoneCount) { m_maxZoneCount = maxZoneCount; }
quint32 zones() const { return m_zones; }
void setZones(quint32 zones);
@ -53,6 +56,8 @@ private:
private:
bool m_isTristate = false;
int m_maxZoneCount = INT_MAX;
quint32 m_zones = 0;
quint32 m_uncheckedZones = 0;

View File

@ -405,6 +405,7 @@ QLayout *ProgramEditDialog::setupZonesLayout()
// Zones
m_btZones = new ZonesSelector();
m_btZones->setIsTristate(true);
m_btZones->setMaxZoneCount(16); // sync with driver's FORT_APP_ENTRY
auto layout = new QHBoxLayout();
layout->addWidget(m_cbLanOnly);

View File

@ -197,6 +197,7 @@ QString ConnBlockListModel::blockReasonText(const ConnRow &connRow)
QT_TR_NOOP("App. Group logic"),
QT_TR_NOOP("Filter Mode logic"),
QT_TR_NOOP("Restrict access to LAN only"),
QT_TR_NOOP("Restrict access by Zone"),
QT_TR_NOOP("Limit of Ask to Connect"),
};
@ -218,6 +219,7 @@ QString ConnBlockListModel::connIconPath(const ConnRow &connRow)
":/icons/application_double.png",
":/icons/deny.png",
":/icons/hostname.png",
":/icons/ip_class.png",
":/icons/help.png",
};

View File

@ -5,10 +5,12 @@
#include <QObject>
#include <QVarLengthArray>
#include <common/fortconf.h>
#include "addressrange.h"
using addrranges_arr_t = QVarLengthArray<AddressRange, 2>;
using appentry_map_t = QMap<QString, quint32>;
using appentry_map_t = QMap<QString, FORT_APP_ENTRY>;
class AppParseOptions
{

View File

@ -466,7 +466,6 @@ bool ConfUtil::addApp(const App &app, bool isNew, appentry_map_t &appsMap, quint
appsSize += appSize;
const FORT_APP_ENTRY appEntry = {
.path_len = appPathLen,
.flags = {
.group_index = quint8(app.groupIndex),
.use_group_perm = app.useGroupPerm,
@ -481,9 +480,12 @@ bool ConfUtil::addApp(const App &app, bool isNew, appentry_map_t &appsMap, quint
.is_new = isNew,
.found = 1,
},
.path_len = appPathLen,
.accept_zones = quint16(app.acceptZones),
.reject_zones = quint16(app.rejectZones),
};
appsMap.insert(kernelPath, appEntry.v);
appsMap.insert(kernelPath, appEntry);
m_driveMask |= FileUtil::driveMaskByPath(app.appPath);
@ -797,8 +799,7 @@ void ConfUtil::writeApps(char **data, const appentry_map_t &appsMap, bool useHea
for (; it != end; ++it) {
const QString &appPath = it.key();
FORT_APP_ENTRY appEntry;
appEntry.v = it.value();
const FORT_APP_ENTRY &appEntry = it.value();
PFORT_APP_ENTRY entry = (PFORT_APP_ENTRY) p;
*entry++ = appEntry;